diff options
Diffstat (limited to 'contrib/llvm/utils')
39 files changed, 4845 insertions, 1286 deletions
diff --git a/contrib/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/contrib/llvm/utils/TableGen/AsmMatcherEmitter.cpp index 026d47f..ee83311 100644 --- a/contrib/llvm/utils/TableGen/AsmMatcherEmitter.cpp +++ b/contrib/llvm/utils/TableGen/AsmMatcherEmitter.cpp @@ -77,7 +77,7 @@ // // Some targets need a custom way to parse operands, some specific instructions // can contain arguments that can represent processor flags and other kinds of -// identifiers that need to be mapped to specific valeus in the final encoded +// identifiers that need to be mapped to specific values in the final encoded // instructions. The target specific custom operand parsing works in the // following way: // @@ -199,7 +199,7 @@ public: return Kind >= UserClass0; } - /// isRelatedTo - Check whether this class is "related" to \arg RHS. Classes + /// isRelatedTo - Check whether this class is "related" to \p RHS. Classes /// are related if they are in the same class hierarchy. bool isRelatedTo(const ClassInfo &RHS) const { // Tokens are only related to tokens. @@ -238,7 +238,7 @@ public: return Root == RHSRoot; } - /// isSubsetOf - Test whether this class is a subset of \arg RHS; + /// isSubsetOf - Test whether this class is a subset of \p RHS. bool isSubsetOf(const ClassInfo &RHS) const { // This is a subset of RHS if it is the same class... if (this == &RHS) @@ -279,6 +279,15 @@ public: } }; +namespace { +/// Sort ClassInfo pointers independently of pointer value. +struct LessClassInfoPtr { + bool operator()(const ClassInfo *LHS, const ClassInfo *RHS) const { + return *LHS < *RHS; + } +}; +} + /// MatchableInfo - Helper class for storing the necessary information for an /// instruction or alias which is capable of being matched. struct MatchableInfo { @@ -416,7 +425,7 @@ struct MatchableInfo { SmallVector<SubtargetFeatureInfo*, 4> RequiredFeatures; /// ConversionFnKind - The enum value which is passed to the generated - /// ConvertToMCInst to convert parsed operands into an MCInst for this + /// convertToMCInst to convert parsed operands into an MCInst for this /// function. std::string ConversionFnKind; @@ -488,11 +497,20 @@ struct MatchableInfo { return false; } + // Give matches that require more features higher precedence. This is useful + // because we cannot define AssemblerPredicates with the negation of + // processor features. For example, ARM v6 "nop" may be either a HINT or + // MOV. With v6, we want to match HINT. The assembler has no way to + // predicate MOV under "NoV6", but HINT will always match first because it + // requires V6 while MOV does not. + if (RequiredFeatures.size() != RHS.RequiredFeatures.size()) + return RequiredFeatures.size() > RHS.RequiredFeatures.size(); + return false; } /// couldMatchAmbiguouslyWith - Check whether this matchable could - /// ambiguously match the same set of operands as \arg RHS (without being a + /// ambiguously match the same set of operands as \p RHS (without being a /// strictly superior match). bool couldMatchAmbiguouslyWith(const MatchableInfo &RHS) { // The primary comparator is the instruction mnemonic. @@ -590,7 +608,8 @@ public: std::vector<OperandMatchEntry> OperandMatchInfo; /// Map of Register records to their class information. - std::map<Record*, ClassInfo*> RegisterClasses; + typedef std::map<Record*, ClassInfo*, LessRecordByID> RegisterClassesTy; + RegisterClassesTy RegisterClasses; /// Map of Predicate records to their subtarget information. std::map<Record*, SubtargetFeatureInfo*> SubtargetFeatures; @@ -666,22 +685,22 @@ void MatchableInfo::dump() { } static std::pair<StringRef, StringRef> -parseTwoOperandConstraint(StringRef S, SMLoc Loc) { +parseTwoOperandConstraint(StringRef S, ArrayRef<SMLoc> Loc) { // Split via the '='. std::pair<StringRef, StringRef> Ops = S.split('='); if (Ops.second == "") - throw TGError(Loc, "missing '=' in two-operand alias constraint"); + PrintFatalError(Loc, "missing '=' in two-operand alias constraint"); // Trim whitespace and the leading '$' on the operand names. size_t start = Ops.first.find_first_of('$'); if (start == std::string::npos) - throw TGError(Loc, "expected '$' prefix on asm operand name"); + PrintFatalError(Loc, "expected '$' prefix on asm operand name"); Ops.first = Ops.first.slice(start + 1, std::string::npos); size_t end = Ops.first.find_last_of(" \t"); Ops.first = Ops.first.slice(0, end); // Now the second operand. start = Ops.second.find_first_of('$'); if (start == std::string::npos) - throw TGError(Loc, "expected '$' prefix on asm operand name"); + PrintFatalError(Loc, "expected '$' prefix on asm operand name"); Ops.second = Ops.second.slice(start + 1, std::string::npos); end = Ops.second.find_last_of(" \t"); Ops.first = Ops.first.slice(0, end); @@ -697,11 +716,11 @@ void MatchableInfo::formTwoOperandAlias(StringRef Constraint) { int SrcAsmOperand = findAsmOperandNamed(Ops.first); int DstAsmOperand = findAsmOperandNamed(Ops.second); if (SrcAsmOperand == -1) - throw TGError(TheDef->getLoc(), + PrintFatalError(TheDef->getLoc(), "unknown source two-operand alias operand '" + Ops.first.str() + "'."); if (DstAsmOperand == -1) - throw TGError(TheDef->getLoc(), + PrintFatalError(TheDef->getLoc(), "unknown destination two-operand alias operand '" + Ops.second.str() + "'."); @@ -833,15 +852,15 @@ void MatchableInfo::tokenizeAsmString(const AsmMatcherInfo &Info) { // The first token of the instruction is the mnemonic, which must be a // simple string, not a $foo variable or a singleton register. if (AsmOperands.empty()) - throw TGError(TheDef->getLoc(), + PrintFatalError(TheDef->getLoc(), "Instruction '" + TheDef->getName() + "' has no tokens"); Mnemonic = AsmOperands[0].Token; if (Mnemonic.empty()) - throw TGError(TheDef->getLoc(), + PrintFatalError(TheDef->getLoc(), "Missing instruction mnemonic"); // FIXME : Check and raise an error if it is a register. if (Mnemonic[0] == '$') - throw TGError(TheDef->getLoc(), + PrintFatalError(TheDef->getLoc(), "Invalid instruction mnemonic '" + Mnemonic.str() + "'!"); // Remove the first operand, it is tracked in the mnemonic field. @@ -851,12 +870,12 @@ void MatchableInfo::tokenizeAsmString(const AsmMatcherInfo &Info) { bool MatchableInfo::validate(StringRef CommentDelimiter, bool Hack) const { // Reject matchables with no .s string. if (AsmString.empty()) - throw TGError(TheDef->getLoc(), "instruction with empty asm string"); + PrintFatalError(TheDef->getLoc(), "instruction with empty asm string"); // Reject any matchables with a newline in them, they should be marked // isCodeGenOnly if they are pseudo instructions. if (AsmString.find('\n') != std::string::npos) - throw TGError(TheDef->getLoc(), + PrintFatalError(TheDef->getLoc(), "multiline instruction is not valid for the asmparser, " "mark it isCodeGenOnly"); @@ -864,7 +883,7 @@ bool MatchableInfo::validate(StringRef CommentDelimiter, bool Hack) const { // has one line. if (!CommentDelimiter.empty() && StringRef(AsmString).find(CommentDelimiter) != StringRef::npos) - throw TGError(TheDef->getLoc(), + PrintFatalError(TheDef->getLoc(), "asmstring for instruction has comment character in it, " "mark it isCodeGenOnly"); @@ -878,7 +897,7 @@ bool MatchableInfo::validate(StringRef CommentDelimiter, bool Hack) const { for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) { StringRef Tok = AsmOperands[i].Token; if (Tok[0] == '$' && Tok.find(':') != StringRef::npos) - throw TGError(TheDef->getLoc(), + PrintFatalError(TheDef->getLoc(), "matchable with operand modifier '" + Tok.str() + "' not supported by asm matcher. Mark isCodeGenOnly!"); @@ -886,7 +905,7 @@ bool MatchableInfo::validate(StringRef CommentDelimiter, bool Hack) const { // We reject aliases and ignore instructions for now. if (Tok[0] == '$' && !OperandNames.insert(Tok).second) { if (!Hack) - throw TGError(TheDef->getLoc(), + PrintFatalError(TheDef->getLoc(), "ERROR: matchable with tied operand '" + Tok.str() + "' can never be matched!"); // FIXME: Should reject these. The ARM backend hits this with $lane in a @@ -974,7 +993,7 @@ AsmMatcherInfo::getOperandClass(const CGIOperandList::OperandInfo &OI, int SubOpIdx) { Record *Rec = OI.Rec; if (SubOpIdx != -1) - Rec = dynamic_cast<DefInit*>(OI.MIOperandInfo->getArg(SubOpIdx))->getDef(); + Rec = cast<DefInit>(OI.MIOperandInfo->getArg(SubOpIdx))->getDef(); return getOperandClass(Rec, SubOpIdx); } @@ -985,10 +1004,10 @@ AsmMatcherInfo::getOperandClass(Record *Rec, int SubOpIdx) { // use it, else just fall back to the underlying register class. const RecordVal *R = Rec->getValue("ParserMatchClass"); if (R == 0 || R->getValue() == 0) - throw "Record `" + Rec->getName() + - "' does not have a ParserMatchClass!\n"; + PrintFatalError("Record `" + Rec->getName() + + "' does not have a ParserMatchClass!\n"); - if (DefInit *DI= dynamic_cast<DefInit*>(R->getValue())) { + if (DefInit *DI= dyn_cast<DefInit>(R->getValue())) { Record *MatchClass = DI->getDef(); if (ClassInfo *CI = AsmOperandClasses[MatchClass]) return CI; @@ -997,26 +1016,28 @@ AsmMatcherInfo::getOperandClass(Record *Rec, int SubOpIdx) { // No custom match class. Just use the register class. Record *ClassRec = Rec->getValueAsDef("RegClass"); if (!ClassRec) - throw TGError(Rec->getLoc(), "RegisterOperand `" + Rec->getName() + + PrintFatalError(Rec->getLoc(), "RegisterOperand `" + Rec->getName() + "' has no associated register class!\n"); if (ClassInfo *CI = RegisterClassClasses[ClassRec]) return CI; - throw TGError(Rec->getLoc(), "register class has no class info!"); + PrintFatalError(Rec->getLoc(), "register class has no class info!"); } if (Rec->isSubClassOf("RegisterClass")) { if (ClassInfo *CI = RegisterClassClasses[Rec]) return CI; - throw TGError(Rec->getLoc(), "register class has no class info!"); + PrintFatalError(Rec->getLoc(), "register class has no class info!"); } - assert(Rec->isSubClassOf("Operand") && "Unexpected operand!"); + if (!Rec->isSubClassOf("Operand")) + PrintFatalError(Rec->getLoc(), "Operand `" + Rec->getName() + + "' does not derive from class Operand!\n"); Record *MatchClass = Rec->getValueAsDef("ParserMatchClass"); if (ClassInfo *CI = AsmOperandClasses[MatchClass]) return CI; - throw TGError(Rec->getLoc(), "operand has no match class!"); + PrintFatalError(Rec->getLoc(), "operand has no match class!"); } void AsmMatcherInfo:: @@ -1164,7 +1185,7 @@ void AsmMatcherInfo::buildOperandClasses() { ListInit *Supers = (*it)->getValueAsListInit("SuperClasses"); for (unsigned i = 0, e = Supers->getSize(); i != e; ++i) { - DefInit *DI = dynamic_cast<DefInit*>(Supers->getElement(i)); + DefInit *DI = dyn_cast<DefInit>(Supers->getElement(i)); if (!DI) { PrintError((*it)->getLoc(), "Invalid super class reference!"); continue; @@ -1182,33 +1203,31 @@ void AsmMatcherInfo::buildOperandClasses() { // Get or construct the predicate method name. Init *PMName = (*it)->getValueInit("PredicateMethod"); - if (StringInit *SI = dynamic_cast<StringInit*>(PMName)) { + if (StringInit *SI = dyn_cast<StringInit>(PMName)) { CI->PredicateMethod = SI->getValue(); } else { - assert(dynamic_cast<UnsetInit*>(PMName) && - "Unexpected PredicateMethod field!"); + assert(isa<UnsetInit>(PMName) && "Unexpected PredicateMethod field!"); CI->PredicateMethod = "is" + CI->ClassName; } // Get or construct the render method name. Init *RMName = (*it)->getValueInit("RenderMethod"); - if (StringInit *SI = dynamic_cast<StringInit*>(RMName)) { + if (StringInit *SI = dyn_cast<StringInit>(RMName)) { CI->RenderMethod = SI->getValue(); } else { - assert(dynamic_cast<UnsetInit*>(RMName) && - "Unexpected RenderMethod field!"); + assert(isa<UnsetInit>(RMName) && "Unexpected RenderMethod field!"); CI->RenderMethod = "add" + CI->ClassName + "Operands"; } // Get the parse method name or leave it as empty. Init *PRMName = (*it)->getValueInit("ParserMethod"); - if (StringInit *SI = dynamic_cast<StringInit*>(PRMName)) + if (StringInit *SI = dyn_cast<StringInit>(PRMName)) CI->ParserMethod = SI->getValue(); // Get the diagnostic type or leave it as empty. // Get the parse method name or leave it as empty. Init *DiagnosticType = (*it)->getValueInit("DiagnosticType"); - if (StringInit *SI = dynamic_cast<StringInit*>(DiagnosticType)) + if (StringInit *SI = dyn_cast<StringInit>(DiagnosticType)) CI->DiagnosticType = SI->getValue(); AsmOperandClasses[*it] = CI; @@ -1228,7 +1247,8 @@ void AsmMatcherInfo::buildOperandMatchInfo() { /// Map containing a mask with all operands indices that can be found for /// that class inside a instruction. - std::map<ClassInfo*, unsigned> OpClassMask; + typedef std::map<ClassInfo*, unsigned, LessClassInfoPtr> OpClassMaskTy; + OpClassMaskTy OpClassMask; for (std::vector<MatchableInfo*>::const_iterator it = Matchables.begin(), ie = Matchables.end(); @@ -1247,7 +1267,7 @@ void AsmMatcherInfo::buildOperandMatchInfo() { } // Generate operand match info for each mnemonic/operand class pair. - for (std::map<ClassInfo*, unsigned>::iterator iit = OpClassMask.begin(), + for (OpClassMaskTy::iterator iit = OpClassMask.begin(), iie = OpClassMask.end(); iit != iie; ++iit) { unsigned OpMask = iit->second; ClassInfo *CI = iit->first; @@ -1267,7 +1287,7 @@ void AsmMatcherInfo::buildInfo() { continue; if (Pred->getName().empty()) - throw TGError(Pred->getLoc(), "Predicate has no name!"); + PrintFatalError(Pred->getLoc(), "Predicate has no name!"); unsigned FeatureNo = SubtargetFeatures.size(); SubtargetFeatures[Pred] = new SubtargetFeatureInfo(Pred, FeatureNo); @@ -1448,7 +1468,7 @@ void AsmMatcherInfo::buildInfo() { ClassInfo *FromClass = getTokenClass(Rec->getValueAsString("FromToken")); ClassInfo *ToClass = getTokenClass(Rec->getValueAsString("ToToken")); if (FromClass == ToClass) - throw TGError(Rec->getLoc(), + PrintFatalError(Rec->getLoc(), "error: Destination value identical to source value."); FromClass->SuperClasses.push_back(ToClass); } @@ -1470,7 +1490,7 @@ buildInstructionOperandReference(MatchableInfo *II, // Map this token to an operand. unsigned Idx; if (!Operands.hasOperandNamed(OperandName, Idx)) - throw TGError(II->TheDef->getLoc(), "error: unable to find operand: '" + + PrintFatalError(II->TheDef->getLoc(), "error: unable to find operand: '" + OperandName.str() + "'"); // If the instruction operand has multiple suboperands, but the parser @@ -1541,7 +1561,7 @@ void AsmMatcherInfo::buildAliasOperandReference(MatchableInfo *II, return; } - throw TGError(II->TheDef->getLoc(), "error: unable to find operand: '" + + PrintFatalError(II->TheDef->getLoc(), "error: unable to find operand: '" + OperandName.str() + "'"); } @@ -1563,7 +1583,7 @@ void MatchableInfo::buildInstructionResultOperands() { // Find out what operand from the asmparser this MCInst operand comes from. int SrcOperand = findAsmOperandNamed(OpInfo.Name); if (OpInfo.Name.empty() || SrcOperand == -1) - throw TGError(TheDef->getLoc(), "Instruction '" + + PrintFatalError(TheDef->getLoc(), "Instruction '" + TheDef->getName() + "' has operand '" + OpInfo.Name + "' that doesn't appear in asm string!"); @@ -1615,7 +1635,7 @@ void MatchableInfo::buildAliasResultOperands() { StringRef Name = CGA.ResultOperands[AliasOpNo].getName(); int SrcOperand = findAsmOperand(Name, SubIdx); if (SrcOperand == -1) - throw TGError(TheDef->getLoc(), "Instruction '" + + PrintFatalError(TheDef->getLoc(), "Instruction '" + TheDef->getName() + "' has operand '" + OpName + "' that doesn't appear in asm string!"); unsigned NumOperands = (SubIdx == -1 ? OpInfo->MINumOperands : 1); @@ -1638,35 +1658,85 @@ void MatchableInfo::buildAliasResultOperands() { } } -static void emitConvertToMCInst(CodeGenTarget &Target, StringRef ClassName, - std::vector<MatchableInfo*> &Infos, - raw_ostream &OS) { - // Write the convert function to a separate stream, so we can drop it after - // the enum. - std::string ConvertFnBody; - raw_string_ostream CvtOS(ConvertFnBody); +static unsigned getConverterOperandID(const std::string &Name, + SetVector<std::string> &Table, + bool &IsNew) { + IsNew = Table.insert(Name); - // Function we have already generated. - std::set<std::string> GeneratedFns; + unsigned ID = IsNew ? Table.size() - 1 : + std::find(Table.begin(), Table.end(), Name) - Table.begin(); - // Start the unified conversion function. - CvtOS << "bool " << Target.getName() << ClassName << "::\n"; - CvtOS << "ConvertToMCInst(unsigned Kind, MCInst &Inst, " - << "unsigned Opcode,\n" - << " const SmallVectorImpl<MCParsedAsmOperand*" - << "> &Operands) {\n"; - CvtOS << " Inst.setOpcode(Opcode);\n"; - CvtOS << " switch (Kind) {\n"; - CvtOS << " default:\n"; + assert(ID < Table.size()); + + return ID; +} - // Start the enum, which we will generate inline. - OS << "// Unified function for converting operands to MCInst instances.\n\n"; - OS << "enum ConversionKind {\n"; +static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, + std::vector<MatchableInfo*> &Infos, + raw_ostream &OS) { + SetVector<std::string> OperandConversionKinds; + SetVector<std::string> InstructionConversionKinds; + std::vector<std::vector<uint8_t> > ConversionTable; + size_t MaxRowLength = 2; // minimum is custom converter plus terminator. // TargetOperandClass - This is the target's operand class, like X86Operand. std::string TargetOperandClass = Target.getName() + "Operand"; + // Write the convert function to a separate stream, so we can drop it after + // the enum. We'll build up the conversion handlers for the individual + // operand types opportunistically as we encounter them. + std::string ConvertFnBody; + raw_string_ostream CvtOS(ConvertFnBody); + // Start the unified conversion function. + CvtOS << "void " << Target.getName() << ClassName << "::\n" + << "convertToMCInst(unsigned Kind, MCInst &Inst, " + << "unsigned Opcode,\n" + << " const SmallVectorImpl<MCParsedAsmOperand*" + << "> &Operands) {\n" + << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n" + << " const uint8_t *Converter = ConversionTable[Kind];\n" + << " Inst.setOpcode(Opcode);\n" + << " for (const uint8_t *p = Converter; *p; p+= 2) {\n" + << " switch (*p) {\n" + << " default: llvm_unreachable(\"invalid conversion entry!\");\n" + << " case CVT_Reg:\n" + << " static_cast<" << TargetOperandClass + << "*>(Operands[*(p + 1)])->addRegOperands(Inst, 1);\n" + << " break;\n" + << " case CVT_Tied:\n" + << " Inst.addOperand(Inst.getOperand(*(p + 1)));\n" + << " break;\n"; + + std::string OperandFnBody; + raw_string_ostream OpOS(OperandFnBody); + // Start the operand number lookup function. + OpOS << "void " << Target.getName() << ClassName << "::\n" + << "convertToMapAndConstraints(unsigned Kind,\n"; + OpOS.indent(27); + OpOS << "const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {\n" + << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n" + << " unsigned NumMCOperands = 0;\n" + << " const uint8_t *Converter = ConversionTable[Kind];\n" + << " for (const uint8_t *p = Converter; *p; p+= 2) {\n" + << " switch (*p) {\n" + << " default: llvm_unreachable(\"invalid conversion entry!\");\n" + << " case CVT_Reg:\n" + << " Operands[*(p + 1)]->setMCOperandNum(NumMCOperands);\n" + << " Operands[*(p + 1)]->setConstraint(\"m\");\n" + << " ++NumMCOperands;\n" + << " break;\n" + << " case CVT_Tied:\n" + << " ++NumMCOperands;\n" + << " break;\n"; + + // Pre-populate the operand conversion kinds with the standard always + // available entries. + OperandConversionKinds.insert("CVT_Done"); + OperandConversionKinds.insert("CVT_Reg"); + OperandConversionKinds.insert("CVT_Tied"); + enum { CVT_Done, CVT_Reg, CVT_Tied }; + for (std::vector<MatchableInfo*>::const_iterator it = Infos.begin(), ie = Infos.end(); it != ie; ++it) { MatchableInfo &II = **it; @@ -1679,24 +1749,35 @@ static void emitConvertToMCInst(CodeGenTarget &Target, StringRef ClassName, II.ConversionFnKind = Signature; // Check if we have already generated this signature. - if (!GeneratedFns.insert(Signature).second) + if (!InstructionConversionKinds.insert(Signature)) continue; - // If not, emit it now. Add to the enum list. - OS << " " << Signature << ",\n"; + // Remember this converter for the kind enum. + unsigned KindID = OperandConversionKinds.size(); + OperandConversionKinds.insert("CVT_" + AsmMatchConverter); + + // Add the converter row for this instruction. + ConversionTable.push_back(std::vector<uint8_t>()); + ConversionTable.back().push_back(KindID); + ConversionTable.back().push_back(CVT_Done); + + // Add the handler to the conversion driver function. + CvtOS << " case CVT_" << AsmMatchConverter << ":\n" + << " " << AsmMatchConverter << "(Inst, Operands);\n" + << " break;\n"; - CvtOS << " case " << Signature << ":\n"; - CvtOS << " return " << AsmMatchConverter - << "(Inst, Opcode, Operands);\n"; + // FIXME: Handle the operand number lookup for custom match functions. continue; } // Build the conversion function signature. std::string Signature = "Convert"; - std::string CaseBody; - raw_string_ostream CaseOS(CaseBody); + + std::vector<uint8_t> ConversionRow; // Compute the convert enum and the case body. + MaxRowLength = std::max(MaxRowLength, II.ResOperands.size()*2 + 1 ); + for (unsigned i = 0, e = II.ResOperands.size(); i != e; ++i) { const MatchableInfo::ResOperand &OpInfo = II.ResOperands[i]; @@ -1709,74 +1790,180 @@ static void emitConvertToMCInst(CodeGenTarget &Target, StringRef ClassName, // Registers are always converted the same, don't duplicate the // conversion function based on them. Signature += "__"; - if (Op.Class->isRegisterClass()) - Signature += "Reg"; - else - Signature += Op.Class->ClassName; + std::string Class; + Class = Op.Class->isRegisterClass() ? "Reg" : Op.Class->ClassName; + Signature += Class; Signature += utostr(OpInfo.MINumOperands); Signature += "_" + itostr(OpInfo.AsmOperandNum); - CaseOS << " ((" << TargetOperandClass << "*)Operands[" - << (OpInfo.AsmOperandNum+1) << "])->" << Op.Class->RenderMethod - << "(Inst, " << OpInfo.MINumOperands << ");\n"; + // Add the conversion kind, if necessary, and get the associated ID + // the index of its entry in the vector). + std::string Name = "CVT_" + (Op.Class->isRegisterClass() ? "Reg" : + Op.Class->RenderMethod); + + bool IsNewConverter = false; + unsigned ID = getConverterOperandID(Name, OperandConversionKinds, + IsNewConverter); + + // Add the operand entry to the instruction kind conversion row. + ConversionRow.push_back(ID); + ConversionRow.push_back(OpInfo.AsmOperandNum + 1); + + if (!IsNewConverter) + break; + + // This is a new operand kind. Add a handler for it to the + // converter driver. + CvtOS << " case " << Name << ":\n" + << " static_cast<" << TargetOperandClass + << "*>(Operands[*(p + 1)])->" + << Op.Class->RenderMethod << "(Inst, " << OpInfo.MINumOperands + << ");\n" + << " break;\n"; + + // Add a handler for the operand number lookup. + OpOS << " case " << Name << ":\n" + << " Operands[*(p + 1)]->setMCOperandNum(NumMCOperands);\n" + << " Operands[*(p + 1)]->setConstraint(\"m\");\n" + << " NumMCOperands += " << OpInfo.MINumOperands << ";\n" + << " break;\n"; break; } - case MatchableInfo::ResOperand::TiedOperand: { // If this operand is tied to a previous one, just copy the MCInst // operand from the earlier one.We can only tie single MCOperand values. //assert(OpInfo.MINumOperands == 1 && "Not a singular MCOperand"); unsigned TiedOp = OpInfo.TiedOperandNum; assert(i > TiedOp && "Tied operand precedes its target!"); - CaseOS << " Inst.addOperand(Inst.getOperand(" << TiedOp << "));\n"; Signature += "__Tie" + utostr(TiedOp); + ConversionRow.push_back(CVT_Tied); + ConversionRow.push_back(TiedOp); + // FIXME: Handle the operand number lookup for tied operands. break; } case MatchableInfo::ResOperand::ImmOperand: { int64_t Val = OpInfo.ImmVal; - CaseOS << " Inst.addOperand(MCOperand::CreateImm(" << Val << "));\n"; - Signature += "__imm" + itostr(Val); + std::string Ty = "imm_" + itostr(Val); + Signature += "__" + Ty; + + std::string Name = "CVT_" + Ty; + bool IsNewConverter = false; + unsigned ID = getConverterOperandID(Name, OperandConversionKinds, + IsNewConverter); + // Add the operand entry to the instruction kind conversion row. + ConversionRow.push_back(ID); + ConversionRow.push_back(0); + + if (!IsNewConverter) + break; + + CvtOS << " case " << Name << ":\n" + << " Inst.addOperand(MCOperand::CreateImm(" << Val << "));\n" + << " break;\n"; + + OpOS << " case " << Name << ":\n" + << " Operands[*(p + 1)]->setMCOperandNum(NumMCOperands);\n" + << " Operands[*(p + 1)]->setConstraint(\"\");\n" + << " ++NumMCOperands;\n" + << " break;\n"; break; } case MatchableInfo::ResOperand::RegOperand: { + std::string Reg, Name; if (OpInfo.Register == 0) { - CaseOS << " Inst.addOperand(MCOperand::CreateReg(0));\n"; - Signature += "__reg0"; + Name = "reg0"; + Reg = "0"; } else { - std::string N = getQualifiedName(OpInfo.Register); - CaseOS << " Inst.addOperand(MCOperand::CreateReg(" << N << "));\n"; - Signature += "__reg" + OpInfo.Register->getName(); + Reg = getQualifiedName(OpInfo.Register); + Name = "reg" + OpInfo.Register->getName(); } + Signature += "__" + Name; + Name = "CVT_" + Name; + bool IsNewConverter = false; + unsigned ID = getConverterOperandID(Name, OperandConversionKinds, + IsNewConverter); + // Add the operand entry to the instruction kind conversion row. + ConversionRow.push_back(ID); + ConversionRow.push_back(0); + + if (!IsNewConverter) + break; + CvtOS << " case " << Name << ":\n" + << " Inst.addOperand(MCOperand::CreateReg(" << Reg << "));\n" + << " break;\n"; + + OpOS << " case " << Name << ":\n" + << " Operands[*(p + 1)]->setMCOperandNum(NumMCOperands);\n" + << " Operands[*(p + 1)]->setConstraint(\"m\");\n" + << " ++NumMCOperands;\n" + << " break;\n"; } } } + // If there were no operands, add to the signature to that effect + if (Signature == "Convert") + Signature += "_NoOperands"; + II.ConversionFnKind = Signature; - // Check if we have already generated this signature. - if (!GeneratedFns.insert(Signature).second) + // Save the signature. If we already have it, don't add a new row + // to the table. + if (!InstructionConversionKinds.insert(Signature)) continue; - // If not, emit it now. Add to the enum list. - OS << " " << Signature << ",\n"; - - CvtOS << " case " << Signature << ":\n"; - CvtOS << CaseOS.str(); - CvtOS << " return true;\n"; + // Add the row to the table. + ConversionTable.push_back(ConversionRow); } - // Finish the convert function. + // Finish up the converter driver function. + CvtOS << " }\n }\n}\n\n"; + + // Finish up the operand number lookup function. + OpOS << " }\n }\n}\n\n"; - CvtOS << " }\n"; - CvtOS << " return false;\n"; - CvtOS << "}\n\n"; + OS << "namespace {\n"; + + // Output the operand conversion kind enum. + OS << "enum OperatorConversionKind {\n"; + for (unsigned i = 0, e = OperandConversionKinds.size(); i != e; ++i) + OS << " " << OperandConversionKinds[i] << ",\n"; + OS << " CVT_NUM_CONVERTERS\n"; + OS << "};\n\n"; + + // Output the instruction conversion kind enum. + OS << "enum InstructionConversionKind {\n"; + for (SetVector<std::string>::const_iterator + i = InstructionConversionKinds.begin(), + e = InstructionConversionKinds.end(); i != e; ++i) + OS << " " << *i << ",\n"; + OS << " CVT_NUM_SIGNATURES\n"; + OS << "};\n\n"; + + + OS << "} // end anonymous namespace\n\n"; - // Finish the enum, and drop the convert function after it. + // Output the conversion table. + OS << "static const uint8_t ConversionTable[CVT_NUM_SIGNATURES][" + << MaxRowLength << "] = {\n"; + + for (unsigned Row = 0, ERow = ConversionTable.size(); Row != ERow; ++Row) { + assert(ConversionTable[Row].size() % 2 == 0 && "bad conversion row!"); + OS << " // " << InstructionConversionKinds[Row] << "\n"; + OS << " { "; + for (unsigned i = 0, e = ConversionTable[Row].size(); i != e; i += 2) + OS << OperandConversionKinds[ConversionTable[Row][i]] << ", " + << (unsigned)(ConversionTable[Row][i + 1]) << ", "; + OS << "CVT_Done },\n"; + } - OS << " NumConversionVariants\n"; OS << "};\n\n"; + // Spit out the conversion driver function. OS << CvtOS.str(); + + // Spit out the operand number lookup function. + OS << OpOS.str(); } /// emitMatchClassEnumeration - Emit the enumeration for match class kinds. @@ -1853,7 +2040,7 @@ static void emitValidateOperandClass(AsmMatcherInfo &Info, OS << " MatchClassKind OpKind;\n"; OS << " switch (Operand.getReg()) {\n"; OS << " default: OpKind = InvalidMatchClass; break;\n"; - for (std::map<Record*, ClassInfo*>::iterator + for (AsmMatcherInfo::RegisterClassesTy::iterator it = Info.RegisterClasses.begin(), ie = Info.RegisterClasses.end(); it != ie; ++it) OS << " case " << Info.Target.getName() << "::" @@ -1874,7 +2061,7 @@ static void emitValidateOperandClass(AsmMatcherInfo &Info, static void emitIsSubclass(CodeGenTarget &Target, std::vector<ClassInfo*> &Infos, raw_ostream &OS) { - OS << "/// isSubclass - Compute whether \\arg A is a subclass of \\arg B.\n"; + OS << "/// isSubclass - Compute whether \\p A is a subclass of \\p B.\n"; OS << "static bool isSubclass(MatchClassKind A, MatchClassKind B) {\n"; OS << " if (A == B)\n"; OS << " return true;\n\n"; @@ -2083,7 +2270,7 @@ static std::string GetAliasRequiredFeatures(Record *R, SubtargetFeatureInfo *F = Info.getSubtargetFeature(ReqFeatures[i]); if (F == 0) - throw TGError(R->getLoc(), "Predicate '" + ReqFeatures[i]->getName() + + PrintFatalError(R->getLoc(), "Predicate '" + ReqFeatures[i]->getName() + "' is not marked as an AssemblerPredicate!"); if (NumFeatures) @@ -2146,14 +2333,14 @@ static bool emitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info) { // We can't have two aliases from the same mnemonic with no predicate. PrintError(ToVec[AliasWithNoPredicate]->getLoc(), "two MnemonicAliases with the same 'from' mnemonic!"); - throw TGError(R->getLoc(), "this is the other MnemonicAlias."); + PrintFatalError(R->getLoc(), "this is the other MnemonicAlias."); } AliasWithNoPredicate = i; continue; } if (R->getValueAsString("ToMnemonic") == I->first) - throw TGError(R->getLoc(), "MnemonicAlias to the same string"); + PrintFatalError(R->getLoc(), "MnemonicAlias to the same string"); if (!MatchCode.empty()) MatchCode += "else "; @@ -2189,17 +2376,27 @@ static const char *getMinimalTypeForRange(uint64_t Range) { } static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, - const AsmMatcherInfo &Info, StringRef ClassName) { + const AsmMatcherInfo &Info, StringRef ClassName, + StringToOffsetTable &StringTable, + unsigned MaxMnemonicIndex) { + unsigned MaxMask = 0; + for (std::vector<OperandMatchEntry>::const_iterator it = + Info.OperandMatchInfo.begin(), ie = Info.OperandMatchInfo.end(); + it != ie; ++it) { + MaxMask |= it->OperandMask; + } + // Emit the static custom operand parsing table; OS << "namespace {\n"; OS << " struct OperandMatchEntry {\n"; - OS << " static const char *const MnemonicTable;\n"; - OS << " uint32_t OperandMask;\n"; - OS << " uint32_t Mnemonic;\n"; OS << " " << getMinimalTypeForRange(1ULL << Info.SubtargetFeatures.size()) << " RequiredFeatures;\n"; + OS << " " << getMinimalTypeForRange(MaxMnemonicIndex) + << " Mnemonic;\n"; OS << " " << getMinimalTypeForRange(Info.Classes.size()) - << " Class;\n\n"; + << " Class;\n"; + OS << " " << getMinimalTypeForRange(MaxMask) + << " OperandMask;\n\n"; OS << " StringRef getMnemonic() const {\n"; OS << " return StringRef(MnemonicTable + Mnemonic + 1,\n"; OS << " MnemonicTable[Mnemonic]);\n"; @@ -2222,8 +2419,6 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, OS << "} // end anonymous namespace.\n\n"; - StringToOffsetTable StringTable; - OS << "static const OperandMatchEntry OperandMatchTable[" << Info.OperandMatchInfo.size() << "] = {\n"; @@ -2234,8 +2429,25 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, const OperandMatchEntry &OMI = *it; const MatchableInfo &II = *OMI.MI; - OS << " { " << OMI.OperandMask; + OS << " { "; + // Write the required features mask. + if (!II.RequiredFeatures.empty()) { + for (unsigned i = 0, e = II.RequiredFeatures.size(); i != e; ++i) { + if (i) OS << "|"; + OS << II.RequiredFeatures[i]->getEnumName(); + } + } else + OS << "0"; + + // 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; + + OS << ", " << OMI.OperandMask; OS << " /* "; bool printComma = false; for (int i = 0, e = 31; i !=e; ++i) @@ -2247,30 +2459,10 @@ 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 << " */, "; - - // Write the required features mask. - if (!II.RequiredFeatures.empty()) { - for (unsigned i = 0, e = II.RequiredFeatures.size(); i != e; ++i) { - if (i) OS << "|"; - OS << II.RequiredFeatures[i]->getEnumName(); - } - } else - OS << "0"; - - OS << ", " << OMI.CI->Name; - OS << " },\n"; } OS << "};\n\n"; - OS << "const char *const OperandMatchEntry::MnemonicTable =\n"; - StringTable.EmitString(OS); - OS << ";\n\n"; - // Emit the operand class switch to call the correct custom parser for // the found operand class. OS << Target.getName() << ClassName << "::OperandMatchResultTy " @@ -2407,14 +2599,20 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " // This should be included into the middle of the declaration of\n"; OS << " // your subclasses implementation of MCTargetAsmParser.\n"; OS << " unsigned ComputeAvailableFeatures(uint64_t FeatureBits) const;\n"; - OS << " bool ConvertToMCInst(unsigned Kind, MCInst &Inst, " + OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, " << "unsigned Opcode,\n" << " const SmallVectorImpl<MCParsedAsmOperand*> " << "&Operands);\n"; - OS << " bool MnemonicIsValid(StringRef Mnemonic);\n"; + OS << " void convertToMapAndConstraints(unsigned Kind,\n "; + OS << " const SmallVectorImpl<MCParsedAsmOperand*> &Operands);\n"; + OS << " bool mnemonicIsValid(StringRef Mnemonic);\n"; OS << " unsigned MatchInstructionImpl(\n"; - OS << " const SmallVectorImpl<MCParsedAsmOperand*> &Operands,\n"; - OS << " MCInst &Inst, unsigned &ErrorInfo, unsigned VariantID = 0);\n"; + OS.indent(27); + OS << "const SmallVectorImpl<MCParsedAsmOperand*> &Operands,\n" + << " MCInst &Inst,\n" + << " unsigned &ErrorInfo," + << " bool matchingInlineAsm,\n" + << " unsigned VariantID = 0);\n"; if (Info.OperandMatchInfo.size()) { OS << "\n enum OperandMatchResultTy {\n"; @@ -2447,7 +2645,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { emitSubtargetFeatureFlagEnumeration(Info, OS); // Emit the function to match a register name to number. - emitMatchRegisterName(Target, AsmParser, OS); + // This should be omitted for Mips target + if (AsmParser->getValueAsBit("ShouldEmitMatchRegisterName")) + emitMatchRegisterName(Target, AsmParser, OS); OS << "#endif // GET_REGISTER_MATCHER\n\n"; @@ -2465,8 +2665,10 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { // Generate the function that remaps for mnemonic aliases. bool HasMnemonicAliases = emitMnemonicAliases(OS, Info); - // Generate the unified function to convert operands into an MCInst. - emitConvertToMCInst(Target, ClassName, Info.Matchables, OS); + // Generate the convertToMCInst function to convert operands into an MCInst. + // Also, generate the convertToMapAndConstraints function for MS-style inline + // assembly. The latter doesn't actually generate a MCInst. + emitConvertFuncs(Target, ClassName, Info.Matchables, OS); // Emit the enumeration for classes which participate in matching. emitMatchClassEnumeration(Target, Info.Classes, OS); @@ -2484,11 +2686,25 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { emitComputeAvailableFeatures(Info, OS); + StringToOffsetTable StringTable; + size_t MaxNumOperands = 0; + unsigned MaxMnemonicIndex = 0; for (std::vector<MatchableInfo*>::const_iterator it = Info.Matchables.begin(), ie = Info.Matchables.end(); - it != ie; ++it) - MaxNumOperands = std::max(MaxNumOperands, (*it)->AsmOperands.size()); + it != ie; ++it) { + MatchableInfo &II = **it; + MaxNumOperands = std::max(MaxNumOperands, II.AsmOperands.size()); + + // Store a pascal-style length byte in the mnemonic. + std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.str(); + MaxMnemonicIndex = std::max(MaxMnemonicIndex, + StringTable.GetOrAddStringOffset(LenMnemonic, false)); + } + + OS << "static const char *const MnemonicTable =\n"; + StringTable.EmitString(OS); + OS << ";\n\n"; // Emit the static match table; unused classes get initalized to 0 which is // guaranteed to be InvalidMatchClass. @@ -2502,8 +2718,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { // following the mnemonic. OS << "namespace {\n"; OS << " struct MatchEntry {\n"; - OS << " static const char *const MnemonicTable;\n"; - OS << " uint32_t Mnemonic;\n"; + OS << " " << getMinimalTypeForRange(MaxMnemonicIndex) + << " Mnemonic;\n"; OS << " uint16_t Opcode;\n"; OS << " " << getMinimalTypeForRange(Info.Matchables.size()) << " ConvertFn;\n"; @@ -2533,8 +2749,6 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << "} // end anonymous namespace.\n\n"; - StringToOffsetTable StringTable; - OS << "static const MatchEntry MatchTable[" << Info.Matchables.size() << "] = {\n"; @@ -2573,13 +2787,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << "};\n\n"; - OS << "const char *const MatchEntry::MnemonicTable =\n"; - StringTable.EmitString(OS); - OS << ";\n\n"; - // A method to determine if a mnemonic is in the list. OS << "bool " << Target.getName() << ClassName << "::\n" - << "MnemonicIsValid(StringRef Mnemonic) {\n"; + << "mnemonicIsValid(StringRef Mnemonic) {\n"; OS << " // Search the table.\n"; OS << " std::pair<const MatchEntry*, const MatchEntry*> MnemonicRange =\n"; OS << " std::equal_range(MatchTable, MatchTable+" @@ -2592,8 +2802,14 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { << Target.getName() << ClassName << "::\n" << "MatchInstructionImpl(const SmallVectorImpl<MCParsedAsmOperand*>" << " &Operands,\n"; - OS << " MCInst &Inst, unsigned &ErrorInfo, "; - OS << "unsigned VariantID) {\n"; + OS << " MCInst &Inst,\n" + << "unsigned &ErrorInfo, bool matchingInlineAsm, unsigned VariantID) {\n"; + + OS << " // Eliminate obvious mismatches.\n"; + OS << " if (Operands.size() > " << (MaxNumOperands+1) << ") {\n"; + OS << " ErrorInfo = " << (MaxNumOperands+1) << ";\n"; + OS << " return Match_InvalidOperand;\n"; + OS << " }\n\n"; // Emit code to get the available features. OS << " // Get the current feature set.\n"; @@ -2611,12 +2827,6 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { } // Emit code to compute the class list for this operand vector. - OS << " // Eliminate obvious mismatches.\n"; - OS << " if (Operands.size() > " << (MaxNumOperands+1) << ") {\n"; - OS << " ErrorInfo = " << (MaxNumOperands+1) << ";\n"; - OS << " return Match_InvalidOperand;\n"; - OS << " }\n\n"; - OS << " // Some state to try to produce better error messages.\n"; OS << " bool HadMatchOtherThanFeatures = false;\n"; OS << " bool HadMatchOtherThanPredicate = false;\n"; @@ -2681,17 +2891,20 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " HadMatchOtherThanFeatures = true;\n"; OS << " unsigned NewMissingFeatures = it->RequiredFeatures & " "~AvailableFeatures;\n"; - OS << " if (CountPopulation_32(NewMissingFeatures) <= " - "CountPopulation_32(MissingFeatures))\n"; + OS << " if (CountPopulation_32(NewMissingFeatures) <=\n" + " CountPopulation_32(MissingFeatures))\n"; OS << " MissingFeatures = NewMissingFeatures;\n"; OS << " continue;\n"; OS << " }\n"; OS << "\n"; + OS << " if (matchingInlineAsm) {\n"; + OS << " Inst.setOpcode(it->Opcode);\n"; + OS << " convertToMapAndConstraints(it->ConvertFn, Operands);\n"; + OS << " return Match_Success;\n"; + OS << " }\n\n"; OS << " // We have selected a definite instruction, convert the parsed\n" << " // operands into the appropriate MCInst.\n"; - OS << " if (!ConvertToMCInst(it->ConvertFn, Inst,\n" - << " it->Opcode, Operands))\n"; - OS << " return Match_ConversionFail;\n"; + OS << " convertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands);\n"; OS << "\n"; // Verify the instruction with the target-specific match predicate function. @@ -2716,15 +2929,16 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " }\n\n"; OS << " // Okay, we had no match. Try to return a useful error code.\n"; - OS << " if (HadMatchOtherThanPredicate || !HadMatchOtherThanFeatures)"; - OS << " return RetCode;\n"; + OS << " if (HadMatchOtherThanPredicate || !HadMatchOtherThanFeatures)\n"; + OS << " return RetCode;\n\n"; OS << " // Missing feature matches return which features were missing\n"; OS << " ErrorInfo = MissingFeatures;\n"; OS << " return Match_MissingFeature;\n"; OS << "}\n\n"; if (Info.OperandMatchInfo.size()) - emitCustomOperandParsing(OS, Target, Info, ClassName); + emitCustomOperandParsing(OS, Target, Info, ClassName, StringTable, + MaxMnemonicIndex); OS << "#endif // GET_MATCHER_IMPLEMENTATION\n\n"; } diff --git a/contrib/llvm/utils/TableGen/AsmWriterEmitter.cpp b/contrib/llvm/utils/TableGen/AsmWriterEmitter.cpp index 57979b3..a4114d9 100644 --- a/contrib/llvm/utils/TableGen/AsmWriterEmitter.cpp +++ b/contrib/llvm/utils/TableGen/AsmWriterEmitter.cpp @@ -313,7 +313,9 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { /// OpcodeInfo - This encodes the index of the string to use for the first /// chunk of the output as well as indices used for operand printing. - std::vector<unsigned> OpcodeInfo; + /// To reduce the number of unhandled cases, we expand the size from 32-bit + /// to 32+16 = 48-bit. + std::vector<uint64_t> OpcodeInfo; // Add all strings to the string table upfront so it can generate an optimized // representation. @@ -362,7 +364,7 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { // To reduce code size, we compactify common instructions into a few bits // in the opcode-indexed table. - unsigned BitsLeft = 32-AsmStrBits; + unsigned BitsLeft = 64-AsmStrBits; std::vector<std::vector<std::string> > TableDrivenOperandPrinters; @@ -388,10 +390,11 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { } // Otherwise, we can include this in the initial lookup table. Add it in. - BitsLeft -= NumBits; for (unsigned i = 0, e = InstIdxs.size(); i != e; ++i) - if (InstIdxs[i] != ~0U) - OpcodeInfo[i] |= InstIdxs[i] << (BitsLeft+AsmStrBits); + if (InstIdxs[i] != ~0U) { + OpcodeInfo[i] |= (uint64_t)InstIdxs[i] << (64-BitsLeft); + } + BitsLeft -= NumBits; // Remove the info about this operand. for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { @@ -410,16 +413,32 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { } - - O<<" static const unsigned OpInfo[] = {\n"; + // We always emit at least one 32-bit table. A second table is emitted if + // more bits are needed. + O<<" static const uint32_t OpInfo[] = {\n"; for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { - O << " " << OpcodeInfo[i] << "U,\t// " + O << " " << (OpcodeInfo[i] & 0xffffffff) << "U,\t// " << NumberedInstructions[i]->TheDef->getName() << "\n"; } // Add a dummy entry so the array init doesn't end with a comma. O << " 0U\n"; O << " };\n\n"; + if (BitsLeft < 32) { + // Add a second OpInfo table only when it is necessary. + // Adjust the type of the second table based on the number of bits needed. + O << " static const uint" + << ((BitsLeft < 16) ? "32" : (BitsLeft < 24) ? "16" : "8") + << "_t OpInfo2[] = {\n"; + for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { + O << " " << (OpcodeInfo[i] >> 32) << "U,\t// " + << NumberedInstructions[i]->TheDef->getName() << "\n"; + } + // Add a dummy entry so the array init doesn't end with a comma. + O << " 0U\n"; + O << " };\n\n"; + } + // Emit the string itself. O << " const char AsmStrs[] = {\n"; StringTable.emit(O, printChar); @@ -427,13 +446,22 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { O << " O << \"\\t\";\n\n"; - O << " // Emit the opcode for the instruction.\n" - << " unsigned Bits = OpInfo[MI->getOpcode()];\n" - << " assert(Bits != 0 && \"Cannot print this instruction.\");\n" + O << " // Emit the opcode for the instruction.\n"; + if (BitsLeft < 32) { + // If we have two tables then we need to perform two lookups and combine + // the results into a single 64-bit value. + O << " uint64_t Bits1 = OpInfo[MI->getOpcode()];\n" + << " uint64_t Bits2 = OpInfo2[MI->getOpcode()];\n" + << " uint64_t Bits = (Bits2 << 32) | Bits1;\n"; + } else { + // If only one table is used we just need to perform a single lookup. + O << " uint32_t Bits = OpInfo[MI->getOpcode()];\n"; + } + O << " assert(Bits != 0 && \"Cannot print this instruction.\");\n" << " O << AsmStrs+(Bits & " << (1 << AsmStrBits)-1 << ")-1;\n\n"; // Output the table driven operand information. - BitsLeft = 32-AsmStrBits; + BitsLeft = 64-AsmStrBits; for (unsigned i = 0, e = TableDrivenOperandPrinters.size(); i != e; ++i) { std::vector<std::string> &Commands = TableDrivenOperandPrinters[i]; @@ -443,14 +471,13 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { assert(NumBits <= BitsLeft && "consistency error"); // Emit code to extract this field from Bits. - BitsLeft -= NumBits; - O << "\n // Fragment " << i << " encoded into " << NumBits << " bits for " << Commands.size() << " unique commands.\n"; if (Commands.size() == 2) { // Emit two possibilitys with if/else. - O << " if ((Bits >> " << (BitsLeft+AsmStrBits) << ") & " + O << " if ((Bits >> " + << (64-BitsLeft) << ") & " << ((1 << NumBits)-1) << ") {\n" << Commands[1] << " } else {\n" @@ -460,7 +487,8 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { // Emit a single possibility. O << Commands[0] << "\n\n"; } else { - O << " switch ((Bits >> " << (BitsLeft+AsmStrBits) << ") & " + O << " switch ((Bits >> " + << (64-BitsLeft) << ") & " << ((1 << NumBits)-1) << ") {\n" << " default: // unreachable.\n"; @@ -472,6 +500,7 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { } O << " }\n\n"; } + BitsLeft -= NumBits; } // Okay, delete instructions with no operand info left. @@ -537,9 +566,9 @@ emitRegisterNameString(raw_ostream &O, StringRef AltName, std::vector<std::string> AltNames = Reg.TheDef->getValueAsListOfStrings("AltNames"); if (AltNames.size() <= Idx) - throw TGError(Reg.TheDef->getLoc(), - (Twine("Register definition missing alt name for '") + - AltName + "'.").str()); + PrintFatalError(Reg.TheDef->getLoc(), + (Twine("Register definition missing alt name for '") + + AltName + "'.").str()); AsmName = AltNames[Idx]; } } @@ -551,7 +580,7 @@ emitRegisterNameString(raw_ostream &O, StringRef AltName, StringTable.emit(O, printChar); O << " };\n\n"; - O << " static const unsigned RegAsmOffset" << AltName << "[] = {"; + O << " static const uint32_t RegAsmOffset" << AltName << "[] = {"; for (unsigned i = 0, e = Registers.size(); i != e; ++i) { if ((i % 14) == 0) O << "\n "; @@ -590,7 +619,7 @@ void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) { emitRegisterNameString(O, "", Registers); if (hasAltNames) { - O << " const unsigned *RegAsmOffset;\n" + O << " const uint32_t *RegAsmOffset;\n" << " const char *AsmStrs;\n" << " switch(AltIdx) {\n" << " default: llvm_unreachable(\"Invalid register alt name index!\");\n"; @@ -763,7 +792,7 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { if (!R->getValueAsBit("EmitAlias")) continue; // We were told not to emit the alias, but to emit the aliasee. const DagInit *DI = R->getValueAsDag("ResultInst"); - const DefInit *Op = dynamic_cast<const DefInit*>(DI->getOperator()); + const DefInit *Op = cast<DefInit>(DI->getOperator()); AliasMap[getQualifiedName(Op->getDef())].push_back(Alias); } diff --git a/contrib/llvm/utils/TableGen/AsmWriterInst.cpp b/contrib/llvm/utils/TableGen/AsmWriterInst.cpp index 350a2cc..fe1f756 100644 --- a/contrib/llvm/utils/TableGen/AsmWriterInst.cpp +++ b/contrib/llvm/utils/TableGen/AsmWriterInst.cpp @@ -14,6 +14,7 @@ #include "AsmWriterInst.h" #include "CodeGenTarget.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" using namespace llvm; @@ -123,8 +124,8 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, != std::string::npos) { AddLiteralString(std::string(1, AsmString[DollarPos+1])); } else { - throw "Non-supported escaped character found in instruction '" + - CGI.TheDef->getName() + "'!"; + PrintFatalError("Non-supported escaped character found in instruction '" + + CGI.TheDef->getName() + "'!"); } LastEmitted = DollarPos+2; continue; @@ -162,15 +163,15 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, // brace. if (hasCurlyBraces) { if (VarEnd >= AsmString.size()) - throw "Reached end of string before terminating curly brace in '" - + CGI.TheDef->getName() + "'"; + PrintFatalError("Reached end of string before terminating curly brace in '" + + CGI.TheDef->getName() + "'"); // Look for a modifier string. if (AsmString[VarEnd] == ':') { ++VarEnd; if (VarEnd >= AsmString.size()) - throw "Reached end of string before terminating curly brace in '" - + CGI.TheDef->getName() + "'"; + PrintFatalError("Reached end of string before terminating curly brace in '" + + CGI.TheDef->getName() + "'"); unsigned ModifierStart = VarEnd; while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) @@ -178,17 +179,17 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, Modifier = std::string(AsmString.begin()+ModifierStart, AsmString.begin()+VarEnd); if (Modifier.empty()) - throw "Bad operand modifier name in '"+ CGI.TheDef->getName() + "'"; + PrintFatalError("Bad operand modifier name in '"+ CGI.TheDef->getName() + "'"); } if (AsmString[VarEnd] != '}') - throw "Variable name beginning with '{' did not end with '}' in '" - + CGI.TheDef->getName() + "'"; + PrintFatalError("Variable name beginning with '{' did not end with '}' in '" + + CGI.TheDef->getName() + "'"); ++VarEnd; } if (VarName.empty() && Modifier.empty()) - throw "Stray '$' in '" + CGI.TheDef->getName() + - "' asm string, maybe you want $$?"; + PrintFatalError("Stray '$' in '" + CGI.TheDef->getName() + + "' asm string, maybe you want $$?"); if (VarName.empty()) { // Just a modifier, pass this into PrintSpecial. diff --git a/contrib/llvm/utils/TableGen/CallingConvEmitter.cpp b/contrib/llvm/utils/TableGen/CallingConvEmitter.cpp index e9c4bd3..94f3c65 100644 --- a/contrib/llvm/utils/TableGen/CallingConvEmitter.cpp +++ b/contrib/llvm/utils/TableGen/CallingConvEmitter.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenTarget.h" +#include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" #include <cassert> @@ -93,7 +94,7 @@ void CallingConvEmitter::EmitAction(Record *Action, O << Action->getValueAsString("Predicate"); } else { Action->dump(); - throw "Unknown CCPredicateAction!"; + PrintFatalError("Unknown CCPredicateAction!"); } O << ") {\n"; @@ -131,7 +132,7 @@ void CallingConvEmitter::EmitAction(Record *Action, ListInit *ShadowRegList = Action->getValueAsListInit("ShadowRegList"); if (ShadowRegList->getSize() >0 && ShadowRegList->getSize() != RegList->getSize()) - throw "Invalid length of list of shadowed registers"; + PrintFatalError("Invalid length of list of shadowed registers"); if (RegList->getSize() == 1) { O << IndentStr << "if (unsigned Reg = State.AllocateReg("; @@ -177,12 +178,12 @@ void CallingConvEmitter::EmitAction(Record *Action, if (Size) O << Size << ", "; else - O << "\n" << IndentStr << " State.getTarget().getTargetData()" + O << "\n" << IndentStr << " State.getTarget().getDataLayout()" "->getTypeAllocSize(EVT(LocVT).getTypeForEVT(State.getContext())), "; if (Align) O << Align; else - O << "\n" << IndentStr << " State.getTarget().getTargetData()" + O << "\n" << IndentStr << " State.getTarget().getDataLayout()" "->getABITypeAlignment(EVT(LocVT).getTypeForEVT(State.getContext()))"; if (Action->isSubClassOf("CCAssignToStackWithShadow")) O << ", " << getQualifiedName(Action->getValueAsDef("ShadowReg")); @@ -221,7 +222,7 @@ void CallingConvEmitter::EmitAction(Record *Action, O << IndentStr << IndentStr << "return false;\n"; } else { Action->dump(); - throw "Unknown CCAction!"; + PrintFatalError("Unknown CCAction!"); } } } diff --git a/contrib/llvm/utils/TableGen/CodeEmitterGen.cpp b/contrib/llvm/utils/TableGen/CodeEmitterGen.cpp index 31a39b1..3e4f626 100644 --- a/contrib/llvm/utils/TableGen/CodeEmitterGen.cpp +++ b/contrib/llvm/utils/TableGen/CodeEmitterGen.cpp @@ -91,11 +91,11 @@ void CodeEmitterGen::reverseBits(std::vector<Record*> &Insts) { // return the variable bit position. Otherwise return -1. int CodeEmitterGen::getVariableBit(const std::string &VarName, BitsInit *BI, int bit) { - if (VarBitInit *VBI = dynamic_cast<VarBitInit*>(BI->getBit(bit))) { - if (VarInit *VI = dynamic_cast<VarInit*>(VBI->getVariable())) + if (VarBitInit *VBI = dyn_cast<VarBitInit>(BI->getBit(bit))) { + if (VarInit *VI = dyn_cast<VarInit>(VBI->getBitVar())) if (VI->getName() == VarName) return VBI->getBitNum(); - } else if (VarInit *VI = dynamic_cast<VarInit*>(BI->getBit(bit))) { + } else if (VarInit *VI = dyn_cast<VarInit>(BI->getBit(bit))) { if (VI->getName() == VarName) return 0; } @@ -134,10 +134,13 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName, assert(!CGI.Operands.isFlatOperandNotEmitted(OpIdx) && "Explicitly used operand also marked as not emitted!"); } else { + unsigned NumberOps = CGI.Operands.size(); /// If this operand is not supposed to be emitted by the /// generated emitter, skip it. - while (CGI.Operands.isFlatOperandNotEmitted(NumberedOp)) + while (NumberedOp < NumberOps && + CGI.Operands.isFlatOperandNotEmitted(NumberedOp)) ++NumberedOp; + OpIdx = NumberedOp++; } @@ -269,7 +272,7 @@ void CodeEmitterGen::run(raw_ostream &o) { // Start by filling in fixed values. uint64_t Value = 0; for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i) { - if (BitInit *B = dynamic_cast<BitInit*>(BI->getBit(e-i-1))) + if (BitInit *B = dyn_cast<BitInit>(BI->getBit(e-i-1))) Value |= (uint64_t)B->getValue() << (e-i-1); } o << " UINT64_C(" << Value << ")," << '\t' << "// " << R->getName() << "\n"; diff --git a/contrib/llvm/utils/TableGen/CodeGenDAGPatterns.cpp b/contrib/llvm/utils/TableGen/CodeGenDAGPatterns.cpp index 34f8a34..d5b581b 100644 --- a/contrib/llvm/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/contrib/llvm/utils/TableGen/CodeGenDAGPatterns.cpp @@ -79,14 +79,19 @@ bool EEVT::TypeSet::FillWithPossibleTypes(TreePattern &TP, const std::vector<MVT::SimpleValueType> &LegalTypes = TP.getDAGPatterns().getTargetInfo().getLegalValueTypes(); + if (TP.hasError()) + return false; + for (unsigned i = 0, e = LegalTypes.size(); i != e; ++i) if (Pred == 0 || Pred(LegalTypes[i])) TypeVec.push_back(LegalTypes[i]); // If we have nothing that matches the predicate, bail out. - if (TypeVec.empty()) + if (TypeVec.empty()) { TP.error("Type inference contradiction found, no " + std::string(PredicateName) + " types found"); + return false; + } // No need to sort with one element. if (TypeVec.size() == 1) return true; @@ -146,9 +151,9 @@ std::string EEVT::TypeSet::getName() const { /// MergeInTypeInfo - This merges in type information from the specified /// argument. If 'this' changes, it returns true. If the two types are -/// contradictory (e.g. merge f32 into i32) then this throws an exception. +/// contradictory (e.g. merge f32 into i32) then this flags an error. bool EEVT::TypeSet::MergeInTypeInfo(const EEVT::TypeSet &InVT, TreePattern &TP){ - if (InVT.isCompletelyUnknown() || *this == InVT) + if (InVT.isCompletelyUnknown() || *this == InVT || TP.hasError()) return false; if (isCompletelyUnknown()) { @@ -224,11 +229,13 @@ bool EEVT::TypeSet::MergeInTypeInfo(const EEVT::TypeSet &InVT, TreePattern &TP){ // FIXME: Really want an SMLoc here! TP.error("Type inference contradiction found, merging '" + InVT.getName() + "' into '" + InputSet.getName() + "'"); - return true; // unreachable + return false; } /// EnforceInteger - Remove all non-integer types from this set. bool EEVT::TypeSet::EnforceInteger(TreePattern &TP) { + if (TP.hasError()) + return false; // If we know nothing, then get the full set. if (TypeVec.empty()) return FillWithPossibleTypes(TP, isInteger, "integer"); @@ -242,14 +249,18 @@ bool EEVT::TypeSet::EnforceInteger(TreePattern &TP) { if (!isInteger(TypeVec[i])) TypeVec.erase(TypeVec.begin()+i--); - if (TypeVec.empty()) + if (TypeVec.empty()) { TP.error("Type inference contradiction found, '" + InputSet.getName() + "' needs to be integer"); + return false; + } return true; } /// EnforceFloatingPoint - Remove all integer types from this set. bool EEVT::TypeSet::EnforceFloatingPoint(TreePattern &TP) { + if (TP.hasError()) + return false; // If we know nothing, then get the full set. if (TypeVec.empty()) return FillWithPossibleTypes(TP, isFloatingPoint, "floating point"); @@ -264,14 +275,19 @@ bool EEVT::TypeSet::EnforceFloatingPoint(TreePattern &TP) { if (!isFloatingPoint(TypeVec[i])) TypeVec.erase(TypeVec.begin()+i--); - if (TypeVec.empty()) + if (TypeVec.empty()) { TP.error("Type inference contradiction found, '" + InputSet.getName() + "' needs to be floating point"); + return false; + } return true; } /// EnforceScalar - Remove all vector types from this. bool EEVT::TypeSet::EnforceScalar(TreePattern &TP) { + if (TP.hasError()) + return false; + // If we know nothing, then get the full set. if (TypeVec.empty()) return FillWithPossibleTypes(TP, isScalar, "scalar"); @@ -286,14 +302,19 @@ bool EEVT::TypeSet::EnforceScalar(TreePattern &TP) { if (!isScalar(TypeVec[i])) TypeVec.erase(TypeVec.begin()+i--); - if (TypeVec.empty()) + if (TypeVec.empty()) { TP.error("Type inference contradiction found, '" + InputSet.getName() + "' needs to be scalar"); + return false; + } return true; } /// EnforceVector - Remove all vector types from this. bool EEVT::TypeSet::EnforceVector(TreePattern &TP) { + if (TP.hasError()) + return false; + // If we know nothing, then get the full set. if (TypeVec.empty()) return FillWithPossibleTypes(TP, isVector, "vector"); @@ -308,9 +329,11 @@ bool EEVT::TypeSet::EnforceVector(TreePattern &TP) { MadeChange = true; } - if (TypeVec.empty()) + if (TypeVec.empty()) { TP.error("Type inference contradiction found, '" + InputSet.getName() + "' needs to be a vector"); + return false; + } return MadeChange; } @@ -319,6 +342,9 @@ bool EEVT::TypeSet::EnforceVector(TreePattern &TP) { /// EnforceSmallerThan - 'this' must be a smaller VT than Other. Update /// this an other based on this information. bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) { + if (TP.hasError()) + return false; + // Both operands must be integer or FP, but we don't care which. bool MadeChange = false; @@ -365,19 +391,22 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) { if (hasVectorTypes() && Other.hasVectorTypes()) { if (Type.getSizeInBits() >= OtherType.getSizeInBits()) if (Type.getVectorElementType().getSizeInBits() - >= OtherType.getVectorElementType().getSizeInBits()) + >= OtherType.getVectorElementType().getSizeInBits()) { TP.error("Type inference contradiction found, '" + getName() + "' element type not smaller than '" + Other.getName() +"'!"); + return false; + } } else // For scalar types, the bitsize of this type must be larger // than that of the other. - if (Type.getSizeInBits() >= OtherType.getSizeInBits()) + if (Type.getSizeInBits() >= OtherType.getSizeInBits()) { TP.error("Type inference contradiction found, '" + getName() + "' is not smaller than '" + Other.getName() +"'!"); - + return false; + } } @@ -437,9 +466,11 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) { // If this is the only type in the large set, the constraint can never be // satisfied. if ((Other.hasIntegerTypes() && OtherIntSize == 0) - || (Other.hasFloatingPointTypes() && OtherFPSize == 0)) + || (Other.hasFloatingPointTypes() && OtherFPSize == 0)) { TP.error("Type inference contradiction found, '" + Other.getName() + "' has nothing larger than '" + getName() +"'!"); + return false; + } // Okay, find the largest type in the Other set and remove it from the // current set. @@ -493,9 +524,11 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) { // If this is the only type in the small set, the constraint can never be // satisfied. if ((hasIntegerTypes() && IntSize == 0) - || (hasFloatingPointTypes() && FPSize == 0)) + || (hasFloatingPointTypes() && FPSize == 0)) { TP.error("Type inference contradiction found, '" + getName() + "' has nothing smaller than '" + Other.getName()+"'!"); + return false; + } return MadeChange; } @@ -504,6 +537,9 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) { /// whose element is specified by VTOperand. bool EEVT::TypeSet::EnforceVectorEltTypeIs(EEVT::TypeSet &VTOperand, TreePattern &TP) { + if (TP.hasError()) + return false; + // "This" must be a vector and "VTOperand" must be a scalar. bool MadeChange = false; MadeChange |= EnforceVector(TP); @@ -535,9 +571,11 @@ bool EEVT::TypeSet::EnforceVectorEltTypeIs(EEVT::TypeSet &VTOperand, } } - if (TypeVec.empty()) // FIXME: Really want an SMLoc here! + if (TypeVec.empty()) { // FIXME: Really want an SMLoc here! TP.error("Type inference contradiction found, forcing '" + InputSet.getName() + "' to have a vector element"); + return false; + } return MadeChange; } @@ -574,10 +612,6 @@ bool EEVT::TypeSet::EnforceVectorSubVectorTypeIs(EEVT::TypeSet &VTOperand, //===----------------------------------------------------------------------===// // Helpers for working with extended types. -bool RecordPtrCmp::operator()(const Record *LHS, const Record *RHS) const { - return LHS->getID() < RHS->getID(); -} - /// Dependent variable map for CodeGenDAGPattern variant generation typedef std::map<std::string, int> DepVarMap; @@ -586,7 +620,7 @@ typedef DepVarMap::const_iterator DepVarMap_citer; static void FindDepVarsOf(TreePatternNode *N, DepVarMap &DepMap) { if (N->isLeaf()) { - if (dynamic_cast<DefInit*>(N->getLeafValue()) != NULL) + if (isa<DefInit>(N->getLeafValue())) DepMap[N->getName()]++; } else { for (size_t i = 0, e = N->getNumChildren(); i != e; ++i) @@ -695,7 +729,7 @@ static unsigned getPatternSize(const TreePatternNode *P, unsigned Size = 3; // The node itself. // If the root node is a ConstantSDNode, increases its size. // e.g. (set R32:$dst, 0). - if (P->isLeaf() && dynamic_cast<IntInit*>(P->getLeafValue())) + if (P->isLeaf() && isa<IntInit>(P->getLeafValue())) Size += 2; // FIXME: This is a hack to statically increase the priority of patterns @@ -719,7 +753,7 @@ static unsigned getPatternSize(const TreePatternNode *P, Child->getType(0) != MVT::Other) Size += getPatternSize(Child, CGP); else if (Child->isLeaf()) { - if (dynamic_cast<IntInit*>(Child->getLeafValue())) + if (isa<IntInit>(Child->getLeafValue())) Size += 5; // Matches a ConstantSDNode (+3) and a specific value (+2). else if (Child->getComplexPatternInfo(CGP)) Size += getPatternSize(Child, CGP); @@ -745,7 +779,7 @@ getPatternComplexity(const CodeGenDAGPatterns &CGP) const { std::string PatternToMatch::getPredicateCheck() const { std::string PredicateCheck; for (unsigned i = 0, e = Predicates->getSize(); i != e; ++i) { - if (DefInit *Pred = dynamic_cast<DefInit*>(Predicates->getElement(i))) { + if (DefInit *Pred = dyn_cast<DefInit>(Predicates->getElement(i))) { Record *Def = Pred->getDef(); if (!Def->isSubClassOf("Predicate")) { #ifndef NDEBUG @@ -773,7 +807,7 @@ SDTypeConstraint::SDTypeConstraint(Record *R) { ConstraintType = SDTCisVT; x.SDTCisVT_Info.VT = getValueType(R->getValueAsDef("VT")); if (x.SDTCisVT_Info.VT == MVT::isVoid) - throw TGError(R->getLoc(), "Cannot use 'Void' as type to SDTCisVT"); + PrintFatalError(R->getLoc(), "Cannot use 'Void' as type to SDTCisVT"); } else if (R->isSubClassOf("SDTCisPtrTy")) { ConstraintType = SDTCisPtrTy; @@ -833,11 +867,13 @@ static TreePatternNode *getOperandNum(unsigned OpNo, TreePatternNode *N, /// ApplyTypeConstraint - Given a node in a pattern, apply this type /// constraint to the nodes operands. This returns true if it makes a -/// change, false otherwise. If a type contradiction is found, throw an -/// exception. +/// change, false otherwise. If a type contradiction is found, flag an error. bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N, const SDNodeInfo &NodeInfo, TreePattern &TP) const { + if (TP.hasError()) + return false; + unsigned ResNo = 0; // The result number being referenced. TreePatternNode *NodeToApply = getOperandNum(OperandNo, N, NodeInfo, ResNo); @@ -868,10 +904,12 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N, // The NodeToApply must be a leaf node that is a VT. OtherOperandNum must // have an integer type that is smaller than the VT. if (!NodeToApply->isLeaf() || - !dynamic_cast<DefInit*>(NodeToApply->getLeafValue()) || + !isa<DefInit>(NodeToApply->getLeafValue()) || !static_cast<DefInit*>(NodeToApply->getLeafValue())->getDef() - ->isSubClassOf("ValueType")) + ->isSubClassOf("ValueType")) { TP.error(N->getOperator()->getName() + " expects a VT operand!"); + return false; + } MVT::SimpleValueType VT = getValueType(static_cast<DefInit*>(NodeToApply->getLeafValue())->getDef()); @@ -1025,8 +1063,9 @@ static unsigned GetNumNodeResults(Record *Operator, CodeGenDAGPatterns &CDP) { // Get the result tree. DagInit *Tree = Operator->getValueAsDag("Fragment"); Record *Op = 0; - if (Tree && dynamic_cast<DefInit*>(Tree->getOperator())) - Op = dynamic_cast<DefInit*>(Tree->getOperator())->getDef(); + if (Tree) + if (DefInit *DI = dyn_cast<DefInit>(Tree->getOperator())) + Op = DI->getDef(); assert(Op && "Invalid Fragment"); return GetNumNodeResults(Op, CDP); } @@ -1100,8 +1139,8 @@ bool TreePatternNode::isIsomorphicTo(const TreePatternNode *N, return false; if (isLeaf()) { - if (DefInit *DI = dynamic_cast<DefInit*>(getLeafValue())) { - if (DefInit *NDI = dynamic_cast<DefInit*>(N->getLeafValue())) { + if (DefInit *DI = dyn_cast<DefInit>(getLeafValue())) { + if (DefInit *NDI = dyn_cast<DefInit>(N->getLeafValue())) { return ((DI->getDef() == NDI->getDef()) && (DepVars.find(getName()) == DepVars.end() || getName() == N->getName())); @@ -1158,8 +1197,8 @@ SubstituteFormalArguments(std::map<std::string, TreePatternNode*> &ArgMap) { TreePatternNode *Child = getChild(i); if (Child->isLeaf()) { Init *Val = Child->getLeafValue(); - if (dynamic_cast<DefInit*>(Val) && - static_cast<DefInit*>(Val)->getDef()->getName() == "node") { + if (isa<DefInit>(Val) && + cast<DefInit>(Val)->getDef()->getName() == "node") { // We found a use of a formal argument, replace it with its value. TreePatternNode *NewChild = ArgMap[Child->getName()]; assert(NewChild && "Couldn't find formal argument!"); @@ -1179,7 +1218,11 @@ SubstituteFormalArguments(std::map<std::string, TreePatternNode*> &ArgMap) { /// fragments, inline them into place, giving us a pattern without any /// PatFrag references. TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) { - if (isLeaf()) return this; // nothing to do. + if (TP.hasError()) + return 0; + + if (isLeaf()) + return this; // nothing to do. Record *Op = getOperator(); if (!Op->isSubClassOf("PatFrag")) { @@ -1202,9 +1245,11 @@ TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) { TreePattern *Frag = TP.getDAGPatterns().getPatternFragment(Op); // Verify that we are passing the right number of operands. - if (Frag->getNumArgs() != Children.size()) + if (Frag->getNumArgs() != Children.size()) { TP.error("'" + Op->getName() + "' fragment requires " + utostr(Frag->getNumArgs()) + " operands!"); + return 0; + } TreePatternNode *FragTree = Frag->getOnlyTree()->clone(); @@ -1320,8 +1365,7 @@ getIntrinsicInfo(const CodeGenDAGPatterns &CDP) const { getOperator() != CDP.get_intrinsic_wo_chain_sdnode()) return 0; - unsigned IID = - dynamic_cast<IntInit*>(getChild(0)->getLeafValue())->getValue(); + unsigned IID = cast<IntInit>(getChild(0)->getLeafValue())->getValue(); return &CDP.getIntrinsicInfo(IID); } @@ -1331,7 +1375,7 @@ const ComplexPattern * TreePatternNode::getComplexPatternInfo(const CodeGenDAGPatterns &CGP) const { if (!isLeaf()) return 0; - DefInit *DI = dynamic_cast<DefInit*>(getLeafValue()); + DefInit *DI = dyn_cast<DefInit>(getLeafValue()); if (DI && DI->getDef()->isSubClassOf("ComplexPattern")) return &CGP.getComplexPattern(DI->getDef()); return 0; @@ -1379,12 +1423,14 @@ TreePatternNode::isCommutativeIntrinsic(const CodeGenDAGPatterns &CDP) const { /// ApplyTypeConstraints - Apply all of the type constraints relevant to /// this node and its children in the tree. This returns true if it makes a -/// change, false otherwise. If a type contradiction is found, throw an -/// exception. +/// change, false otherwise. If a type contradiction is found, flag an error. bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { + if (TP.hasError()) + return false; + CodeGenDAGPatterns &CDP = TP.getDAGPatterns(); if (isLeaf()) { - if (DefInit *DI = dynamic_cast<DefInit*>(getLeafValue())) { + if (DefInit *DI = dyn_cast<DefInit>(getLeafValue())) { // If it's a regclass or something else known, include the type. bool MadeChange = false; for (unsigned i = 0, e = Types.size(); i != e; ++i) @@ -1393,7 +1439,7 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { return MadeChange; } - if (IntInit *II = dynamic_cast<IntInit*>(getLeafValue())) { + if (IntInit *II = dyn_cast<IntInit>(getLeafValue())) { assert(Types.size() == 1 && "Invalid IntInit"); // Int inits are always integers. :) @@ -1410,21 +1456,15 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { // Make sure that the value is representable for this type. if (Size >= 32) return MadeChange; - int Val = (II->getValue() << (32-Size)) >> (32-Size); - if (Val == II->getValue()) return MadeChange; - - // If sign-extended doesn't fit, does it fit as unsigned? - unsigned ValueMask; - unsigned UnsignedVal; - ValueMask = unsigned(~uint32_t(0UL) >> (32-Size)); - UnsignedVal = unsigned(II->getValue()); - - if ((ValueMask & UnsignedVal) == UnsignedVal) + // Check that the value doesn't use more bits than we have. It must either + // be a sign- or zero-extended equivalent of the original. + int64_t SignBitAndAbove = II->getValue() >> (Size - 1); + if (SignBitAndAbove == -1 || SignBitAndAbove == 0 || SignBitAndAbove == 1) return MadeChange; - TP.error("Integer value '" + itostr(II->getValue())+ + TP.error("Integer value '" + itostr(II->getValue()) + "' is out of range for type '" + getEnumName(getType(0)) + "'!"); - return MadeChange; + return false; } return false; } @@ -1487,10 +1527,12 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { for (unsigned i = 0, e = NumRetVTs; i != e; ++i) MadeChange |= UpdateNodeType(i, Int->IS.RetVTs[i], TP); - if (getNumChildren() != NumParamVTs + 1) + if (getNumChildren() != NumParamVTs + 1) { TP.error("Intrinsic '" + Int->Name + "' expects " + utostr(NumParamVTs) + " operands, not " + utostr(getNumChildren() - 1) + " operands!"); + return false; + } // Apply type info to the intrinsic ID. MadeChange |= getChild(0)->UpdateNodeType(0, MVT::iPTR, TP); @@ -1510,9 +1552,11 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { // Check that the number of operands is sane. Negative operands -> varargs. if (NI.getNumOperands() >= 0 && - getNumChildren() != (unsigned)NI.getNumOperands()) + getNumChildren() != (unsigned)NI.getNumOperands()) { TP.error(getOperator()->getName() + " node requires exactly " + itostr(NI.getNumOperands()) + " operands!"); + return false; + } bool MadeChange = NI.ApplyTypeConstraints(this, TP); for (unsigned i = 0, e = getNumChildren(); i != e; ++i) @@ -1541,7 +1585,7 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { const CodeGenRegisterClass &RC = CDP.getTargetInfo().getRegisterClass(RegClass); MadeChange |= UpdateNodeType(ResNo, RC.getValueTypes(), TP); - } else if (ResultNode->getName() == "unknown") { + } else if (ResultNode->isSubClassOf("unknown_class")) { // Nothing to do. } else { assert(ResultNode->isSubClassOf("RegisterClass") && @@ -1581,15 +1625,16 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { // If the instruction expects a predicate or optional def operand, we // codegen this by setting the operand to it's default value if it has a // non-empty DefaultOps field. - if ((OperandNode->isSubClassOf("PredicateOperand") || - OperandNode->isSubClassOf("OptionalDefOperand")) && + if (OperandNode->isSubClassOf("OperandWithDefaultOps") && !CDP.getDefaultOperand(OperandNode).DefaultOps.empty()) continue; // Verify that we didn't run out of provided operands. - if (ChildNo >= getNumChildren()) + if (ChildNo >= getNumChildren()) { TP.error("Instruction '" + getOperator()->getName() + "' expects more operands than were provided."); + return false; + } MVT::SimpleValueType VT; TreePatternNode *Child = getChild(ChildNo++); @@ -1609,7 +1654,7 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { MadeChange |= Child->UpdateNodeType(ChildResNo, VT, TP); } else if (OperandNode->isSubClassOf("PointerLikeRegClass")) { MadeChange |= Child->UpdateNodeType(ChildResNo, MVT::iPTR, TP); - } else if (OperandNode->getName() == "unknown") { + } else if (OperandNode->isSubClassOf("unknown_class")) { // Nothing to do. } else llvm_unreachable("Unknown operand type!"); @@ -1617,9 +1662,11 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { MadeChange |= Child->ApplyTypeConstraints(TP, NotRegisters); } - if (ChildNo != getNumChildren()) + if (ChildNo != getNumChildren()) { TP.error("Instruction '" + getOperator()->getName() + "' was provided too many operands!"); + return false; + } return MadeChange; } @@ -1627,9 +1674,11 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { assert(getOperator()->isSubClassOf("SDNodeXForm") && "Unknown node type!"); // Node transforms always take one operand. - if (getNumChildren() != 1) + if (getNumChildren() != 1) { TP.error("Node transform '" + getOperator()->getName() + "' requires one operand!"); + return false; + } bool MadeChange = getChild(0)->ApplyTypeConstraints(TP, NotRegisters); @@ -1652,7 +1701,7 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { static bool OnlyOnRHSOfCommutative(TreePatternNode *N) { if (!N->isLeaf() && N->getOperator()->getName() == "imm") return true; - if (N->isLeaf() && dynamic_cast<IntInit*>(N->getLeafValue())) + if (N->isLeaf() && isa<IntInit>(N->getLeafValue())) return true; return false; } @@ -1703,27 +1752,30 @@ bool TreePatternNode::canPatternMatch(std::string &Reason, // TreePattern::TreePattern(Record *TheRec, ListInit *RawPat, bool isInput, - CodeGenDAGPatterns &cdp) : TheRecord(TheRec), CDP(cdp){ - isInputPattern = isInput; + CodeGenDAGPatterns &cdp) : TheRecord(TheRec), CDP(cdp), + isInputPattern(isInput), HasError(false) { for (unsigned i = 0, e = RawPat->getSize(); i != e; ++i) Trees.push_back(ParseTreePattern(RawPat->getElement(i), "")); } TreePattern::TreePattern(Record *TheRec, DagInit *Pat, bool isInput, - CodeGenDAGPatterns &cdp) : TheRecord(TheRec), CDP(cdp){ - isInputPattern = isInput; + CodeGenDAGPatterns &cdp) : TheRecord(TheRec), CDP(cdp), + isInputPattern(isInput), HasError(false) { Trees.push_back(ParseTreePattern(Pat, "")); } TreePattern::TreePattern(Record *TheRec, TreePatternNode *Pat, bool isInput, - CodeGenDAGPatterns &cdp) : TheRecord(TheRec), CDP(cdp){ - isInputPattern = isInput; + CodeGenDAGPatterns &cdp) : TheRecord(TheRec), CDP(cdp), + isInputPattern(isInput), HasError(false) { Trees.push_back(Pat); } -void TreePattern::error(const std::string &Msg) const { +void TreePattern::error(const std::string &Msg) { + if (HasError) + return; dump(); - throw TGError(TheRecord->getLoc(), "In " + TheRecord->getName() + ": " + Msg); + PrintError(TheRecord->getLoc(), "In " + TheRecord->getName() + ": " + Msg); + HasError = true; } void TreePattern::ComputeNamedNodes() { @@ -1741,7 +1793,7 @@ void TreePattern::ComputeNamedNodes(TreePatternNode *N) { TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){ - if (DefInit *DI = dynamic_cast<DefInit*>(TheInit)) { + if (DefInit *DI = dyn_cast<DefInit>(TheInit)) { Record *R = DI->getDef(); // Direct reference to a leaf DagNode or PatFrag? Turn it into a @@ -1765,26 +1817,26 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){ return Res; } - if (IntInit *II = dynamic_cast<IntInit*>(TheInit)) { + if (IntInit *II = dyn_cast<IntInit>(TheInit)) { if (!OpName.empty()) error("Constant int argument should not have a name!"); return new TreePatternNode(II, 1); } - if (BitsInit *BI = dynamic_cast<BitsInit*>(TheInit)) { + if (BitsInit *BI = dyn_cast<BitsInit>(TheInit)) { // Turn this into an IntInit. Init *II = BI->convertInitializerTo(IntRecTy::get()); - if (II == 0 || !dynamic_cast<IntInit*>(II)) + if (II == 0 || !isa<IntInit>(II)) error("Bits value must be constants!"); return ParseTreePattern(II, OpName); } - DagInit *Dag = dynamic_cast<DagInit*>(TheInit); + DagInit *Dag = dyn_cast<DagInit>(TheInit); if (!Dag) { TheInit->dump(); error("Pattern has unexpected init kind!"); } - DefInit *OpDef = dynamic_cast<DefInit*>(Dag->getOperator()); + DefInit *OpDef = dyn_cast<DefInit>(Dag->getOperator()); if (!OpDef) error("Pattern has unexpected operator type!"); Record *Operator = OpDef->getDef(); @@ -1912,7 +1964,7 @@ static bool SimplifyTree(TreePatternNode *&N) { /// InferAllTypes - Infer/propagate as many types throughout the expression /// patterns as possible. Return true if all types are inferred, false -/// otherwise. Throw an exception if a type contradiction is found. +/// otherwise. Flags an error if a type contradiction is found. bool TreePattern:: InferAllTypes(const StringMap<SmallVector<TreePatternNode*,1> > *InNamedTypes) { if (NamedNodes.empty()) @@ -1949,7 +2001,7 @@ InferAllTypes(const StringMap<SmallVector<TreePatternNode*,1> > *InNamedTypes) { // us to match things like: // def : Pat<(v1i64 (bitconvert(v2i32 DPR:$src))), (v1i64 DPR:$src)>; if (Nodes[i] == Trees[0] && Nodes[i]->isLeaf()) { - DefInit *DI = dynamic_cast<DefInit*>(Nodes[i]->getLeafValue()); + DefInit *DI = dyn_cast<DefInit>(Nodes[i]->getLeafValue()); if (DI && (DI->getDef()->isSubClassOf("RegisterClass") || DI->getDef()->isSubClassOf("RegisterOperand"))) continue; @@ -2033,6 +2085,9 @@ CodeGenDAGPatterns::CodeGenDAGPatterns(RecordKeeper &R) : // stores, and side effects in many cases by examining an // instruction's pattern. InferInstructionFlags(); + + // Verify that instruction flags match the patterns. + VerifyInstructionFlags(); } CodeGenDAGPatterns::~CodeGenDAGPatterns() { @@ -2111,7 +2166,7 @@ void CodeGenDAGPatterns::ParsePatternFragments() { // Parse the operands list. DagInit *OpsList = Fragments[i]->getValueAsDag("Operands"); - DefInit *OpsOp = dynamic_cast<DefInit*>(OpsList->getOperator()); + DefInit *OpsOp = dyn_cast<DefInit>(OpsList->getOperator()); // Special cases: ops == outs == ins. Different names are used to // improve readability. if (!OpsOp || @@ -2123,9 +2178,8 @@ void CodeGenDAGPatterns::ParsePatternFragments() { // Copy over the arguments. Args.clear(); for (unsigned j = 0, e = OpsList->getNumArgs(); j != e; ++j) { - if (!dynamic_cast<DefInit*>(OpsList->getArg(j)) || - static_cast<DefInit*>(OpsList->getArg(j))-> - getDef()->getName() != "node") + if (!isa<DefInit>(OpsList->getArg(j)) || + cast<DefInit>(OpsList->getArg(j))->getDef()->getName() != "node") P->error("Operands list should all be 'node' values."); if (OpsList->getArgName(j).empty()) P->error("Operands list should have names for each operand!"); @@ -2161,14 +2215,8 @@ void CodeGenDAGPatterns::ParsePatternFragments() { // Infer as many types as possible. Don't worry about it if we don't infer // all of them, some may depend on the inputs of the pattern. - try { - ThePat->InferAllTypes(); - } catch (...) { - // If this pattern fragment is not supported by this target (no types can - // satisfy its constraints), just ignore it. If the bogus pattern is - // actually used by instructions, the type consistency error will be - // reported there. - } + ThePat->InferAllTypes(); + ThePat->resetError(); // If debugging, print out the pattern fragment result. DEBUG(ThePat->dump()); @@ -2176,53 +2224,46 @@ void CodeGenDAGPatterns::ParsePatternFragments() { } void CodeGenDAGPatterns::ParseDefaultOperands() { - std::vector<Record*> DefaultOps[2]; - DefaultOps[0] = Records.getAllDerivedDefinitions("PredicateOperand"); - DefaultOps[1] = Records.getAllDerivedDefinitions("OptionalDefOperand"); + std::vector<Record*> DefaultOps; + DefaultOps = Records.getAllDerivedDefinitions("OperandWithDefaultOps"); // Find some SDNode. assert(!SDNodes.empty() && "No SDNodes parsed?"); Init *SomeSDNode = DefInit::get(SDNodes.begin()->first); - for (unsigned iter = 0; iter != 2; ++iter) { - for (unsigned i = 0, e = DefaultOps[iter].size(); i != e; ++i) { - DagInit *DefaultInfo = DefaultOps[iter][i]->getValueAsDag("DefaultOps"); - - // Clone the DefaultInfo dag node, changing the operator from 'ops' to - // SomeSDnode so that we can parse this. - std::vector<std::pair<Init*, std::string> > Ops; - for (unsigned op = 0, e = DefaultInfo->getNumArgs(); op != e; ++op) - Ops.push_back(std::make_pair(DefaultInfo->getArg(op), - DefaultInfo->getArgName(op))); - DagInit *DI = DagInit::get(SomeSDNode, "", Ops); - - // Create a TreePattern to parse this. - TreePattern P(DefaultOps[iter][i], DI, false, *this); - assert(P.getNumTrees() == 1 && "This ctor can only produce one tree!"); - - // Copy the operands over into a DAGDefaultOperand. - DAGDefaultOperand DefaultOpInfo; - - TreePatternNode *T = P.getTree(0); - for (unsigned op = 0, e = T->getNumChildren(); op != e; ++op) { - TreePatternNode *TPN = T->getChild(op); - while (TPN->ApplyTypeConstraints(P, false)) - /* Resolve all types */; - - if (TPN->ContainsUnresolvedType()) { - if (iter == 0) - throw "Value #" + utostr(i) + " of PredicateOperand '" + - DefaultOps[iter][i]->getName() +"' doesn't have a concrete type!"; - else - throw "Value #" + utostr(i) + " of OptionalDefOperand '" + - DefaultOps[iter][i]->getName() +"' doesn't have a concrete type!"; - } - DefaultOpInfo.DefaultOps.push_back(TPN); + for (unsigned i = 0, e = DefaultOps.size(); i != e; ++i) { + DagInit *DefaultInfo = DefaultOps[i]->getValueAsDag("DefaultOps"); + + // Clone the DefaultInfo dag node, changing the operator from 'ops' to + // SomeSDnode so that we can parse this. + std::vector<std::pair<Init*, std::string> > Ops; + for (unsigned op = 0, e = DefaultInfo->getNumArgs(); op != e; ++op) + Ops.push_back(std::make_pair(DefaultInfo->getArg(op), + DefaultInfo->getArgName(op))); + DagInit *DI = DagInit::get(SomeSDNode, "", Ops); + + // Create a TreePattern to parse this. + TreePattern P(DefaultOps[i], DI, false, *this); + assert(P.getNumTrees() == 1 && "This ctor can only produce one tree!"); + + // Copy the operands over into a DAGDefaultOperand. + DAGDefaultOperand DefaultOpInfo; + + TreePatternNode *T = P.getTree(0); + for (unsigned op = 0, e = T->getNumChildren(); op != e; ++op) { + TreePatternNode *TPN = T->getChild(op); + while (TPN->ApplyTypeConstraints(P, false)) + /* Resolve all types */; + + if (TPN->ContainsUnresolvedType()) { + PrintFatalError("Value #" + utostr(i) + " of OperandWithDefaultOps '" + + DefaultOps[i]->getName() +"' doesn't have a concrete type!"); } - - // Insert it into the DefaultOperands map so we can find it later. - DefaultOperands[DefaultOps[iter][i]] = DefaultOpInfo; + DefaultOpInfo.DefaultOps.push_back(TPN); } + + // Insert it into the DefaultOperands map so we can find it later. + DefaultOperands[DefaultOps[i]] = DefaultOpInfo; } } @@ -2233,7 +2274,7 @@ static bool HandleUse(TreePattern *I, TreePatternNode *Pat, // No name -> not interesting. if (Pat->getName().empty()) { if (Pat->isLeaf()) { - DefInit *DI = dynamic_cast<DefInit*>(Pat->getLeafValue()); + DefInit *DI = dyn_cast<DefInit>(Pat->getLeafValue()); if (DI && (DI->getDef()->isSubClassOf("RegisterClass") || DI->getDef()->isSubClassOf("RegisterOperand"))) I->error("Input " + DI->getDef()->getName() + " must be named!"); @@ -2243,7 +2284,7 @@ static bool HandleUse(TreePattern *I, TreePatternNode *Pat, Record *Rec; if (Pat->isLeaf()) { - DefInit *DI = dynamic_cast<DefInit*>(Pat->getLeafValue()); + DefInit *DI = dyn_cast<DefInit>(Pat->getLeafValue()); if (!DI) I->error("Input $" + Pat->getName() + " must be an identifier!"); Rec = DI->getDef(); } else { @@ -2261,7 +2302,7 @@ static bool HandleUse(TreePattern *I, TreePatternNode *Pat, } Record *SlotRec; if (Slot->isLeaf()) { - SlotRec = dynamic_cast<DefInit*>(Slot->getLeafValue())->getDef(); + SlotRec = cast<DefInit>(Slot->getLeafValue())->getDef(); } else { assert(Slot->getNumChildren() == 0 && "can't be a use with children!"); SlotRec = Slot->getOperator(); @@ -2296,7 +2337,7 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, if (!Dest->isLeaf()) I->error("implicitly defined value should be a register!"); - DefInit *Val = dynamic_cast<DefInit*>(Dest->getLeafValue()); + DefInit *Val = dyn_cast<DefInit>(Dest->getLeafValue()); if (!Val || !Val->getDef()->isSubClassOf("Register")) I->error("implicitly defined value should be a register!"); InstImpResults.push_back(Val->getDef()); @@ -2337,7 +2378,7 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, if (!Dest->isLeaf()) I->error("set destination should be a register!"); - DefInit *Val = dynamic_cast<DefInit*>(Dest->getLeafValue()); + DefInit *Val = dyn_cast<DefInit>(Dest->getLeafValue()); if (!Val) I->error("set destination should be a register!"); @@ -2367,43 +2408,36 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, class InstAnalyzer { const CodeGenDAGPatterns &CDP; - bool &mayStore; - bool &mayLoad; - bool &IsBitcast; - bool &HasSideEffects; - bool &IsVariadic; public: - InstAnalyzer(const CodeGenDAGPatterns &cdp, - bool &maystore, bool &mayload, bool &isbc, bool &hse, bool &isv) - : CDP(cdp), mayStore(maystore), mayLoad(mayload), IsBitcast(isbc), - HasSideEffects(hse), IsVariadic(isv) { - } + bool hasSideEffects; + bool mayStore; + bool mayLoad; + bool isBitcast; + bool isVariadic; - /// Analyze - Analyze the specified instruction, returning true if the - /// instruction had a pattern. - bool Analyze(Record *InstRecord) { - const TreePattern *Pattern = CDP.getInstruction(InstRecord).getPattern(); - if (Pattern == 0) { - HasSideEffects = 1; - return false; // No pattern. - } + InstAnalyzer(const CodeGenDAGPatterns &cdp) + : CDP(cdp), hasSideEffects(false), mayStore(false), mayLoad(false), + isBitcast(false), isVariadic(false) {} - // FIXME: Assume only the first tree is the pattern. The others are clobber - // nodes. - AnalyzeNode(Pattern->getTree(0)); - return true; + void Analyze(const TreePattern *Pat) { + // Assume only the first tree is the pattern. The others are clobber nodes. + AnalyzeNode(Pat->getTree(0)); + } + + void Analyze(const PatternToMatch *Pat) { + AnalyzeNode(Pat->getSrcPattern()); } private: bool IsNodeBitcast(const TreePatternNode *N) const { - if (HasSideEffects || mayLoad || mayStore || IsVariadic) + if (hasSideEffects || mayLoad || mayStore || isVariadic) return false; if (N->getNumChildren() != 2) return false; const TreePatternNode *N0 = N->getChild(0); - if (!N0->isLeaf() || !dynamic_cast<DefInit*>(N0->getLeafValue())) + if (!N0->isLeaf() || !isa<DefInit>(N0->getLeafValue())) return false; const TreePatternNode *N1 = N->getChild(1); @@ -2418,16 +2452,17 @@ private: return OpInfo.getEnumName() == "ISD::BITCAST"; } +public: void AnalyzeNode(const TreePatternNode *N) { if (N->isLeaf()) { - if (DefInit *DI = dynamic_cast<DefInit*>(N->getLeafValue())) { + if (DefInit *DI = dyn_cast<DefInit>(N->getLeafValue())) { Record *LeafRec = DI->getDef(); // Handle ComplexPattern leaves. if (LeafRec->isSubClassOf("ComplexPattern")) { const ComplexPattern &CP = CDP.getComplexPattern(LeafRec); if (CP.hasProperty(SDNPMayStore)) mayStore = true; if (CP.hasProperty(SDNPMayLoad)) mayLoad = true; - if (CP.hasProperty(SDNPSideEffect)) HasSideEffects = true; + if (CP.hasProperty(SDNPSideEffect)) hasSideEffects = true; } } return; @@ -2439,7 +2474,7 @@ private: // Ignore set nodes, which are not SDNodes. if (N->getOperator()->getName() == "set") { - IsBitcast = IsNodeBitcast(N); + isBitcast = IsNodeBitcast(N); return; } @@ -2449,8 +2484,8 @@ private: // Notice properties of the node. if (OpInfo.hasProperty(SDNPMayStore)) mayStore = true; if (OpInfo.hasProperty(SDNPMayLoad)) mayLoad = true; - if (OpInfo.hasProperty(SDNPSideEffect)) HasSideEffects = true; - if (OpInfo.hasProperty(SDNPVariadic)) IsVariadic = true; + if (OpInfo.hasProperty(SDNPSideEffect)) hasSideEffects = true; + if (OpInfo.hasProperty(SDNPVariadic)) isVariadic = true; if (const CodeGenIntrinsic *IntInfo = N->getIntrinsicInfo(CDP)) { // If this is an intrinsic, analyze it. @@ -2462,68 +2497,70 @@ private: if (IntInfo->ModRef >= CodeGenIntrinsic::ReadWriteMem) // WriteMem intrinsics can have other strange effects. - HasSideEffects = true; + hasSideEffects = true; } } }; -static void InferFromPattern(const CodeGenInstruction &Inst, - bool &MayStore, bool &MayLoad, - bool &IsBitcast, - bool &HasSideEffects, bool &IsVariadic, - const CodeGenDAGPatterns &CDP) { - MayStore = MayLoad = IsBitcast = HasSideEffects = IsVariadic = false; - - bool HadPattern = - InstAnalyzer(CDP, MayStore, MayLoad, IsBitcast, HasSideEffects, IsVariadic) - .Analyze(Inst.TheDef); - - // InstAnalyzer only correctly analyzes mayStore/mayLoad so far. - if (Inst.mayStore) { // If the .td file explicitly sets mayStore, use it. - // If we decided that this is a store from the pattern, then the .td file - // entry is redundant. - if (MayStore) - PrintWarning(Inst.TheDef->getLoc(), - "mayStore flag explicitly set on " - "instruction, but flag already inferred from pattern."); - MayStore = true; +static bool InferFromPattern(CodeGenInstruction &InstInfo, + const InstAnalyzer &PatInfo, + Record *PatDef) { + bool Error = false; + + // Remember where InstInfo got its flags. + if (InstInfo.hasUndefFlags()) + InstInfo.InferredFrom = PatDef; + + // Check explicitly set flags for consistency. + if (InstInfo.hasSideEffects != PatInfo.hasSideEffects && + !InstInfo.hasSideEffects_Unset) { + // Allow explicitly setting hasSideEffects = 1 on instructions, even when + // the pattern has no side effects. That could be useful for div/rem + // instructions that may trap. + if (!InstInfo.hasSideEffects) { + Error = true; + PrintError(PatDef->getLoc(), "Pattern doesn't match hasSideEffects = " + + Twine(InstInfo.hasSideEffects)); + } } - if (Inst.mayLoad) { // If the .td file explicitly sets mayLoad, use it. - // If we decided that this is a load from the pattern, then the .td file - // entry is redundant. - if (MayLoad) - PrintWarning(Inst.TheDef->getLoc(), - "mayLoad flag explicitly set on " - "instruction, but flag already inferred from pattern."); - MayLoad = true; + if (InstInfo.mayStore != PatInfo.mayStore && !InstInfo.mayStore_Unset) { + Error = true; + PrintError(PatDef->getLoc(), "Pattern doesn't match mayStore = " + + Twine(InstInfo.mayStore)); } - if (Inst.neverHasSideEffects) { - if (HadPattern) - PrintWarning(Inst.TheDef->getLoc(), - "neverHasSideEffects flag explicitly set on " - "instruction, but flag already inferred from pattern."); - HasSideEffects = false; + if (InstInfo.mayLoad != PatInfo.mayLoad && !InstInfo.mayLoad_Unset) { + // Allow explicitly setting mayLoad = 1, even when the pattern has no loads. + // Some targets translate imediates to loads. + if (!InstInfo.mayLoad) { + Error = true; + PrintError(PatDef->getLoc(), "Pattern doesn't match mayLoad = " + + Twine(InstInfo.mayLoad)); + } } - if (Inst.hasSideEffects) { - if (HasSideEffects) - PrintWarning(Inst.TheDef->getLoc(), - "hasSideEffects flag explicitly set on " - "instruction, but flag already inferred from pattern."); - HasSideEffects = true; - } + // Transfer inferred flags. + InstInfo.hasSideEffects |= PatInfo.hasSideEffects; + InstInfo.mayStore |= PatInfo.mayStore; + InstInfo.mayLoad |= PatInfo.mayLoad; + + // These flags are silently added without any verification. + InstInfo.isBitcast |= PatInfo.isBitcast; + + // Don't infer isVariadic. This flag means something different on SDNodes and + // instructions. For example, a CALL SDNode is variadic because it has the + // call arguments as operands, but a CALL instruction is not variadic - it + // has argument registers as implicit, not explicit uses. - if (Inst.Operands.isVariadic) - IsVariadic = true; // Can warn if we want. + return Error; } /// hasNullFragReference - Return true if the DAG has any reference to the /// null_frag operator. static bool hasNullFragReference(DagInit *DI) { - DefInit *OpDef = dynamic_cast<DefInit*>(DI->getOperator()); + DefInit *OpDef = dyn_cast<DefInit>(DI->getOperator()); if (!OpDef) return false; Record *Operator = OpDef->getDef(); @@ -2531,7 +2568,7 @@ static bool hasNullFragReference(DagInit *DI) { if (Operator->getName() == "null_frag") return true; // If any of the arguments reference the null fragment, return true. for (unsigned i = 0, e = DI->getNumArgs(); i != e; ++i) { - DagInit *Arg = dynamic_cast<DagInit*>(DI->getArg(i)); + DagInit *Arg = dyn_cast<DagInit>(DI->getArg(i)); if (Arg && hasNullFragReference(Arg)) return true; } @@ -2543,7 +2580,7 @@ static bool hasNullFragReference(DagInit *DI) { /// the null_frag operator. static bool hasNullFragReference(ListInit *LI) { for (unsigned i = 0, e = LI->getSize(); i != e; ++i) { - DagInit *DI = dynamic_cast<DagInit*>(LI->getElement(i)); + DagInit *DI = dyn_cast<DagInit>(LI->getElement(i)); assert(DI && "non-dag in an instruction Pattern list?!"); if (hasNullFragReference(DI)) return true; @@ -2551,6 +2588,17 @@ static bool hasNullFragReference(ListInit *LI) { return false; } +/// Get all the instructions in a tree. +static void +getInstructionsInTree(TreePatternNode *Tree, SmallVectorImpl<Record*> &Instrs) { + if (Tree->isLeaf()) + return; + if (Tree->getOperator()->isSubClassOf("Instruction")) + Instrs.push_back(Tree->getOperator()); + for (unsigned i = 0, e = Tree->getNumChildren(); i != e; ++i) + getInstructionsInTree(Tree->getChild(i), Instrs); +} + /// ParseInstructions - Parse all of the instructions, inlining and resolving /// any fragments involved. This populates the Instructions list with fully /// resolved instructions. @@ -2560,7 +2608,7 @@ void CodeGenDAGPatterns::ParseInstructions() { for (unsigned i = 0, e = Instrs.size(); i != e; ++i) { ListInit *LI = 0; - if (dynamic_cast<ListInit*>(Instrs[i]->getValueInit("Pattern"))) + if (isa<ListInit>(Instrs[i]->getValueInit("Pattern"))) LI = Instrs[i]->getValueAsListInit("Pattern"); // If there is no pattern, only collect minimal information about the @@ -2655,7 +2703,7 @@ void CodeGenDAGPatterns::ParseInstructions() { if (i == 0) Res0Node = RNode; - Record *R = dynamic_cast<DefInit*>(RNode->getLeafValue())->getDef(); + Record *R = cast<DefInit>(RNode->getLeafValue())->getDef(); if (R == 0) I->error("Operand $" + OpName + " should be a set destination: all " "outputs must occur before inputs in operand list!"); @@ -2683,11 +2731,9 @@ void CodeGenDAGPatterns::ParseInstructions() { I->error("Operand #" + utostr(i) + " in operands list has no name!"); if (!InstInputsCheck.count(OpName)) { - // If this is an predicate operand or optional def operand with an - // DefaultOps set filled in, we can ignore this. When we codegen it, - // we will do so as always executed. - if (Op.Rec->isSubClassOf("PredicateOperand") || - Op.Rec->isSubClassOf("OptionalDefOperand")) { + // If this is an operand with a DefaultOps set filled in, we can ignore + // this. When we codegen it, we will do so as always executed. + if (Op.Rec->isSubClassOf("OperandWithDefaultOps")) { // Does it have a non-empty DefaultOps field? If so, ignore this // operand. if (!getDefaultOperand(Op.Rec).DefaultOps.empty()) @@ -2699,8 +2745,7 @@ void CodeGenDAGPatterns::ParseInstructions() { TreePatternNode *InVal = InstInputsCheck[OpName]; InstInputsCheck.erase(OpName); // It occurred, remove from map. - if (InVal->isLeaf() && - dynamic_cast<DefInit*>(InVal->getLeafValue())) { + if (InVal->isLeaf() && isa<DefInit>(InVal->getLeafValue())) { Record *InRec = static_cast<DefInit*>(InVal->getLeafValue())->getDef(); if (Op.Rec != InRec && !InRec->isSubClassOf("ComplexPattern")) I->error("Operand $" + OpName + "'s register class disagrees" @@ -2754,11 +2799,11 @@ void CodeGenDAGPatterns::ParseInstructions() { } // If we can, convert the instructions to be patterns that are matched! - for (std::map<Record*, DAGInstruction, RecordPtrCmp>::iterator II = + for (std::map<Record*, DAGInstruction, LessRecordByID>::iterator II = Instructions.begin(), E = Instructions.end(); II != E; ++II) { DAGInstruction &TheInst = II->second; - const TreePattern *I = TheInst.getPattern(); + TreePattern *I = TheInst.getPattern(); if (I == 0) continue; // No pattern. // FIXME: Assume only the first tree is the pattern. The others are clobber @@ -2789,7 +2834,7 @@ typedef std::pair<const TreePatternNode*, unsigned> NameRecord; static void FindNames(const TreePatternNode *P, std::map<std::string, NameRecord> &Names, - const TreePattern *PatternTop) { + TreePattern *PatternTop) { if (!P->getName().empty()) { NameRecord &Rec = Names[P->getName()]; // If this is the first instance of the name, remember the node. @@ -2806,12 +2851,15 @@ static void FindNames(const TreePatternNode *P, } } -void CodeGenDAGPatterns::AddPatternToMatch(const TreePattern *Pattern, +void CodeGenDAGPatterns::AddPatternToMatch(TreePattern *Pattern, const PatternToMatch &PTM) { // Do some sanity checking on the pattern we're about to match. std::string Reason; - if (!PTM.getSrcPattern()->canPatternMatch(Reason, *this)) - Pattern->error("Pattern can never match: " + Reason); + if (!PTM.getSrcPattern()->canPatternMatch(Reason, *this)) { + PrintWarning(Pattern->getRecord()->getLoc(), + Twine("Pattern can never match: ") + Reason); + return; + } // If the source pattern's root is a complex pattern, that complex pattern // must specify the nodes it can potentially match. @@ -2852,25 +2900,156 @@ void CodeGenDAGPatterns::AddPatternToMatch(const TreePattern *Pattern, void CodeGenDAGPatterns::InferInstructionFlags() { const std::vector<const CodeGenInstruction*> &Instructions = Target.getInstructionsByEnumValue(); + + // First try to infer flags from the primary instruction pattern, if any. + SmallVector<CodeGenInstruction*, 8> Revisit; + unsigned Errors = 0; for (unsigned i = 0, e = Instructions.size(); i != e; ++i) { CodeGenInstruction &InstInfo = const_cast<CodeGenInstruction &>(*Instructions[i]); - // Determine properties of the instruction from its pattern. - bool MayStore, MayLoad, IsBitcast, HasSideEffects, IsVariadic; - InferFromPattern(InstInfo, MayStore, MayLoad, IsBitcast, - HasSideEffects, IsVariadic, *this); - InstInfo.mayStore = MayStore; - InstInfo.mayLoad = MayLoad; - InstInfo.isBitcast = IsBitcast; - InstInfo.hasSideEffects = HasSideEffects; - InstInfo.Operands.isVariadic = IsVariadic; - // Sanity checks. - if (InstInfo.isReMaterializable && InstInfo.hasSideEffects) - throw TGError(InstInfo.TheDef->getLoc(), "The instruction " + - InstInfo.TheDef->getName() + - " is rematerializable AND has unmodeled side effects?"); + // Treat neverHasSideEffects = 1 as the equivalent of hasSideEffects = 0. + // This flag is obsolete and will be removed. + if (InstInfo.neverHasSideEffects) { + assert(!InstInfo.hasSideEffects); + InstInfo.hasSideEffects_Unset = false; + } + + // Get the primary instruction pattern. + const TreePattern *Pattern = getInstruction(InstInfo.TheDef).getPattern(); + if (!Pattern) { + if (InstInfo.hasUndefFlags()) + Revisit.push_back(&InstInfo); + continue; + } + InstAnalyzer PatInfo(*this); + PatInfo.Analyze(Pattern); + Errors += InferFromPattern(InstInfo, PatInfo, InstInfo.TheDef); + } + + // Second, look for single-instruction patterns defined outside the + // instruction. + for (ptm_iterator I = ptm_begin(), E = ptm_end(); I != E; ++I) { + const PatternToMatch &PTM = *I; + + // We can only infer from single-instruction patterns, otherwise we won't + // know which instruction should get the flags. + SmallVector<Record*, 8> PatInstrs; + getInstructionsInTree(PTM.getDstPattern(), PatInstrs); + if (PatInstrs.size() != 1) + continue; + + // Get the single instruction. + CodeGenInstruction &InstInfo = Target.getInstruction(PatInstrs.front()); + + // Only infer properties from the first pattern. We'll verify the others. + if (InstInfo.InferredFrom) + continue; + + InstAnalyzer PatInfo(*this); + PatInfo.Analyze(&PTM); + Errors += InferFromPattern(InstInfo, PatInfo, PTM.getSrcRecord()); + } + + if (Errors) + PrintFatalError("pattern conflicts"); + + // Revisit instructions with undefined flags and no pattern. + if (Target.guessInstructionProperties()) { + for (unsigned i = 0, e = Revisit.size(); i != e; ++i) { + CodeGenInstruction &InstInfo = *Revisit[i]; + if (InstInfo.InferredFrom) + continue; + // The mayLoad and mayStore flags default to false. + // Conservatively assume hasSideEffects if it wasn't explicit. + if (InstInfo.hasSideEffects_Unset) + InstInfo.hasSideEffects = true; + } + return; } + + // Complain about any flags that are still undefined. + for (unsigned i = 0, e = Revisit.size(); i != e; ++i) { + CodeGenInstruction &InstInfo = *Revisit[i]; + if (InstInfo.InferredFrom) + continue; + if (InstInfo.hasSideEffects_Unset) + PrintError(InstInfo.TheDef->getLoc(), + "Can't infer hasSideEffects from patterns"); + if (InstInfo.mayStore_Unset) + PrintError(InstInfo.TheDef->getLoc(), + "Can't infer mayStore from patterns"); + if (InstInfo.mayLoad_Unset) + PrintError(InstInfo.TheDef->getLoc(), + "Can't infer mayLoad from patterns"); + } +} + + +/// Verify instruction flags against pattern node properties. +void CodeGenDAGPatterns::VerifyInstructionFlags() { + unsigned Errors = 0; + for (ptm_iterator I = ptm_begin(), E = ptm_end(); I != E; ++I) { + const PatternToMatch &PTM = *I; + SmallVector<Record*, 8> Instrs; + getInstructionsInTree(PTM.getDstPattern(), Instrs); + if (Instrs.empty()) + continue; + + // Count the number of instructions with each flag set. + unsigned NumSideEffects = 0; + unsigned NumStores = 0; + unsigned NumLoads = 0; + for (unsigned i = 0, e = Instrs.size(); i != e; ++i) { + const CodeGenInstruction &InstInfo = Target.getInstruction(Instrs[i]); + NumSideEffects += InstInfo.hasSideEffects; + NumStores += InstInfo.mayStore; + NumLoads += InstInfo.mayLoad; + } + + // Analyze the source pattern. + InstAnalyzer PatInfo(*this); + PatInfo.Analyze(&PTM); + + // Collect error messages. + SmallVector<std::string, 4> Msgs; + + // Check for missing flags in the output. + // Permit extra flags for now at least. + if (PatInfo.hasSideEffects && !NumSideEffects) + Msgs.push_back("pattern has side effects, but hasSideEffects isn't set"); + + // Don't verify store flags on instructions with side effects. At least for + // intrinsics, side effects implies mayStore. + if (!PatInfo.hasSideEffects && PatInfo.mayStore && !NumStores) + Msgs.push_back("pattern may store, but mayStore isn't set"); + + // Similarly, mayStore implies mayLoad on intrinsics. + if (!PatInfo.mayStore && PatInfo.mayLoad && !NumLoads) + Msgs.push_back("pattern may load, but mayLoad isn't set"); + + // Print error messages. + if (Msgs.empty()) + continue; + ++Errors; + + for (unsigned i = 0, e = Msgs.size(); i != e; ++i) + PrintError(PTM.getSrcRecord()->getLoc(), Twine(Msgs[i]) + " on the " + + (Instrs.size() == 1 ? + "instruction" : "output instructions")); + // Provide the location of the relevant instruction definitions. + for (unsigned i = 0, e = Instrs.size(); i != e; ++i) { + if (Instrs[i] != PTM.getSrcRecord()) + PrintError(Instrs[i]->getLoc(), "defined here"); + const CodeGenInstruction &InstInfo = Target.getInstruction(Instrs[i]); + if (InstInfo.InferredFrom && + InstInfo.InferredFrom != InstInfo.TheDef && + InstInfo.InferredFrom != PTM.getSrcRecord()) + PrintError(InstInfo.InferredFrom->getLoc(), "inferred from patttern"); + } + } + if (Errors) + PrintFatalError("Errors in DAG patterns"); } /// Given a pattern result with an unresolved type, see if we can find one @@ -3230,7 +3409,7 @@ static void GenerateVariantsOf(TreePatternNode *N, for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) { TreePatternNode *Child = N->getChild(i); if (Child->isLeaf()) - if (DefInit *DI = dynamic_cast<DefInit*>(Child->getLeafValue())) { + if (DefInit *DI = dyn_cast<DefInit>(Child->getLeafValue())) { Record *RR = DI->getDef(); if (RR->isSubClassOf("Register")) continue; @@ -3330,4 +3509,3 @@ void CodeGenDAGPatterns::GenerateVariants() { DEBUG(errs() << "\n"); } } - diff --git a/contrib/llvm/utils/TableGen/CodeGenDAGPatterns.h b/contrib/llvm/utils/TableGen/CodeGenDAGPatterns.h index 5a2d40a..9be763f 100644 --- a/contrib/llvm/utils/TableGen/CodeGenDAGPatterns.h +++ b/contrib/llvm/utils/TableGen/CodeGenDAGPatterns.h @@ -105,7 +105,7 @@ namespace EEVT { /// MergeInTypeInfo - This merges in type information from the specified /// argument. If 'this' changes, it returns true. If the two types are - /// contradictory (e.g. merge f32 into i32) then this throws an exception. + /// contradictory (e.g. merge f32 into i32) then this flags an error. bool MergeInTypeInfo(const EEVT::TypeSet &InVT, TreePattern &TP); bool MergeInTypeInfo(MVT::SimpleValueType InVT, TreePattern &TP) { @@ -187,8 +187,8 @@ struct SDTypeConstraint { /// ApplyTypeConstraint - Given a node in a pattern, apply this type /// constraint to the nodes operands. This returns true if it makes a - /// change, false otherwise. If a type contradiction is found, throw an - /// exception. + /// change, false otherwise. If a type contradiction is found, an error + /// is flagged. bool ApplyTypeConstraint(TreePatternNode *N, const SDNodeInfo &NodeInfo, TreePattern &TP) const; }; @@ -232,7 +232,7 @@ public: /// ApplyTypeConstraints - Given a node in a pattern, apply the type /// constraints for this node to the operands of the node. This returns /// true if it makes a change, false otherwise. If a type contradiction is - /// found, throw an exception. + /// found, an error is flagged. bool ApplyTypeConstraints(TreePatternNode *N, TreePattern &TP) const { bool MadeChange = false; for (unsigned i = 0, e = TypeConstraints.size(); i != e; ++i) @@ -446,13 +446,12 @@ public: // Higher level manipulation routines. /// ApplyTypeConstraints - Apply all of the type constraints relevant to /// this node and its children in the tree. This returns true if it makes a - /// change, false otherwise. If a type contradiction is found, throw an - /// exception. + /// change, false otherwise. If a type contradiction is found, flag an error. bool ApplyTypeConstraints(TreePattern &TP, bool NotRegisters); /// UpdateNodeType - Set the node type of N to VT if VT contains - /// information. If N already contains a conflicting type, then throw an - /// exception. This returns true if any information was updated. + /// information. If N already contains a conflicting type, then flag an + /// error. This returns true if any information was updated. /// bool UpdateNodeType(unsigned ResNo, const EEVT::TypeSet &InTy, TreePattern &TP) { @@ -514,6 +513,10 @@ class TreePattern { /// isInputPattern - True if this is an input pattern, something to match. /// False if this is an output pattern, something to emit. bool isInputPattern; + + /// hasError - True if the currently processed nodes have unresolvable types + /// or other non-fatal errors + bool HasError; public: /// TreePattern constructor - Parse the specified DagInits into the @@ -565,13 +568,19 @@ public: /// InferAllTypes - Infer/propagate as many types throughout the expression /// patterns as possible. Return true if all types are inferred, false - /// otherwise. Throw an exception if a type contradiction is found. + /// otherwise. Bail out if a type contradiction is found. bool InferAllTypes(const StringMap<SmallVector<TreePatternNode*,1> > *NamedTypes=0); - /// error - Throw an exception, prefixing it with information about this - /// pattern. - void error(const std::string &Msg) const; + /// error - If this is the first error in the current resolution step, + /// print it and set the error flag. Otherwise, continue silently. + void error(const std::string &Msg); + bool hasError() const { + return HasError; + } + void resetError() { + HasError = false; + } void print(raw_ostream &OS) const; void dump() const; @@ -582,8 +591,8 @@ private: void ComputeNamedNodes(TreePatternNode *N); }; -/// DAGDefaultOperand - One of these is created for each PredicateOperand -/// or OptionalDefOperand that has a set ExecuteAlways / DefaultOps field. +/// DAGDefaultOperand - One of these is created for each OperandWithDefaultOps +/// that has a set ExecuteAlways / DefaultOps field. struct DAGDefaultOperand { std::vector<TreePatternNode*> DefaultOps; }; @@ -602,7 +611,7 @@ public: : Pattern(TP), Results(results), Operands(operands), ImpResults(impresults), ResultPattern(0) {} - const TreePattern *getPattern() const { return Pattern; } + TreePattern *getPattern() const { return Pattern; } unsigned getNumResults() const { return Results.size(); } unsigned getNumOperands() const { return Operands.size(); } unsigned getNumImpResults() const { return ImpResults.size(); } @@ -661,23 +670,18 @@ public: unsigned getPatternComplexity(const CodeGenDAGPatterns &CGP) const; }; -// Deterministic comparison of Record*. -struct RecordPtrCmp { - bool operator()(const Record *LHS, const Record *RHS) const; -}; - class CodeGenDAGPatterns { RecordKeeper &Records; CodeGenTarget Target; std::vector<CodeGenIntrinsic> Intrinsics; std::vector<CodeGenIntrinsic> TgtIntrinsics; - std::map<Record*, SDNodeInfo, RecordPtrCmp> SDNodes; - std::map<Record*, std::pair<Record*, std::string>, RecordPtrCmp> SDNodeXForms; - std::map<Record*, ComplexPattern, RecordPtrCmp> ComplexPatterns; - std::map<Record*, TreePattern*, RecordPtrCmp> PatternFragments; - std::map<Record*, DAGDefaultOperand, RecordPtrCmp> DefaultOperands; - std::map<Record*, DAGInstruction, RecordPtrCmp> Instructions; + std::map<Record*, SDNodeInfo, LessRecordByID> SDNodes; + std::map<Record*, std::pair<Record*, std::string>, LessRecordByID> SDNodeXForms; + std::map<Record*, ComplexPattern, LessRecordByID> ComplexPatterns; + std::map<Record*, TreePattern*, LessRecordByID> PatternFragments; + std::map<Record*, DAGDefaultOperand, LessRecordByID> DefaultOperands; + std::map<Record*, DAGInstruction, LessRecordByID> Instructions; // Specific SDNode definitions: Record *intrinsic_void_sdnode; @@ -708,7 +712,7 @@ public: return SDNodeXForms.find(R)->second; } - typedef std::map<Record*, NodeXForm, RecordPtrCmp>::const_iterator + typedef std::map<Record*, NodeXForm, LessRecordByID>::const_iterator nx_iterator; nx_iterator nx_begin() const { return SDNodeXForms.begin(); } nx_iterator nx_end() const { return SDNodeXForms.end(); } @@ -758,7 +762,7 @@ public: return PatternFragments.find(R)->second; } - typedef std::map<Record*, TreePattern*, RecordPtrCmp>::const_iterator + typedef std::map<Record*, TreePattern*, LessRecordByID>::const_iterator pf_iterator; pf_iterator pf_begin() const { return PatternFragments.begin(); } pf_iterator pf_end() const { return PatternFragments.end(); } @@ -797,8 +801,9 @@ private: void ParsePatterns(); void InferInstructionFlags(); void GenerateVariants(); + void VerifyInstructionFlags(); - void AddPatternToMatch(const TreePattern *Pattern, const PatternToMatch &PTM); + void AddPatternToMatch(TreePattern *Pattern, const PatternToMatch &PTM); void FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, std::map<std::string, TreePatternNode*> &InstInputs, diff --git a/contrib/llvm/utils/TableGen/CodeGenInstruction.cpp b/contrib/llvm/utils/TableGen/CodeGenInstruction.cpp index 12e153a..0a8684d 100644 --- a/contrib/llvm/utils/TableGen/CodeGenInstruction.cpp +++ b/contrib/llvm/utils/TableGen/CodeGenInstruction.cpp @@ -32,20 +32,20 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) { DagInit *OutDI = R->getValueAsDag("OutOperandList"); - if (DefInit *Init = dynamic_cast<DefInit*>(OutDI->getOperator())) { + if (DefInit *Init = dyn_cast<DefInit>(OutDI->getOperator())) { if (Init->getDef()->getName() != "outs") - throw R->getName() + ": invalid def name for output list: use 'outs'"; + PrintFatalError(R->getName() + ": invalid def name for output list: use 'outs'"); } else - throw R->getName() + ": invalid output list: use 'outs'"; + PrintFatalError(R->getName() + ": invalid output list: use 'outs'"); NumDefs = OutDI->getNumArgs(); DagInit *InDI = R->getValueAsDag("InOperandList"); - if (DefInit *Init = dynamic_cast<DefInit*>(InDI->getOperator())) { + if (DefInit *Init = dyn_cast<DefInit>(InDI->getOperator())) { if (Init->getDef()->getName() != "ins") - throw R->getName() + ": invalid def name for input list: use 'ins'"; + PrintFatalError(R->getName() + ": invalid def name for input list: use 'ins'"); } else - throw R->getName() + ": invalid input list: use 'ins'"; + PrintFatalError(R->getName() + ": invalid input list: use 'ins'"); unsigned MIOperandNo = 0; std::set<std::string> OperandNames; @@ -60,9 +60,9 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) { ArgName = InDI->getArgName(i-NumDefs); } - DefInit *Arg = dynamic_cast<DefInit*>(ArgInit); + DefInit *Arg = dyn_cast<DefInit>(ArgInit); if (!Arg) - throw "Illegal operand for the '" + R->getName() + "' instruction!"; + PrintFatalError("Illegal operand for the '" + R->getName() + "' instruction!"); Record *Rec = Arg->getDef(); std::string PrintMethod = "printOperand"; @@ -80,11 +80,10 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) { MIOpInfo = Rec->getValueAsDag("MIOperandInfo"); // Verify that MIOpInfo has an 'ops' root value. - if (!dynamic_cast<DefInit*>(MIOpInfo->getOperator()) || - dynamic_cast<DefInit*>(MIOpInfo->getOperator()) - ->getDef()->getName() != "ops") - throw "Bad value for MIOperandInfo in operand '" + Rec->getName() + - "'\n"; + if (!isa<DefInit>(MIOpInfo->getOperator()) || + cast<DefInit>(MIOpInfo->getOperator())->getDef()->getName() != "ops") + PrintFatalError("Bad value for MIOperandInfo in operand '" + Rec->getName() + + "'\n"); // If we have MIOpInfo, then we have #operands equal to number of entries // in MIOperandInfo. @@ -101,17 +100,17 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) { } else if (Rec->isSubClassOf("RegisterClass")) { OperandType = "OPERAND_REGISTER"; } else if (!Rec->isSubClassOf("PointerLikeRegClass") && - Rec->getName() != "unknown") - throw "Unknown operand class '" + Rec->getName() + - "' in '" + R->getName() + "' instruction!"; + !Rec->isSubClassOf("unknown_class")) + PrintFatalError("Unknown operand class '" + Rec->getName() + + "' in '" + R->getName() + "' instruction!"); // Check that the operand has a name and that it's unique. if (ArgName.empty()) - throw "In instruction '" + R->getName() + "', operand #" + utostr(i) + - " has no name!"; + PrintFatalError("In instruction '" + R->getName() + "', operand #" + utostr(i) + + " has no name!"); if (!OperandNames.insert(ArgName).second) - throw "In instruction '" + R->getName() + "', operand #" + utostr(i) + - " has the same name as a previous operand!"; + PrintFatalError("In instruction '" + R->getName() + "', operand #" + utostr(i) + + " has the same name as a previous operand!"); OperandList.push_back(OperandInfo(Rec, ArgName, PrintMethod, EncoderMethod, OperandType, MIOperandNo, NumOps, @@ -129,13 +128,13 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) { /// getOperandNamed - Return the index of the operand with the specified /// non-empty name. If the instruction does not have an operand with the -/// specified name, throw an exception. +/// specified name, abort. /// unsigned CGIOperandList::getOperandNamed(StringRef Name) const { unsigned OpIdx; if (hasOperandNamed(Name, OpIdx)) return OpIdx; - throw "'" + TheDef->getName() + "' does not have an operand named '$" + - Name.str() + "'!"; + PrintFatalError("'" + TheDef->getName() + "' does not have an operand named '$" + + Name.str() + "'!"); } /// hasOperandNamed - Query whether the instruction has an operand of the @@ -154,7 +153,7 @@ bool CGIOperandList::hasOperandNamed(StringRef Name, unsigned &OpIdx) const { std::pair<unsigned,unsigned> CGIOperandList::ParseOperandName(const std::string &Op, bool AllowWholeOp) { if (Op.empty() || Op[0] != '$') - throw TheDef->getName() + ": Illegal operand name: '" + Op + "'"; + PrintFatalError(TheDef->getName() + ": Illegal operand name: '" + Op + "'"); std::string OpName = Op.substr(1); std::string SubOpName; @@ -164,7 +163,7 @@ CGIOperandList::ParseOperandName(const std::string &Op, bool AllowWholeOp) { if (DotIdx != std::string::npos) { SubOpName = OpName.substr(DotIdx+1); if (SubOpName.empty()) - throw TheDef->getName() + ": illegal empty suboperand name in '" +Op +"'"; + PrintFatalError(TheDef->getName() + ": illegal empty suboperand name in '" +Op +"'"); OpName = OpName.substr(0, DotIdx); } @@ -174,8 +173,8 @@ CGIOperandList::ParseOperandName(const std::string &Op, bool AllowWholeOp) { // If one was needed, throw. if (OperandList[OpIdx].MINumOperands > 1 && !AllowWholeOp && SubOpName.empty()) - throw TheDef->getName() + ": Illegal to refer to" - " whole operand part of complex operand '" + Op + "'"; + PrintFatalError(TheDef->getName() + ": Illegal to refer to" + " whole operand part of complex operand '" + Op + "'"); // Otherwise, return the operand. return std::make_pair(OpIdx, 0U); @@ -184,7 +183,7 @@ CGIOperandList::ParseOperandName(const std::string &Op, bool AllowWholeOp) { // Find the suboperand number involved. DagInit *MIOpInfo = OperandList[OpIdx].MIOperandInfo; if (MIOpInfo == 0) - throw TheDef->getName() + ": unknown suboperand name in '" + Op + "'"; + PrintFatalError(TheDef->getName() + ": unknown suboperand name in '" + Op + "'"); // Find the operand with the right name. for (unsigned i = 0, e = MIOpInfo->getNumArgs(); i != e; ++i) @@ -192,7 +191,7 @@ CGIOperandList::ParseOperandName(const std::string &Op, bool AllowWholeOp) { return std::make_pair(OpIdx, i); // Otherwise, didn't find it! - throw TheDef->getName() + ": unknown suboperand name in '" + Op + "'"; + PrintFatalError(TheDef->getName() + ": unknown suboperand name in '" + Op + "'"); } static void ParseConstraint(const std::string &CStr, CGIOperandList &Ops) { @@ -204,13 +203,13 @@ static void ParseConstraint(const std::string &CStr, CGIOperandList &Ops) { std::string Name = CStr.substr(wpos+1); wpos = Name.find_first_not_of(" \t"); if (wpos == std::string::npos) - throw "Illegal format for @earlyclobber constraint: '" + CStr + "'"; + PrintFatalError("Illegal format for @earlyclobber constraint: '" + CStr + "'"); Name = Name.substr(wpos); std::pair<unsigned,unsigned> Op = Ops.ParseOperandName(Name, false); // Build the string for the operand if (!Ops[Op.first].Constraints[Op.second].isNone()) - throw "Operand '" + Name + "' cannot have multiple constraints!"; + PrintFatalError("Operand '" + Name + "' cannot have multiple constraints!"); Ops[Op.first].Constraints[Op.second] = CGIOperandList::ConstraintInfo::getEarlyClobber(); return; @@ -225,25 +224,27 @@ static void ParseConstraint(const std::string &CStr, CGIOperandList &Ops) { // TIED_TO: $src1 = $dst wpos = Name.find_first_of(" \t"); if (wpos == std::string::npos) - throw "Illegal format for tied-to constraint: '" + CStr + "'"; + PrintFatalError("Illegal format for tied-to constraint: '" + CStr + "'"); std::string DestOpName = Name.substr(0, wpos); std::pair<unsigned,unsigned> DestOp = Ops.ParseOperandName(DestOpName, false); Name = CStr.substr(pos+1); wpos = Name.find_first_not_of(" \t"); if (wpos == std::string::npos) - throw "Illegal format for tied-to constraint: '" + CStr + "'"; - - std::pair<unsigned,unsigned> SrcOp = - Ops.ParseOperandName(Name.substr(wpos), false); - if (SrcOp > DestOp) - throw "Illegal tied-to operand constraint '" + CStr + "'"; + PrintFatalError("Illegal format for tied-to constraint: '" + CStr + "'"); + std::string SrcOpName = Name.substr(wpos); + std::pair<unsigned,unsigned> SrcOp = Ops.ParseOperandName(SrcOpName, false); + if (SrcOp > DestOp) { + std::swap(SrcOp, DestOp); + std::swap(SrcOpName, DestOpName); + } unsigned FlatOpNo = Ops.getFlattenedOperandNumber(SrcOp); if (!Ops[DestOp.first].Constraints[DestOp.second].isNone()) - throw "Operand '" + DestOpName + "' cannot have multiple constraints!"; + PrintFatalError("Operand '" + DestOpName + + "' cannot have multiple constraints!"); Ops[DestOp.first].Constraints[DestOp.second] = CGIOperandList::ConstraintInfo::getTied(FlatOpNo); } @@ -287,7 +288,8 @@ void CGIOperandList::ProcessDisableEncoding(std::string DisableEncoding) { // CodeGenInstruction Implementation //===----------------------------------------------------------------------===// -CodeGenInstruction::CodeGenInstruction(Record *R) : TheDef(R), Operands(R) { +CodeGenInstruction::CodeGenInstruction(Record *R) + : TheDef(R), Operands(R), InferredFrom(0) { Namespace = R->getValueAsString("Namespace"); AsmString = R->getValueAsString("AsmString"); @@ -301,8 +303,6 @@ CodeGenInstruction::CodeGenInstruction(Record *R) : TheDef(R), Operands(R) { isBarrier = R->getValueAsBit("isBarrier"); isCall = R->getValueAsBit("isCall"); canFoldAsLoad = R->getValueAsBit("canFoldAsLoad"); - mayLoad = R->getValueAsBit("mayLoad"); - mayStore = R->getValueAsBit("mayStore"); isPredicable = Operands.isPredicable || R->getValueAsBit("isPredicable"); isConvertibleToThreeAddress = R->getValueAsBit("isConvertibleToThreeAddress"); isCommutable = R->getValueAsBit("isCommutable"); @@ -313,8 +313,13 @@ CodeGenInstruction::CodeGenInstruction(Record *R) : TheDef(R), Operands(R) { hasPostISelHook = R->getValueAsBit("hasPostISelHook"); hasCtrlDep = R->getValueAsBit("hasCtrlDep"); isNotDuplicable = R->getValueAsBit("isNotDuplicable"); - hasSideEffects = R->getValueAsBit("hasSideEffects"); + + mayLoad = R->getValueAsBitOrUnset("mayLoad", mayLoad_Unset); + mayStore = R->getValueAsBitOrUnset("mayStore", mayStore_Unset); + hasSideEffects = R->getValueAsBitOrUnset("hasSideEffects", + hasSideEffects_Unset); neverHasSideEffects = R->getValueAsBit("neverHasSideEffects"); + isAsCheapAsAMove = R->getValueAsBit("isAsCheapAsAMove"); hasExtraSrcRegAllocReq = R->getValueAsBit("hasExtraSrcRegAllocReq"); hasExtraDefRegAllocReq = R->getValueAsBit("hasExtraDefRegAllocReq"); @@ -324,7 +329,7 @@ CodeGenInstruction::CodeGenInstruction(Record *R) : TheDef(R), Operands(R) { ImplicitUses = R->getValueAsListOfDefs("Uses"); if (neverHasSideEffects + hasSideEffects > 1) - throw R->getName() + ": multiple conflicting side-effect flags set!"; + PrintFatalError(R->getName() + ": multiple conflicting side-effect flags set!"); // Parse Constraints. ParseConstraints(R->getValueAsString("Constraints"), Operands); @@ -409,16 +414,16 @@ FlattenAsmStringVariants(StringRef Cur, unsigned Variant) { /// successful match, with ResOp set to the result operand to be used. bool CodeGenInstAlias::tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo, Record *InstOpRec, bool hasSubOps, - SMLoc Loc, CodeGenTarget &T, + ArrayRef<SMLoc> Loc, CodeGenTarget &T, ResultOperand &ResOp) { Init *Arg = Result->getArg(AliasOpNo); - DefInit *ADI = dynamic_cast<DefInit*>(Arg); + DefInit *ADI = dyn_cast<DefInit>(Arg); if (ADI && ADI->getDef() == InstOpRec) { // If the operand is a record, it must have a name, and the record type // must match up with the instruction's argument type. if (Result->getArgName(AliasOpNo).empty()) - throw TGError(Loc, "result argument #" + utostr(AliasOpNo) + + PrintFatalError(Loc, "result argument #" + utostr(AliasOpNo) + " must have a name!"); ResOp = ResultOperand(Result->getArgName(AliasOpNo), ADI->getDef()); return true; @@ -442,7 +447,7 @@ bool CodeGenInstAlias::tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo, DagInit *DI = InstOpRec->getValueAsDag("MIOperandInfo"); // The operand info should only have a single (register) entry. We // want the register class of it. - InstOpRec = dynamic_cast<DefInit*>(DI->getArg(0))->getDef(); + InstOpRec = cast<DefInit>(DI->getArg(0))->getDef(); } if (InstOpRec->isSubClassOf("RegisterOperand")) @@ -453,13 +458,13 @@ bool CodeGenInstAlias::tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo, if (!T.getRegisterClass(InstOpRec) .contains(T.getRegBank().getReg(ADI->getDef()))) - throw TGError(Loc, "fixed register " + ADI->getDef()->getName() + - " is not a member of the " + InstOpRec->getName() + - " register class!"); + PrintFatalError(Loc, "fixed register " + ADI->getDef()->getName() + + " is not a member of the " + InstOpRec->getName() + + " register class!"); if (!Result->getArgName(AliasOpNo).empty()) - throw TGError(Loc, "result fixed register argument must " - "not have a name!"); + PrintFatalError(Loc, "result fixed register argument must " + "not have a name!"); ResOp = ResultOperand(ADI->getDef()); return true; @@ -482,13 +487,13 @@ bool CodeGenInstAlias::tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo, } // Literal integers. - if (IntInit *II = dynamic_cast<IntInit*>(Arg)) { + if (IntInit *II = dyn_cast<IntInit>(Arg)) { if (hasSubOps || !InstOpRec->isSubClassOf("Operand")) return false; // Integer arguments can't have names. if (!Result->getArgName(AliasOpNo).empty()) - throw TGError(Loc, "result argument #" + utostr(AliasOpNo) + - " must not have a name!"); + PrintFatalError(Loc, "result argument #" + utostr(AliasOpNo) + + " must not have a name!"); ResOp = ResultOperand(II->getValue()); return true; } @@ -514,9 +519,10 @@ CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T) : TheDef(R) { Result = R->getValueAsDag("ResultInst"); // Verify that the root of the result is an instruction. - DefInit *DI = dynamic_cast<DefInit*>(Result->getOperator()); + DefInit *DI = dyn_cast<DefInit>(Result->getOperator()); if (DI == 0 || !DI->getDef()->isSubClassOf("Instruction")) - throw TGError(R->getLoc(), "result of inst alias should be an instruction"); + PrintFatalError(R->getLoc(), + "result of inst alias should be an instruction"); ResultInst = &T.getInstruction(DI->getDef()); @@ -524,7 +530,7 @@ CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T) : TheDef(R) { // the same class. StringMap<Record*> NameClass; for (unsigned i = 0, e = Result->getNumArgs(); i != e; ++i) { - DefInit *ADI = dynamic_cast<DefInit*>(Result->getArg(i)); + DefInit *ADI = dyn_cast<DefInit>(Result->getArg(i)); if (!ADI || Result->getArgName(i).empty()) continue; // Verify we don't have something like: (someinst GR16:$foo, GR32:$foo) @@ -532,9 +538,9 @@ CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T) : TheDef(R) { // same type. Record *&Entry = NameClass[Result->getArgName(i)]; if (Entry && Entry != ADI->getDef()) - throw TGError(R->getLoc(), "result value $" + Result->getArgName(i) + - " is both " + Entry->getName() + " and " + - ADI->getDef()->getName() + "!"); + PrintFatalError(R->getLoc(), "result value $" + Result->getArgName(i) + + " is both " + Entry->getName() + " and " + + ADI->getDef()->getName() + "!"); Entry = ADI->getDef(); } @@ -550,7 +556,7 @@ CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T) : TheDef(R) { continue; if (AliasOpNo >= Result->getNumArgs()) - throw TGError(R->getLoc(), "not enough arguments for instruction!"); + PrintFatalError(R->getLoc(), "not enough arguments for instruction!"); Record *InstOpRec = ResultInst->Operands[i].Rec; unsigned NumSubOps = ResultInst->Operands[i].MINumOperands; @@ -571,7 +577,7 @@ CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T) : TheDef(R) { } else { DagInit *MIOI = ResultInst->Operands[i].MIOperandInfo; for (unsigned SubOp = 0; SubOp != NumSubOps; ++SubOp) { - Record *SubRec = dynamic_cast<DefInit*>(MIOI->getArg(SubOp))->getDef(); + Record *SubRec = cast<DefInit>(MIOI->getArg(SubOp))->getDef(); // Take care to instantiate each of the suboperands with the correct // nomenclature: $foo.bar @@ -591,26 +597,26 @@ CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T) : TheDef(R) { DagInit *MIOI = ResultInst->Operands[i].MIOperandInfo; for (unsigned SubOp = 0; SubOp != NumSubOps; ++SubOp) { if (AliasOpNo >= Result->getNumArgs()) - throw TGError(R->getLoc(), "not enough arguments for instruction!"); - Record *SubRec = dynamic_cast<DefInit*>(MIOI->getArg(SubOp))->getDef(); + PrintFatalError(R->getLoc(), "not enough arguments for instruction!"); + Record *SubRec = cast<DefInit>(MIOI->getArg(SubOp))->getDef(); if (tryAliasOpMatch(Result, AliasOpNo, SubRec, false, R->getLoc(), T, ResOp)) { ResultOperands.push_back(ResOp); ResultInstOperandIndex.push_back(std::make_pair(i, SubOp)); ++AliasOpNo; } else { - throw TGError(R->getLoc(), "result argument #" + utostr(AliasOpNo) + + PrintFatalError(R->getLoc(), "result argument #" + utostr(AliasOpNo) + " does not match instruction operand class " + (SubOp == 0 ? InstOpRec->getName() :SubRec->getName())); } } continue; } - throw TGError(R->getLoc(), "result argument #" + utostr(AliasOpNo) + - " does not match instruction operand class " + - InstOpRec->getName()); + PrintFatalError(R->getLoc(), "result argument #" + utostr(AliasOpNo) + + " does not match instruction operand class " + + InstOpRec->getName()); } if (AliasOpNo != Result->getNumArgs()) - throw TGError(R->getLoc(), "too many operands for instruction!"); + PrintFatalError(R->getLoc(), "too many operands for instruction!"); } diff --git a/contrib/llvm/utils/TableGen/CodeGenInstruction.h b/contrib/llvm/utils/TableGen/CodeGenInstruction.h index 95b572d..55d4439 100644 --- a/contrib/llvm/utils/TableGen/CodeGenInstruction.h +++ b/contrib/llvm/utils/TableGen/CodeGenInstruction.h @@ -152,7 +152,7 @@ namespace llvm { /// getOperandNamed - Return the index of the operand with the specified /// non-empty name. If the instruction does not have an operand with the - /// specified name, throw an exception. + /// specified name, abort. unsigned getOperandNamed(StringRef Name) const; /// hasOperandNamed - Query whether the instruction has an operand of the @@ -162,9 +162,8 @@ namespace llvm { /// ParseOperandName - Parse an operand name like "$foo" or "$foo.bar", /// where $foo is a whole operand and $foo.bar refers to a suboperand. - /// This throws an exception if the name is invalid. If AllowWholeOp is - /// true, references to operands with suboperands are allowed, otherwise - /// not. + /// This aborts if the name is invalid. If AllowWholeOp is true, references + /// to operands with suboperands are allowed, otherwise not. std::pair<unsigned,unsigned> ParseOperandName(const std::string &Op, bool AllowWholeOp = true); @@ -226,7 +225,10 @@ namespace llvm { bool isBarrier; bool isCall; bool canFoldAsLoad; - bool mayLoad, mayStore; + bool mayLoad; + bool mayLoad_Unset; + bool mayStore; + bool mayStore_Unset; bool isPredicable; bool isConvertibleToThreeAddress; bool isCommutable; @@ -238,6 +240,7 @@ namespace llvm { bool hasCtrlDep; bool isNotDuplicable; bool hasSideEffects; + bool hasSideEffects_Unset; bool neverHasSideEffects; bool isAsCheapAsAMove; bool hasExtraSrcRegAllocReq; @@ -245,6 +248,14 @@ namespace llvm { bool isCodeGenOnly; bool isPseudo; + /// Are there any undefined flags? + bool hasUndefFlags() const { + return mayLoad_Unset || mayStore_Unset || hasSideEffects_Unset; + } + + // The record used to infer instruction flags, or NULL if no flag values + // have been inferred. + Record *InferredFrom; CodeGenInstruction(Record *R); @@ -319,7 +330,7 @@ namespace llvm { CodeGenInstAlias(Record *R, CodeGenTarget &T); bool tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo, - Record *InstOpRec, bool hasSubOps, SMLoc Loc, + Record *InstOpRec, bool hasSubOps, ArrayRef<SMLoc> Loc, CodeGenTarget &T, ResultOperand &ResOp); }; } diff --git a/contrib/llvm/utils/TableGen/CodeGenMapTable.cpp b/contrib/llvm/utils/TableGen/CodeGenMapTable.cpp new file mode 100644 index 0000000..1653d67 --- /dev/null +++ b/contrib/llvm/utils/TableGen/CodeGenMapTable.cpp @@ -0,0 +1,606 @@ +//===- CodeGenMapTable.cpp - Instruction Mapping Table Generator ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// CodeGenMapTable provides functionality for the TabelGen to create +// relation mapping between instructions. Relation models are defined using +// InstrMapping as a base class. This file implements the functionality which +// parses these definitions and generates relation maps using the information +// specified there. These maps are emitted as tables in the XXXGenInstrInfo.inc +// file along with the functions to query them. +// +// A relationship model to relate non-predicate instructions with their +// predicated true/false forms can be defined as follows: +// +// def getPredOpcode : InstrMapping { +// let FilterClass = "PredRel"; +// let RowFields = ["BaseOpcode"]; +// let ColFields = ["PredSense"]; +// let KeyCol = ["none"]; +// let ValueCols = [["true"], ["false"]]; } +// +// CodeGenMapTable parses this map and generates a table in XXXGenInstrInfo.inc +// file that contains the instructions modeling this relationship. This table +// is defined in the function +// "int getPredOpcode(uint16_t Opcode, enum PredSense inPredSense)" +// that can be used to retrieve the predicated form of the instruction by +// passing its opcode value and the predicate sense (true/false) of the desired +// instruction as arguments. +// +// Short description of the algorithm: +// +// 1) Iterate through all the records that derive from "InstrMapping" class. +// 2) For each record, filter out instructions based on the FilterClass value. +// 3) Iterate through this set of instructions and insert them into +// RowInstrMap map based on their RowFields values. RowInstrMap is keyed by the +// vector of RowFields values and contains vectors of Records (instructions) as +// values. RowFields is a list of fields that are required to have the same +// values for all the instructions appearing in the same row of the relation +// table. All the instructions in a given row of the relation table have some +// sort of relationship with the key instruction defined by the corresponding +// relationship model. +// +// Ex: RowInstrMap(RowVal1, RowVal2, ...) -> [Instr1, Instr2, Instr3, ... ] +// Here Instr1, Instr2, Instr3 have same values (RowVal1, RowVal2) for +// RowFields. These groups of instructions are later matched against ValueCols +// to determine the column they belong to, if any. +// +// While building the RowInstrMap map, collect all the key instructions in +// KeyInstrVec. These are the instructions having the same values as KeyCol +// for all the fields listed in ColFields. +// +// For Example: +// +// Relate non-predicate instructions with their predicated true/false forms. +// +// def getPredOpcode : InstrMapping { +// let FilterClass = "PredRel"; +// let RowFields = ["BaseOpcode"]; +// let ColFields = ["PredSense"]; +// let KeyCol = ["none"]; +// let ValueCols = [["true"], ["false"]]; } +// +// Here, only instructions that have "none" as PredSense will be selected as key +// instructions. +// +// 4) For each key instruction, get the group of instructions that share the +// same key-value as the key instruction from RowInstrMap. Iterate over the list +// of columns in ValueCols (it is defined as a list<list<string> >. Therefore, +// it can specify multi-column relationships). For each column, find the +// instruction from the group that matches all the values for the column. +// Multiple matches are not allowed. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenTarget.h" +#include "llvm/Support/Format.h" +#include "llvm/TableGen/Error.h" +using namespace llvm; +typedef std::map<std::string, std::vector<Record*> > InstrRelMapTy; + +typedef std::map<std::vector<Init*>, std::vector<Record*> > RowInstrMapTy; + +namespace { + +//===----------------------------------------------------------------------===// +// This class is used to represent InstrMapping class defined in Target.td file. +class InstrMap { +private: + std::string Name; + std::string FilterClass; + ListInit *RowFields; + ListInit *ColFields; + ListInit *KeyCol; + std::vector<ListInit*> ValueCols; + +public: + InstrMap(Record* MapRec) { + Name = MapRec->getName(); + + // FilterClass - It's used to reduce the search space only to the + // instructions that define the kind of relationship modeled by + // this InstrMapping object/record. + const RecordVal *Filter = MapRec->getValue("FilterClass"); + FilterClass = Filter->getValue()->getAsUnquotedString(); + + // List of fields/attributes that need to be same across all the + // instructions in a row of the relation table. + RowFields = MapRec->getValueAsListInit("RowFields"); + + // List of fields/attributes that are constant across all the instruction + // in a column of the relation table. Ex: ColFields = 'predSense' + ColFields = MapRec->getValueAsListInit("ColFields"); + + // Values for the fields/attributes listed in 'ColFields'. + // Ex: KeyCol = 'noPred' -- key instruction is non predicated + KeyCol = MapRec->getValueAsListInit("KeyCol"); + + // List of values for the fields/attributes listed in 'ColFields', one for + // each column in the relation table. + // + // Ex: ValueCols = [['true'],['false']] -- it results two columns in the + // table. First column requires all the instructions to have predSense + // set to 'true' and second column requires it to be 'false'. + ListInit *ColValList = MapRec->getValueAsListInit("ValueCols"); + + // Each instruction map must specify at least one column for it to be valid. + if (ColValList->getSize() == 0) + PrintFatalError(MapRec->getLoc(), "InstrMapping record `" + + MapRec->getName() + "' has empty " + "`ValueCols' field!"); + + for (unsigned i = 0, e = ColValList->getSize(); i < e; i++) { + ListInit *ColI = dyn_cast<ListInit>(ColValList->getElement(i)); + + // Make sure that all the sub-lists in 'ValueCols' have same number of + // elements as the fields in 'ColFields'. + if (ColI->getSize() != ColFields->getSize()) + PrintFatalError(MapRec->getLoc(), "Record `" + MapRec->getName() + + "', field `ValueCols' entries don't match with " + + " the entries in 'ColFields'!"); + ValueCols.push_back(ColI); + } + } + + std::string getName() const { + return Name; + } + + std::string getFilterClass() { + return FilterClass; + } + + ListInit *getRowFields() const { + return RowFields; + } + + ListInit *getColFields() const { + return ColFields; + } + + ListInit *getKeyCol() const { + return KeyCol; + } + + const std::vector<ListInit*> &getValueCols() const { + return ValueCols; + } +}; +} // End anonymous namespace. + + +//===----------------------------------------------------------------------===// +// class MapTableEmitter : It builds the instruction relation maps using +// the information provided in InstrMapping records. It outputs these +// relationship maps as tables into XXXGenInstrInfo.inc file along with the +// functions to query them. + +namespace { +class MapTableEmitter { +private: +// std::string TargetName; + const CodeGenTarget &Target; + // InstrMapDesc - InstrMapping record to be processed. + InstrMap InstrMapDesc; + + // InstrDefs - list of instructions filtered using FilterClass defined + // in InstrMapDesc. + std::vector<Record*> InstrDefs; + + // RowInstrMap - maps RowFields values to the instructions. It's keyed by the + // values of the row fields and contains vector of records as values. + RowInstrMapTy RowInstrMap; + + // KeyInstrVec - list of key instructions. + std::vector<Record*> KeyInstrVec; + DenseMap<Record*, std::vector<Record*> > MapTable; + +public: + MapTableEmitter(CodeGenTarget &Target, RecordKeeper &Records, Record *IMRec): + Target(Target), InstrMapDesc(IMRec) { + const std::string FilterClass = InstrMapDesc.getFilterClass(); + InstrDefs = Records.getAllDerivedDefinitions(FilterClass); + } + + void buildRowInstrMap(); + + // Returns true if an instruction is a key instruction, i.e., its ColFields + // have same values as KeyCol. + bool isKeyColInstr(Record* CurInstr); + + // Find column instruction corresponding to a key instruction based on the + // constraints for that column. + Record *getInstrForColumn(Record *KeyInstr, ListInit *CurValueCol); + + // Find column instructions for each key instruction based + // on ValueCols and store them into MapTable. + void buildMapTable(); + + void emitBinSearch(raw_ostream &OS, unsigned TableSize); + void emitTablesWithFunc(raw_ostream &OS); + unsigned emitBinSearchTable(raw_ostream &OS); + + // Lookup functions to query binary search tables. + void emitMapFuncBody(raw_ostream &OS, unsigned TableSize); + +}; +} // End anonymous namespace. + + +//===----------------------------------------------------------------------===// +// Process all the instructions that model this relation (alreday present in +// InstrDefs) and insert them into RowInstrMap which is keyed by the values of +// the fields listed as RowFields. It stores vectors of records as values. +// All the related instructions have the same values for the RowFields thus are +// part of the same key-value pair. +//===----------------------------------------------------------------------===// + +void MapTableEmitter::buildRowInstrMap() { + for (unsigned i = 0, e = InstrDefs.size(); i < e; i++) { + std::vector<Record*> InstrList; + Record *CurInstr = InstrDefs[i]; + std::vector<Init*> KeyValue; + ListInit *RowFields = InstrMapDesc.getRowFields(); + for (unsigned j = 0, endRF = RowFields->getSize(); j < endRF; j++) { + Init *RowFieldsJ = RowFields->getElement(j); + Init *CurInstrVal = CurInstr->getValue(RowFieldsJ)->getValue(); + KeyValue.push_back(CurInstrVal); + } + + // Collect key instructions into KeyInstrVec. Later, these instructions are + // processed to assign column position to the instructions sharing + // their KeyValue in RowInstrMap. + if (isKeyColInstr(CurInstr)) + KeyInstrVec.push_back(CurInstr); + + RowInstrMap[KeyValue].push_back(CurInstr); + } +} + +//===----------------------------------------------------------------------===// +// Return true if an instruction is a KeyCol instruction. +//===----------------------------------------------------------------------===// + +bool MapTableEmitter::isKeyColInstr(Record* CurInstr) { + ListInit *ColFields = InstrMapDesc.getColFields(); + ListInit *KeyCol = InstrMapDesc.getKeyCol(); + + // Check if the instruction is a KeyCol instruction. + bool MatchFound = true; + for (unsigned j = 0, endCF = ColFields->getSize(); + (j < endCF) && MatchFound; j++) { + RecordVal *ColFieldName = CurInstr->getValue(ColFields->getElement(j)); + std::string CurInstrVal = ColFieldName->getValue()->getAsUnquotedString(); + std::string KeyColValue = KeyCol->getElement(j)->getAsUnquotedString(); + MatchFound = (CurInstrVal == KeyColValue); + } + return MatchFound; +} + +//===----------------------------------------------------------------------===// +// Build a map to link key instructions with the column instructions arranged +// according to their column positions. +//===----------------------------------------------------------------------===// + +void MapTableEmitter::buildMapTable() { + // Find column instructions for a given key based on the ColField + // constraints. + const std::vector<ListInit*> &ValueCols = InstrMapDesc.getValueCols(); + unsigned NumOfCols = ValueCols.size(); + for (unsigned j = 0, endKI = KeyInstrVec.size(); j < endKI; j++) { + Record *CurKeyInstr = KeyInstrVec[j]; + std::vector<Record*> ColInstrVec(NumOfCols); + + // Find the column instruction based on the constraints for the column. + for (unsigned ColIdx = 0; ColIdx < NumOfCols; ColIdx++) { + ListInit *CurValueCol = ValueCols[ColIdx]; + Record *ColInstr = getInstrForColumn(CurKeyInstr, CurValueCol); + ColInstrVec[ColIdx] = ColInstr; + } + MapTable[CurKeyInstr] = ColInstrVec; + } +} + +//===----------------------------------------------------------------------===// +// Find column instruction based on the constraints for that column. +//===----------------------------------------------------------------------===// + +Record *MapTableEmitter::getInstrForColumn(Record *KeyInstr, + ListInit *CurValueCol) { + ListInit *RowFields = InstrMapDesc.getRowFields(); + std::vector<Init*> KeyValue; + + // Construct KeyValue using KeyInstr's values for RowFields. + for (unsigned j = 0, endRF = RowFields->getSize(); j < endRF; j++) { + Init *RowFieldsJ = RowFields->getElement(j); + Init *KeyInstrVal = KeyInstr->getValue(RowFieldsJ)->getValue(); + KeyValue.push_back(KeyInstrVal); + } + + // Get all the instructions that share the same KeyValue as the KeyInstr + // in RowInstrMap. We search through these instructions to find a match + // for the current column, i.e., the instruction which has the same values + // as CurValueCol for all the fields in ColFields. + const std::vector<Record*> &RelatedInstrVec = RowInstrMap[KeyValue]; + + ListInit *ColFields = InstrMapDesc.getColFields(); + Record *MatchInstr = NULL; + + for (unsigned i = 0, e = RelatedInstrVec.size(); i < e; i++) { + bool MatchFound = true; + Record *CurInstr = RelatedInstrVec[i]; + for (unsigned j = 0, endCF = ColFields->getSize(); + (j < endCF) && MatchFound; j++) { + Init *ColFieldJ = ColFields->getElement(j); + Init *CurInstrInit = CurInstr->getValue(ColFieldJ)->getValue(); + std::string CurInstrVal = CurInstrInit->getAsUnquotedString(); + Init *ColFieldJVallue = CurValueCol->getElement(j); + MatchFound = (CurInstrVal == ColFieldJVallue->getAsUnquotedString()); + } + + if (MatchFound) { + if (MatchInstr) // Already had a match + // Error if multiple matches are found for a column. + PrintFatalError("Multiple matches found for `" + KeyInstr->getName() + + "', for the relation `" + InstrMapDesc.getName()); + MatchInstr = CurInstr; + } + } + return MatchInstr; +} + +//===----------------------------------------------------------------------===// +// Emit one table per relation. Only instructions with a valid relation of a +// given type are included in the table sorted by their enum values (opcodes). +// Binary search is used for locating instructions in the table. +//===----------------------------------------------------------------------===// + +unsigned MapTableEmitter::emitBinSearchTable(raw_ostream &OS) { + + const std::vector<const CodeGenInstruction*> &NumberedInstructions = + Target.getInstructionsByEnumValue(); + std::string TargetName = Target.getName(); + const std::vector<ListInit*> &ValueCols = InstrMapDesc.getValueCols(); + unsigned NumCol = ValueCols.size(); + unsigned TotalNumInstr = NumberedInstructions.size(); + unsigned TableSize = 0; + + OS << "static const uint16_t "<<InstrMapDesc.getName(); + // Number of columns in the table are NumCol+1 because key instructions are + // emitted as first column. + OS << "Table[]["<< NumCol+1 << "] = {\n"; + for (unsigned i = 0; i < TotalNumInstr; i++) { + Record *CurInstr = NumberedInstructions[i]->TheDef; + std::vector<Record*> ColInstrs = MapTable[CurInstr]; + std::string OutStr(""); + unsigned RelExists = 0; + if (ColInstrs.size()) { + for (unsigned j = 0; j < NumCol; j++) { + if (ColInstrs[j] != NULL) { + RelExists = 1; + OutStr += ", "; + OutStr += TargetName; + OutStr += "::"; + OutStr += ColInstrs[j]->getName(); + } else { OutStr += ", -1";} + } + + if (RelExists) { + OS << " { " << TargetName << "::" << CurInstr->getName(); + OS << OutStr <<" },\n"; + TableSize++; + } + } + } + if (!TableSize) { + OS << " { " << TargetName << "::" << "INSTRUCTION_LIST_END, "; + OS << TargetName << "::" << "INSTRUCTION_LIST_END }"; + } + OS << "}; // End of " << InstrMapDesc.getName() << "Table\n\n"; + return TableSize; +} + +//===----------------------------------------------------------------------===// +// Emit binary search algorithm as part of the functions used to query +// relation tables. +//===----------------------------------------------------------------------===// + +void MapTableEmitter::emitBinSearch(raw_ostream &OS, unsigned TableSize) { + OS << " unsigned mid;\n"; + OS << " unsigned start = 0;\n"; + OS << " unsigned end = " << TableSize << ";\n"; + OS << " while (start < end) {\n"; + OS << " mid = start + (end - start)/2;\n"; + OS << " if (Opcode == " << InstrMapDesc.getName() << "Table[mid][0]) {\n"; + OS << " break;\n"; + OS << " }\n"; + OS << " if (Opcode < " << InstrMapDesc.getName() << "Table[mid][0])\n"; + OS << " end = mid;\n"; + OS << " else\n"; + OS << " start = mid + 1;\n"; + OS << " }\n"; + OS << " if (start == end)\n"; + OS << " return -1; // Instruction doesn't exist in this table.\n\n"; +} + +//===----------------------------------------------------------------------===// +// Emit functions to query relation tables. +//===----------------------------------------------------------------------===// + +void MapTableEmitter::emitMapFuncBody(raw_ostream &OS, + unsigned TableSize) { + + ListInit *ColFields = InstrMapDesc.getColFields(); + const std::vector<ListInit*> &ValueCols = InstrMapDesc.getValueCols(); + + // Emit binary search algorithm to locate instructions in the + // relation table. If found, return opcode value from the appropriate column + // of the table. + emitBinSearch(OS, TableSize); + + if (ValueCols.size() > 1) { + for (unsigned i = 0, e = ValueCols.size(); i < e; i++) { + ListInit *ColumnI = ValueCols[i]; + for (unsigned j = 0, ColSize = ColumnI->getSize(); j < ColSize; j++) { + std::string ColName = ColFields->getElement(j)->getAsUnquotedString(); + OS << " if (in" << ColName; + OS << " == "; + OS << ColName << "_" << ColumnI->getElement(j)->getAsUnquotedString(); + if (j < ColumnI->getSize() - 1) OS << " && "; + else OS << ")\n"; + } + OS << " return " << InstrMapDesc.getName(); + OS << "Table[mid]["<<i+1<<"];\n"; + } + OS << " return -1;"; + } + else + OS << " return " << InstrMapDesc.getName() << "Table[mid][1];\n"; + + OS <<"}\n\n"; +} + +//===----------------------------------------------------------------------===// +// Emit relation tables and the functions to query them. +//===----------------------------------------------------------------------===// + +void MapTableEmitter::emitTablesWithFunc(raw_ostream &OS) { + + // Emit function name and the input parameters : mostly opcode value of the + // current instruction. However, if a table has multiple columns (more than 2 + // since first column is used for the key instructions), then we also need + // to pass another input to indicate the column to be selected. + + ListInit *ColFields = InstrMapDesc.getColFields(); + const std::vector<ListInit*> &ValueCols = InstrMapDesc.getValueCols(); + OS << "// "<< InstrMapDesc.getName() << "\n"; + OS << "int "<< InstrMapDesc.getName() << "(uint16_t Opcode"; + if (ValueCols.size() > 1) { + for (unsigned i = 0, e = ColFields->getSize(); i < e; i++) { + std::string ColName = ColFields->getElement(i)->getAsUnquotedString(); + OS << ", enum " << ColName << " in" << ColName << ") {\n"; + } + } else { OS << ") {\n"; } + + // Emit map table. + unsigned TableSize = emitBinSearchTable(OS); + + // Emit rest of the function body. + emitMapFuncBody(OS, TableSize); +} + +//===----------------------------------------------------------------------===// +// Emit enums for the column fields across all the instruction maps. +//===----------------------------------------------------------------------===// + +static void emitEnums(raw_ostream &OS, RecordKeeper &Records) { + + std::vector<Record*> InstrMapVec; + InstrMapVec = Records.getAllDerivedDefinitions("InstrMapping"); + std::map<std::string, std::vector<Init*> > ColFieldValueMap; + + // Iterate over all InstrMapping records and create a map between column + // fields and their possible values across all records. + for (unsigned i = 0, e = InstrMapVec.size(); i < e; i++) { + Record *CurMap = InstrMapVec[i]; + ListInit *ColFields; + ColFields = CurMap->getValueAsListInit("ColFields"); + ListInit *List = CurMap->getValueAsListInit("ValueCols"); + std::vector<ListInit*> ValueCols; + unsigned ListSize = List->getSize(); + + for (unsigned j = 0; j < ListSize; j++) { + ListInit *ListJ = dyn_cast<ListInit>(List->getElement(j)); + + if (ListJ->getSize() != ColFields->getSize()) + PrintFatalError("Record `" + CurMap->getName() + "', field " + "`ValueCols' entries don't match with the entries in 'ColFields' !"); + ValueCols.push_back(ListJ); + } + + for (unsigned j = 0, endCF = ColFields->getSize(); j < endCF; j++) { + for (unsigned k = 0; k < ListSize; k++){ + std::string ColName = ColFields->getElement(j)->getAsUnquotedString(); + ColFieldValueMap[ColName].push_back((ValueCols[k])->getElement(j)); + } + } + } + + for (std::map<std::string, std::vector<Init*> >::iterator + II = ColFieldValueMap.begin(), IE = ColFieldValueMap.end(); + II != IE; II++) { + std::vector<Init*> FieldValues = (*II).second; + unsigned FieldSize = FieldValues.size(); + + // Delete duplicate entries from ColFieldValueMap + for (unsigned i = 0; i < FieldSize - 1; i++) { + Init *CurVal = FieldValues[i]; + for (unsigned j = i+1; j < FieldSize; j++) { + if (CurVal == FieldValues[j]) { + FieldValues.erase(FieldValues.begin()+j); + } + } + } + + // Emit enumerated values for the column fields. + OS << "enum " << (*II).first << " {\n"; + for (unsigned i = 0; i < FieldSize; i++) { + OS << "\t" << (*II).first << "_" << FieldValues[i]->getAsUnquotedString(); + if (i != FieldValues.size() - 1) + OS << ",\n"; + else + OS << "\n};\n\n"; + } + } +} + +namespace llvm { +//===----------------------------------------------------------------------===// +// Parse 'InstrMapping' records and use the information to form relationship +// between instructions. These relations are emitted as a tables along with the +// functions to query them. +//===----------------------------------------------------------------------===// +void EmitMapTable(RecordKeeper &Records, raw_ostream &OS) { + CodeGenTarget Target(Records); + std::string TargetName = Target.getName(); + std::vector<Record*> InstrMapVec; + InstrMapVec = Records.getAllDerivedDefinitions("InstrMapping"); + + if (!InstrMapVec.size()) + return; + + OS << "#ifdef GET_INSTRMAP_INFO\n"; + OS << "#undef GET_INSTRMAP_INFO\n"; + OS << "namespace llvm {\n\n"; + OS << "namespace " << TargetName << " {\n\n"; + + // Emit coulumn field names and their values as enums. + emitEnums(OS, Records); + + // Iterate over all instruction mapping records and construct relationship + // maps based on the information specified there. + // + for (unsigned i = 0, e = InstrMapVec.size(); i < e; i++) { + MapTableEmitter IMap(Target, Records, InstrMapVec[i]); + + // Build RowInstrMap to group instructions based on their values for + // RowFields. In the process, also collect key instructions into + // KeyInstrVec. + IMap.buildRowInstrMap(); + + // Build MapTable to map key instructions with the corresponding column + // instructions. + IMap.buildMapTable(); + + // Emit map tables and the functions to query them. + IMap.emitTablesWithFunc(OS); + } + OS << "} // End " << TargetName << " namespace\n"; + OS << "} // End llvm namespace\n"; + OS << "#endif // GET_INSTRMAP_INFO\n\n"; +} + +} // End llvm namespace diff --git a/contrib/llvm/utils/TableGen/CodeGenRegisters.cpp b/contrib/llvm/utils/TableGen/CodeGenRegisters.cpp index 011f4b7..580e319 100644 --- a/contrib/llvm/utils/TableGen/CodeGenRegisters.cpp +++ b/contrib/llvm/utils/TableGen/CodeGenRegisters.cpp @@ -28,7 +28,7 @@ using namespace llvm; //===----------------------------------------------------------------------===// CodeGenSubRegIndex::CodeGenSubRegIndex(Record *R, unsigned Enum) - : TheDef(R), EnumValue(Enum) { + : TheDef(R), EnumValue(Enum), LaneMask(0) { Name = R->getName(); if (R->getValue("Namespace")) Namespace = R->getValueAsString("Namespace"); @@ -36,7 +36,7 @@ CodeGenSubRegIndex::CodeGenSubRegIndex(Record *R, unsigned Enum) CodeGenSubRegIndex::CodeGenSubRegIndex(StringRef N, StringRef Nspace, unsigned Enum) - : TheDef(0), Name(N), Namespace(Nspace), EnumValue(Enum) { + : TheDef(0), Name(N), Namespace(Nspace), EnumValue(Enum), LaneMask(0) { } std::string CodeGenSubRegIndex::getQualifiedName() const { @@ -54,19 +54,20 @@ void CodeGenSubRegIndex::updateComponents(CodeGenRegBank &RegBank) { std::vector<Record*> Comps = TheDef->getValueAsListOfDefs("ComposedOf"); if (!Comps.empty()) { if (Comps.size() != 2) - throw TGError(TheDef->getLoc(), "ComposedOf must have exactly two entries"); + PrintFatalError(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"); + PrintFatalError(TheDef->getLoc(), "Ambiguous ComposedOf entries"); } std::vector<Record*> Parts = TheDef->getValueAsListOfDefs("CoveringSubRegIndices"); if (!Parts.empty()) { if (Parts.size() < 2) - throw TGError(TheDef->getLoc(), + PrintFatalError(TheDef->getLoc(), "CoveredBySubRegs must have two or more entries"); SmallVector<CodeGenSubRegIndex*, 8> IdxParts; for (unsigned i = 0, e = Parts.size(); i != e; ++i) @@ -75,14 +76,21 @@ void CodeGenSubRegIndex::updateComponents(CodeGenRegBank &RegBank) { } } -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); - } +unsigned CodeGenSubRegIndex::computeLaneMask() { + // Already computed? + if (LaneMask) + return LaneMask; + + // Recursion guard, shouldn't be required. + LaneMask = ~0u; + + // The lane mask is simply the union of all sub-indices. + unsigned M = 0; + for (CompMap::iterator I = Composed.begin(), E = Composed.end(); I != E; ++I) + M |= I->second->computeLaneMask(); + assert(M && "Missing lane mask, sub-register cycle?"); + LaneMask = M; + return LaneMask; } //===----------------------------------------------------------------------===// @@ -105,8 +113,8 @@ void CodeGenRegister::buildObjectGraph(CodeGenRegBank &RegBank) { std::vector<Record*> SRs = TheDef->getValueAsListOfDefs("SubRegs"); if (SRIs.size() != SRs.size()) - throw TGError(TheDef->getLoc(), - "SubRegs and SubRegIndices must have the same size"); + PrintFatalError(TheDef->getLoc(), + "SubRegs and SubRegIndices must have the same size"); for (unsigned i = 0, e = SRIs.size(); i != e; ++i) { ExplicitSubRegIndices.push_back(RegBank.getSubRegIdx(SRIs[i])); @@ -217,8 +225,8 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) { CodeGenRegister *SR = ExplicitSubRegs[i]; CodeGenSubRegIndex *Idx = ExplicitSubRegIndices[i]; if (!SubRegs.insert(std::make_pair(Idx, SR)).second) - throw TGError(TheDef->getLoc(), "SubRegIndex " + Idx->getName() + - " appears twice in Register " + getName()); + PrintFatalError(TheDef->getLoc(), "SubRegIndex " + Idx->getName() + + " appears twice in Register " + getName()); // Map explicit sub-registers first, so the names take precedence. // The inherited sub-registers are mapped below. SubReg2Idx.insert(std::make_pair(SR, Idx)); @@ -298,11 +306,11 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) { for (SubRegMap::const_iterator SI = SubRegs.begin(), SE = SubRegs.end(); SI != SE; ++SI) { if (SI->second == this) { - SMLoc Loc; + ArrayRef<SMLoc> Loc; if (TheDef) Loc = TheDef->getLoc(); - throw TGError(Loc, "Register " + getName() + - " has itself as a sub-register"); + PrintFatalError(Loc, "Register " + getName() + + " has itself as a sub-register"); } // Ensure that every sub-register has a unique name. DenseMap<const CodeGenRegister*, CodeGenSubRegIndex*>::iterator Ins = @@ -310,10 +318,10 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) { if (Ins->second == SI->first) continue; // Trouble: Two different names for SI->second. - SMLoc Loc; + ArrayRef<SMLoc> Loc; if (TheDef) Loc = TheDef->getLoc(); - throw TGError(Loc, "Sub-register can't have two names: " + + PrintFatalError(Loc, "Sub-register can't have two names: " + SI->second->getName() + " available as " + SI->first->getName() + " and " + Ins->second->getName()); } @@ -460,8 +468,8 @@ void CodeGenRegister::computeSecondarySubRegs(CodeGenRegBank &RegBank) { SE = NewSubReg->SubRegs.end(); SI != SE; ++SI) { CodeGenSubRegIndex *SubIdx = getSubRegIndex(SI->second); if (!SubIdx) - throw TGError(TheDef->getLoc(), "No SubRegIndex for " + - SI->second->getName() + " in " + getName()); + PrintFatalError(TheDef->getLoc(), "No SubRegIndex for " + + SI->second->getName() + " in " + getName()); NewIdx->addComposite(SI->first, SubIdx); } } @@ -585,15 +593,16 @@ struct TupleExpander : SetTheory::Expander { unsigned Dim = Indices.size(); ListInit *SubRegs = Def->getValueAsListInit("SubRegs"); if (Dim != SubRegs->getSize()) - throw TGError(Def->getLoc(), "SubRegIndices and SubRegs size mismatch"); + PrintFatalError(Def->getLoc(), "SubRegIndices and SubRegs size mismatch"); if (Dim < 2) - throw TGError(Def->getLoc(), "Tuples must have at least 2 sub-registers"); + PrintFatalError(Def->getLoc(), + "Tuples must have at least 2 sub-registers"); // Evaluate the sub-register lists to be zipped. unsigned Length = ~0u; SmallVector<SetTheory::RecSet, 4> Lists(Dim); for (unsigned i = 0; i != Dim; ++i) { - ST.evaluate(SubRegs->getElement(i), Lists[i]); + ST.evaluate(SubRegs->getElement(i), Lists[i], Def->getLoc()); Length = std::min(Length, unsigned(Lists[i].size())); } @@ -699,8 +708,8 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R) for (unsigned i = 0, e = TypeList.size(); i != e; ++i) { Record *Type = TypeList[i]; if (!Type->isSubClassOf("ValueType")) - throw "RegTypes list member '" + Type->getName() + - "' does not derive from the ValueType class!"; + PrintFatalError("RegTypes list member '" + Type->getName() + + "' does not derive from the ValueType class!"); VTs.push_back(getValueType(Type)); } assert(!VTs.empty() && "RegisterClass must contain at least one ValueType!"); @@ -721,14 +730,14 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R) // Alternative allocation orders may be subsets. SetTheory::RecSet Order; for (unsigned i = 0, e = AltOrders->size(); i != e; ++i) { - RegBank.getSets().evaluate(AltOrders->getElement(i), Order); + RegBank.getSets().evaluate(AltOrders->getElement(i), Order, R->getLoc()); Orders[1 + i].append(Order.begin(), Order.end()); // Verify that all altorder members are regclass members. while (!Order.empty()) { CodeGenRegister *Reg = RegBank.getReg(Order.back()); Order.pop_back(); if (!contains(Reg)) - throw TGError(R->getLoc(), " AltOrder register " + Reg->getName() + + PrintFatalError(R->getLoc(), " AltOrder register " + Reg->getName() + " is not a class member"); } } @@ -986,6 +995,12 @@ CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records) { for (unsigned i = 0, e = Registers.size(); i != e; ++i) Registers[i]->buildObjectGraph(*this); + // Compute register name map. + for (unsigned i = 0, e = Registers.size(); i != e; ++i) + RegistersByName.GetOrCreateValue( + Registers[i]->TheDef->getValueAsString("AsmName"), + Registers[i]); + // Precompute all sub-register maps. // This will create Composite entries for all inferred sub-register indices. for (unsigned i = 0, e = Registers.size(); i != e; ++i) @@ -1008,7 +1023,7 @@ CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records) { // Read in register class definitions. std::vector<Record*> RCs = Records.getAllDerivedDefinitions("RegisterClass"); if (RCs.empty()) - throw std::string("No 'RegisterClass' subclasses defined!"); + PrintFatalError(std::string("No 'RegisterClass' subclasses defined!")); // Allocate user-defined register classes. RegClasses.reserve(RCs.size()); @@ -1085,7 +1100,7 @@ CodeGenRegisterClass *CodeGenRegBank::getRegClass(Record *Def) { if (CodeGenRegisterClass *RC = Def2RC[Def]) return RC; - throw TGError(Def->getLoc(), "Not a known RegisterClass!"); + PrintFatalError(Def->getLoc(), "Not a known RegisterClass!"); } CodeGenSubRegIndex* @@ -1164,11 +1179,35 @@ void CodeGenRegBank::computeComposites() { } } } +} + +// Compute lane masks. This is similar to register units, but at the +// sub-register index level. Each bit in the lane mask is like a register unit +// class, and two lane masks will have a bit in common if two sub-register +// indices overlap in some register. +// +// Conservatively share a lane mask bit if two sub-register indices overlap in +// some registers, but not in others. That shouldn't happen a lot. +void CodeGenRegBank::computeSubRegIndexLaneMasks() { + // First assign individual bits to all the leaf indices. + unsigned Bit = 0; + for (unsigned i = 0, e = SubRegIndices.size(); i != e; ++i) { + CodeGenSubRegIndex *Idx = SubRegIndices[i]; + if (Idx->getComposites().empty()) { + Idx->LaneMask = 1u << Bit; + // Share bit 31 in the unlikely case there are more than 32 leafs. + if (Bit < 31) ++Bit; + } else { + Idx->LaneMask = 0; + } + } + + // FIXME: What if ad-hoc aliasing introduces overlaps that aren't represented + // by the sub-register graph? This doesn't occur in any known targets. - // We don't care about the difference between (Idx1, Idx2) -> Idx2 and invalid - // compositions, so remove any mappings of that form. + // Inherit lanes from composites. for (unsigned i = 0, e = SubRegIndices.size(); i != e; ++i) - SubRegIndices[i]->cleanComposites(); + SubRegIndices[i]->computeLaneMask(); } namespace { @@ -1554,6 +1593,7 @@ void CodeGenRegBank::computeRegUnitSets() { void CodeGenRegBank::computeDerivedInfo() { computeComposites(); + computeSubRegIndexLaneMasks(); // Compute a weight for each register unit created during getSubRegs. // This may create adopted register units (with unit # >= NumNativeRegUnits). diff --git a/contrib/llvm/utils/TableGen/CodeGenRegisters.h b/contrib/llvm/utils/TableGen/CodeGenRegisters.h index 827063e..e411074 100644 --- a/contrib/llvm/utils/TableGen/CodeGenRegisters.h +++ b/contrib/llvm/utils/TableGen/CodeGenRegisters.h @@ -40,6 +40,7 @@ namespace llvm { public: const unsigned EnumValue; + unsigned LaneMask; CodeGenSubRegIndex(Record *R, unsigned Enum); CodeGenSubRegIndex(StringRef N, StringRef Nspace, unsigned Enum); @@ -80,12 +81,12 @@ namespace llvm { // 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; } + // Compute LaneMask from Composed. Return LaneMask. + unsigned computeLaneMask(); + private: CompMap Composed; }; @@ -439,6 +440,7 @@ namespace llvm { // Registers. std::vector<CodeGenRegister*> Registers; + StringMap<CodeGenRegister*> RegistersByName; DenseMap<Record*, CodeGenRegister*> Def2Reg; unsigned NumNativeRegUnits; @@ -489,6 +491,9 @@ namespace llvm { // Populate the Composite map from sub-register relationships. void computeComposites(); + // Compute a lane mask for each sub-register index. + void computeSubRegIndexLaneMasks(); + public: CodeGenRegBank(RecordKeeper&); @@ -518,6 +523,9 @@ namespace llvm { } const std::vector<CodeGenRegister*> &getRegisters() { return Registers; } + const StringMap<CodeGenRegister*> &getRegistersByName() { + return RegistersByName; + } // Find a register from its Record def. CodeGenRegister *getReg(Record*); diff --git a/contrib/llvm/utils/TableGen/CodeGenSchedule.cpp b/contrib/llvm/utils/TableGen/CodeGenSchedule.cpp index f57fd18..63cc97a 100644 --- a/contrib/llvm/utils/TableGen/CodeGenSchedule.cpp +++ b/contrib/llvm/utils/TableGen/CodeGenSchedule.cpp @@ -16,41 +16,505 @@ #include "CodeGenSchedule.h" #include "CodeGenTarget.h" +#include "llvm/TableGen/Error.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Regex.h" +#include "llvm/ADT/STLExtras.h" using namespace llvm; -// CodeGenModels ctor interprets machine model records and populates maps. +#ifndef NDEBUG +static void dumpIdxVec(const IdxVec &V) { + for (unsigned i = 0, e = V.size(); i < e; ++i) { + dbgs() << V[i] << ", "; + } +} +static void dumpIdxVec(const SmallVectorImpl<unsigned> &V) { + for (unsigned i = 0, e = V.size(); i < e; ++i) { + dbgs() << V[i] << ", "; + } +} +#endif + +// (instrs a, b, ...) Evaluate and union all arguments. Identical to AddOp. +struct InstrsOp : public SetTheory::Operator { + void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, + ArrayRef<SMLoc> Loc) { + ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc); + } +}; + +// (instregex "OpcPat",...) Find all instructions matching an opcode pattern. +// +// TODO: Since this is a prefix match, perform a binary search over the +// instruction names using lower_bound. Note that the predefined instrs must be +// scanned linearly first. However, this is only safe if the regex pattern has +// no top-level bars. The DAG already has a list of patterns, so there's no +// reason to use top-level bars, but we need a way to verify they don't exist +// before implementing the optimization. +struct InstRegexOp : public SetTheory::Operator { + const CodeGenTarget &Target; + InstRegexOp(const CodeGenTarget &t): Target(t) {} + + void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, + ArrayRef<SMLoc> Loc) { + SmallVector<Regex*, 4> RegexList; + for (DagInit::const_arg_iterator + AI = Expr->arg_begin(), AE = Expr->arg_end(); AI != AE; ++AI) { + StringInit *SI = dyn_cast<StringInit>(*AI); + if (!SI) + PrintFatalError(Loc, "instregex requires pattern string: " + + Expr->getAsString()); + std::string pat = SI->getValue(); + // Implement a python-style prefix match. + if (pat[0] != '^') { + pat.insert(0, "^("); + pat.insert(pat.end(), ')'); + } + RegexList.push_back(new Regex(pat)); + } + for (CodeGenTarget::inst_iterator I = Target.inst_begin(), + E = Target.inst_end(); I != E; ++I) { + for (SmallVectorImpl<Regex*>::iterator + RI = RegexList.begin(), RE = RegexList.end(); RI != RE; ++RI) { + if ((*RI)->match((*I)->TheDef->getName())) + Elts.insert((*I)->TheDef); + } + } + DeleteContainerPointers(RegexList); + } +}; + +/// CodeGenModels ctor interprets machine model records and populates maps. CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK, const CodeGenTarget &TGT): - Records(RK), Target(TGT), NumItineraryClasses(0), HasProcItineraries(false) { + Records(RK), Target(TGT), NumItineraryClasses(0) { + + Sets.addFieldExpander("InstRW", "Instrs"); + + // Allow Set evaluation to recognize the dags used in InstRW records: + // (instrs Op1, Op1...) + Sets.addOperator("instrs", new InstrsOp); + Sets.addOperator("instregex", new InstRegexOp(Target)); + + // Instantiate a CodeGenProcModel for each SchedMachineModel with the values + // that are explicitly referenced in tablegen records. Resources associated + // with each processor will be derived later. Populate ProcModelMap with the + // CodeGenProcModel instances. + collectProcModels(); + + // Instantiate a CodeGenSchedRW for each SchedReadWrite record explicitly + // defined, and populate SchedReads and SchedWrites vectors. Implicit + // SchedReadWrites that represent sequences derived from expanded variant will + // be inferred later. + collectSchedRW(); + + // Instantiate a CodeGenSchedClass for each unique SchedRW signature directly + // required by an instruction definition, and populate SchedClassIdxMap. Set + // NumItineraryClasses to the number of explicit itinerary classes referenced + // by instructions. Set NumInstrSchedClasses to the number of itinerary + // classes plus any classes implied by instructions that derive from class + // Sched and provide SchedRW list. This does not infer any new classes from + // SchedVariant. + collectSchedClasses(); + + // Find instruction itineraries for each processor. Sort and populate + // CodeGenProcModel::ItinDefList. (Cycle-to-cycle itineraries). This requires + // all itinerary classes to be discovered. + collectProcItins(); + + // Find ItinRW records for each processor and itinerary class. + // (For per-operand resources mapped to itinerary classes). + collectProcItinRW(); + + // Infer new SchedClasses from SchedVariant. + inferSchedClasses(); + + // Populate each CodeGenProcModel's WriteResDefs, ReadAdvanceDefs, and + // ProcResourceDefs. + collectProcResources(); +} + +/// Gather all processor models. +void CodeGenSchedModels::collectProcModels() { + RecVec ProcRecords = Records.getAllDerivedDefinitions("Processor"); + std::sort(ProcRecords.begin(), ProcRecords.end(), LessRecordFieldName()); + + // Reserve space because we can. Reallocation would be ok. + ProcModels.reserve(ProcRecords.size()+1); + + // Use idx=0 for NoModel/NoItineraries. + Record *NoModelDef = Records.getDef("NoSchedModel"); + Record *NoItinsDef = Records.getDef("NoItineraries"); + ProcModels.push_back(CodeGenProcModel(0, "NoSchedModel", + NoModelDef, NoItinsDef)); + ProcModelMap[NoModelDef] = 0; + + // For each processor, find a unique machine model. + for (unsigned i = 0, N = ProcRecords.size(); i < N; ++i) + addProcModel(ProcRecords[i]); +} + +/// Get a unique processor model based on the defined MachineModel and +/// ProcessorItineraries. +void CodeGenSchedModels::addProcModel(Record *ProcDef) { + Record *ModelKey = getModelOrItinDef(ProcDef); + if (!ProcModelMap.insert(std::make_pair(ModelKey, ProcModels.size())).second) + return; + + std::string Name = ModelKey->getName(); + if (ModelKey->isSubClassOf("SchedMachineModel")) { + Record *ItinsDef = ModelKey->getValueAsDef("Itineraries"); + ProcModels.push_back( + CodeGenProcModel(ProcModels.size(), Name, ModelKey, ItinsDef)); + } + else { + // An itinerary is defined without a machine model. Infer a new model. + if (!ModelKey->getValueAsListOfDefs("IID").empty()) + Name = Name + "Model"; + ProcModels.push_back( + CodeGenProcModel(ProcModels.size(), Name, + ProcDef->getValueAsDef("SchedModel"), ModelKey)); + } + DEBUG(ProcModels.back().dump()); +} + +// Recursively find all reachable SchedReadWrite records. +static void scanSchedRW(Record *RWDef, RecVec &RWDefs, + SmallPtrSet<Record*, 16> &RWSet) { + if (!RWSet.insert(RWDef)) + return; + RWDefs.push_back(RWDef); + // Reads don't current have sequence records, but it can be added later. + if (RWDef->isSubClassOf("WriteSequence")) { + RecVec Seq = RWDef->getValueAsListOfDefs("Writes"); + for (RecIter I = Seq.begin(), E = Seq.end(); I != E; ++I) + scanSchedRW(*I, RWDefs, RWSet); + } + else if (RWDef->isSubClassOf("SchedVariant")) { + // Visit each variant (guarded by a different predicate). + RecVec Vars = RWDef->getValueAsListOfDefs("Variants"); + for (RecIter VI = Vars.begin(), VE = Vars.end(); VI != VE; ++VI) { + // Visit each RW in the sequence selected by the current variant. + RecVec Selected = (*VI)->getValueAsListOfDefs("Selected"); + for (RecIter I = Selected.begin(), E = Selected.end(); I != E; ++I) + scanSchedRW(*I, RWDefs, RWSet); + } + } +} + +// Collect and sort all SchedReadWrites reachable via tablegen records. +// More may be inferred later when inferring new SchedClasses from variants. +void CodeGenSchedModels::collectSchedRW() { + // Reserve idx=0 for invalid writes/reads. + SchedWrites.resize(1); + SchedReads.resize(1); + + SmallPtrSet<Record*, 16> RWSet; + + // Find all SchedReadWrites referenced by instruction defs. + RecVec SWDefs, SRDefs; + for (CodeGenTarget::inst_iterator I = Target.inst_begin(), + E = Target.inst_end(); I != E; ++I) { + Record *SchedDef = (*I)->TheDef; + if (!SchedDef->isSubClassOf("Sched")) + continue; + RecVec RWs = SchedDef->getValueAsListOfDefs("SchedRW"); + for (RecIter RWI = RWs.begin(), RWE = RWs.end(); RWI != RWE; ++RWI) { + if ((*RWI)->isSubClassOf("SchedWrite")) + scanSchedRW(*RWI, SWDefs, RWSet); + else { + assert((*RWI)->isSubClassOf("SchedRead") && "Unknown SchedReadWrite"); + scanSchedRW(*RWI, SRDefs, RWSet); + } + } + } + // Find all ReadWrites referenced by InstRW. + RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW"); + for (RecIter OI = InstRWDefs.begin(), OE = InstRWDefs.end(); OI != OE; ++OI) { + // For all OperandReadWrites. + RecVec RWDefs = (*OI)->getValueAsListOfDefs("OperandReadWrites"); + for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end(); + RWI != RWE; ++RWI) { + if ((*RWI)->isSubClassOf("SchedWrite")) + scanSchedRW(*RWI, SWDefs, RWSet); + else { + assert((*RWI)->isSubClassOf("SchedRead") && "Unknown SchedReadWrite"); + scanSchedRW(*RWI, SRDefs, RWSet); + } + } + } + // Find all ReadWrites referenced by ItinRW. + RecVec ItinRWDefs = Records.getAllDerivedDefinitions("ItinRW"); + for (RecIter II = ItinRWDefs.begin(), IE = ItinRWDefs.end(); II != IE; ++II) { + // For all OperandReadWrites. + RecVec RWDefs = (*II)->getValueAsListOfDefs("OperandReadWrites"); + for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end(); + RWI != RWE; ++RWI) { + if ((*RWI)->isSubClassOf("SchedWrite")) + scanSchedRW(*RWI, SWDefs, RWSet); + else { + assert((*RWI)->isSubClassOf("SchedRead") && "Unknown SchedReadWrite"); + scanSchedRW(*RWI, SRDefs, RWSet); + } + } + } + // Find all ReadWrites referenced by SchedAlias. AliasDefs needs to be sorted + // for the loop below that initializes Alias vectors. + RecVec AliasDefs = Records.getAllDerivedDefinitions("SchedAlias"); + std::sort(AliasDefs.begin(), AliasDefs.end(), LessRecord()); + for (RecIter AI = AliasDefs.begin(), AE = AliasDefs.end(); AI != AE; ++AI) { + Record *MatchDef = (*AI)->getValueAsDef("MatchRW"); + Record *AliasDef = (*AI)->getValueAsDef("AliasRW"); + if (MatchDef->isSubClassOf("SchedWrite")) { + if (!AliasDef->isSubClassOf("SchedWrite")) + PrintFatalError((*AI)->getLoc(), "SchedWrite Alias must be SchedWrite"); + scanSchedRW(AliasDef, SWDefs, RWSet); + } + else { + assert(MatchDef->isSubClassOf("SchedRead") && "Unknown SchedReadWrite"); + if (!AliasDef->isSubClassOf("SchedRead")) + PrintFatalError((*AI)->getLoc(), "SchedRead Alias must be SchedRead"); + scanSchedRW(AliasDef, SRDefs, RWSet); + } + } + // Sort and add the SchedReadWrites directly referenced by instructions or + // itinerary resources. Index reads and writes in separate domains. + std::sort(SWDefs.begin(), SWDefs.end(), LessRecord()); + for (RecIter SWI = SWDefs.begin(), SWE = SWDefs.end(); SWI != SWE; ++SWI) { + assert(!getSchedRWIdx(*SWI, /*IsRead=*/false) && "duplicate SchedWrite"); + SchedWrites.push_back(CodeGenSchedRW(SchedWrites.size(), *SWI)); + } + std::sort(SRDefs.begin(), SRDefs.end(), LessRecord()); + for (RecIter SRI = SRDefs.begin(), SRE = SRDefs.end(); SRI != SRE; ++SRI) { + assert(!getSchedRWIdx(*SRI, /*IsRead-*/true) && "duplicate SchedWrite"); + SchedReads.push_back(CodeGenSchedRW(SchedReads.size(), *SRI)); + } + // Initialize WriteSequence vectors. + for (std::vector<CodeGenSchedRW>::iterator WI = SchedWrites.begin(), + WE = SchedWrites.end(); WI != WE; ++WI) { + if (!WI->IsSequence) + continue; + findRWs(WI->TheDef->getValueAsListOfDefs("Writes"), WI->Sequence, + /*IsRead=*/false); + } + // Initialize Aliases vectors. + for (RecIter AI = AliasDefs.begin(), AE = AliasDefs.end(); AI != AE; ++AI) { + Record *AliasDef = (*AI)->getValueAsDef("AliasRW"); + getSchedRW(AliasDef).IsAlias = true; + Record *MatchDef = (*AI)->getValueAsDef("MatchRW"); + CodeGenSchedRW &RW = getSchedRW(MatchDef); + if (RW.IsAlias) + PrintFatalError((*AI)->getLoc(), "Cannot Alias an Alias"); + RW.Aliases.push_back(*AI); + } + DEBUG( + for (unsigned WIdx = 0, WEnd = SchedWrites.size(); WIdx != WEnd; ++WIdx) { + dbgs() << WIdx << ": "; + SchedWrites[WIdx].dump(); + dbgs() << '\n'; + } + for (unsigned RIdx = 0, REnd = SchedReads.size(); RIdx != REnd; ++RIdx) { + dbgs() << RIdx << ": "; + SchedReads[RIdx].dump(); + dbgs() << '\n'; + } + RecVec RWDefs = Records.getAllDerivedDefinitions("SchedReadWrite"); + for (RecIter RI = RWDefs.begin(), RE = RWDefs.end(); + RI != RE; ++RI) { + if (!getSchedRWIdx(*RI, (*RI)->isSubClassOf("SchedRead"))) { + const std::string &Name = (*RI)->getName(); + if (Name != "NoWrite" && Name != "ReadDefault") + dbgs() << "Unused SchedReadWrite " << (*RI)->getName() << '\n'; + } + }); +} + +/// Compute a SchedWrite name from a sequence of writes. +std::string CodeGenSchedModels::genRWName(const IdxVec& Seq, bool IsRead) { + std::string Name("("); + for (IdxIter I = Seq.begin(), E = Seq.end(); I != E; ++I) { + if (I != Seq.begin()) + Name += '_'; + Name += getSchedRW(*I, IsRead).Name; + } + Name += ')'; + return Name; +} + +unsigned CodeGenSchedModels::getSchedRWIdx(Record *Def, bool IsRead, + unsigned After) const { + const std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites; + assert(After < RWVec.size() && "start position out of bounds"); + for (std::vector<CodeGenSchedRW>::const_iterator I = RWVec.begin() + After, + E = RWVec.end(); I != E; ++I) { + if (I->TheDef == Def) + return I - RWVec.begin(); + } + return 0; +} + +bool CodeGenSchedModels::hasReadOfWrite(Record *WriteDef) const { + for (unsigned i = 0, e = SchedReads.size(); i < e; ++i) { + Record *ReadDef = SchedReads[i].TheDef; + if (!ReadDef || !ReadDef->isSubClassOf("ProcReadAdvance")) + continue; + + RecVec ValidWrites = ReadDef->getValueAsListOfDefs("ValidWrites"); + if (std::find(ValidWrites.begin(), ValidWrites.end(), WriteDef) + != ValidWrites.end()) { + return true; + } + } + return false; +} - // Populate SchedClassIdxMap and set NumItineraryClasses. - CollectSchedClasses(); +namespace llvm { +void splitSchedReadWrites(const RecVec &RWDefs, + RecVec &WriteDefs, RecVec &ReadDefs) { + for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end(); RWI != RWE; ++RWI) { + if ((*RWI)->isSubClassOf("SchedWrite")) + WriteDefs.push_back(*RWI); + else { + assert((*RWI)->isSubClassOf("SchedRead") && "unknown SchedReadWrite"); + ReadDefs.push_back(*RWI); + } + } +} +} // namespace llvm + +// Split the SchedReadWrites defs and call findRWs for each list. +void CodeGenSchedModels::findRWs(const RecVec &RWDefs, + IdxVec &Writes, IdxVec &Reads) const { + RecVec WriteDefs; + RecVec ReadDefs; + splitSchedReadWrites(RWDefs, WriteDefs, ReadDefs); + findRWs(WriteDefs, Writes, false); + findRWs(ReadDefs, Reads, true); +} + +// Call getSchedRWIdx for all elements in a sequence of SchedRW defs. +void CodeGenSchedModels::findRWs(const RecVec &RWDefs, IdxVec &RWs, + bool IsRead) const { + for (RecIter RI = RWDefs.begin(), RE = RWDefs.end(); RI != RE; ++RI) { + unsigned Idx = getSchedRWIdx(*RI, IsRead); + assert(Idx && "failed to collect SchedReadWrite"); + RWs.push_back(Idx); + } +} + +void CodeGenSchedModels::expandRWSequence(unsigned RWIdx, IdxVec &RWSeq, + bool IsRead) const { + const CodeGenSchedRW &SchedRW = getSchedRW(RWIdx, IsRead); + if (!SchedRW.IsSequence) { + RWSeq.push_back(RWIdx); + return; + } + int Repeat = + SchedRW.TheDef ? SchedRW.TheDef->getValueAsInt("Repeat") : 1; + for (int i = 0; i < Repeat; ++i) { + for (IdxIter I = SchedRW.Sequence.begin(), E = SchedRW.Sequence.end(); + I != E; ++I) { + expandRWSequence(*I, RWSeq, IsRead); + } + } +} + +// Expand a SchedWrite as a sequence following any aliases that coincide with +// the given processor model. +void CodeGenSchedModels::expandRWSeqForProc( + unsigned RWIdx, IdxVec &RWSeq, bool IsRead, + const CodeGenProcModel &ProcModel) const { + + const CodeGenSchedRW &SchedWrite = getSchedRW(RWIdx, IsRead); + Record *AliasDef = 0; + for (RecIter AI = SchedWrite.Aliases.begin(), AE = SchedWrite.Aliases.end(); + AI != AE; ++AI) { + const CodeGenSchedRW &AliasRW = getSchedRW((*AI)->getValueAsDef("AliasRW")); + if ((*AI)->getValueInit("SchedModel")->isComplete()) { + Record *ModelDef = (*AI)->getValueAsDef("SchedModel"); + if (&getProcModel(ModelDef) != &ProcModel) + continue; + } + if (AliasDef) + PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases " + "defined for processor " + ProcModel.ModelName + + " Ensure only one SchedAlias exists per RW."); + AliasDef = AliasRW.TheDef; + } + if (AliasDef) { + expandRWSeqForProc(getSchedRWIdx(AliasDef, IsRead), + RWSeq, IsRead,ProcModel); + return; + } + if (!SchedWrite.IsSequence) { + RWSeq.push_back(RWIdx); + return; + } + int Repeat = + SchedWrite.TheDef ? SchedWrite.TheDef->getValueAsInt("Repeat") : 1; + for (int i = 0; i < Repeat; ++i) { + for (IdxIter I = SchedWrite.Sequence.begin(), E = SchedWrite.Sequence.end(); + I != E; ++I) { + expandRWSeqForProc(*I, RWSeq, IsRead, ProcModel); + } + } +} + +// Find the existing SchedWrite that models this sequence of writes. +unsigned CodeGenSchedModels::findRWForSequence(const IdxVec &Seq, + bool IsRead) { + std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites; - // Populate ProcModelMap. - CollectProcModels(); + for (std::vector<CodeGenSchedRW>::iterator I = RWVec.begin(), E = RWVec.end(); + I != E; ++I) { + if (I->Sequence == Seq) + return I - RWVec.begin(); + } + // Index zero reserved for invalid RW. + return 0; } -// Visit all the instruction definitions for this target to gather and enumerate -// the itinerary classes. These are the explicitly specified SchedClasses. More -// SchedClasses may be inferred. -void CodeGenSchedModels::CollectSchedClasses() { +/// Add this ReadWrite if it doesn't already exist. +unsigned CodeGenSchedModels::findOrInsertRW(ArrayRef<unsigned> Seq, + bool IsRead) { + assert(!Seq.empty() && "cannot insert empty sequence"); + if (Seq.size() == 1) + return Seq.back(); - // NoItinerary is always the first class at Index=0 + unsigned Idx = findRWForSequence(Seq, IsRead); + if (Idx) + return Idx; + + unsigned RWIdx = IsRead ? SchedReads.size() : SchedWrites.size(); + CodeGenSchedRW SchedRW(RWIdx, IsRead, Seq, genRWName(Seq, IsRead)); + if (IsRead) + SchedReads.push_back(SchedRW); + else + SchedWrites.push_back(SchedRW); + return RWIdx; +} + +/// Visit all the instruction definitions for this target to gather and +/// enumerate the itinerary classes. These are the explicitly specified +/// SchedClasses. More SchedClasses may be inferred. +void CodeGenSchedModels::collectSchedClasses() { + + // NoItinerary is always the first class at Idx=0 SchedClasses.resize(1); SchedClasses.back().Name = "NoItinerary"; + SchedClasses.back().ProcIndices.push_back(0); SchedClassIdxMap[SchedClasses.back().Name] = 0; // Gather and sort all itinerary classes used by instruction descriptions. - std::vector<Record*> ItinClassList; + RecVec ItinClassList; for (CodeGenTarget::inst_iterator I = Target.inst_begin(), E = Target.inst_end(); I != E; ++I) { - Record *SchedDef = (*I)->TheDef->getValueAsDef("Itinerary"); + Record *ItinDef = (*I)->TheDef->getValueAsDef("Itinerary"); // Map a new SchedClass with no index. - if (!SchedClassIdxMap.count(SchedDef->getName())) { - SchedClassIdxMap[SchedDef->getName()] = 0; - ItinClassList.push_back(SchedDef); + if (!SchedClassIdxMap.count(ItinDef->getName())) { + SchedClassIdxMap[ItinDef->getName()] = 0; + ItinClassList.push_back(ItinDef); } } // Assign each itinerary class unique number, skipping NoItinerary==0 @@ -61,91 +525,1139 @@ void CodeGenSchedModels::CollectSchedClasses() { SchedClassIdxMap[ItinDef->getName()] = SchedClasses.size(); SchedClasses.push_back(CodeGenSchedClass(ItinDef)); } + // Infer classes from SchedReadWrite resources listed for each + // instruction definition that inherits from class Sched. + for (CodeGenTarget::inst_iterator I = Target.inst_begin(), + E = Target.inst_end(); I != E; ++I) { + if (!(*I)->TheDef->isSubClassOf("Sched")) + continue; + IdxVec Writes, Reads; + findRWs((*I)->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads); + // ProcIdx == 0 indicates the class applies to all processors. + IdxVec ProcIndices(1, 0); + addSchedClass(Writes, Reads, ProcIndices); + } + // Create classes for InstRW defs. + RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW"); + std::sort(InstRWDefs.begin(), InstRWDefs.end(), LessRecord()); + for (RecIter OI = InstRWDefs.begin(), OE = InstRWDefs.end(); OI != OE; ++OI) + createInstRWClass(*OI); + + NumInstrSchedClasses = SchedClasses.size(); + + bool EnableDump = false; + DEBUG(EnableDump = true); + if (!EnableDump) + return; + for (CodeGenTarget::inst_iterator I = Target.inst_begin(), + E = Target.inst_end(); I != E; ++I) { + Record *SchedDef = (*I)->TheDef; + std::string InstName = (*I)->TheDef->getName(); + if (SchedDef->isSubClassOf("Sched")) { + IdxVec Writes; + IdxVec Reads; + findRWs((*I)->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads); + dbgs() << "SchedRW machine model for " << InstName; + for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI) + dbgs() << " " << SchedWrites[*WI].Name; + for (IdxIter RI = Reads.begin(), RE = Reads.end(); RI != RE; ++RI) + dbgs() << " " << SchedReads[*RI].Name; + dbgs() << '\n'; + } + unsigned SCIdx = InstrClassMap.lookup((*I)->TheDef); + if (SCIdx) { + const RecVec &RWDefs = SchedClasses[SCIdx].InstRWs; + for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end(); + RWI != RWE; ++RWI) { + const CodeGenProcModel &ProcModel = + getProcModel((*RWI)->getValueAsDef("SchedModel")); + dbgs() << "InstRW on " << ProcModel.ModelName << " for " << InstName; + IdxVec Writes; + IdxVec Reads; + findRWs((*RWI)->getValueAsListOfDefs("OperandReadWrites"), + Writes, Reads); + for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI) + dbgs() << " " << SchedWrites[*WI].Name; + for (IdxIter RI = Reads.begin(), RE = Reads.end(); RI != RE; ++RI) + dbgs() << " " << SchedReads[*RI].Name; + dbgs() << '\n'; + } + continue; + } + if (!SchedDef->isSubClassOf("Sched") + && (SchedDef->getValueAsDef("Itinerary")->getName() == "NoItinerary")) { + dbgs() << "No machine model for " << (*I)->TheDef->getName() << '\n'; + } + } +} + +unsigned CodeGenSchedModels::getSchedClassIdx( + const RecVec &RWDefs) const { - // TODO: Infer classes from non-itinerary scheduler resources. + IdxVec Writes, Reads; + findRWs(RWDefs, Writes, Reads); + return findSchedClassIdx(Writes, Reads); } -// Gather all processor models. -void CodeGenSchedModels::CollectProcModels() { - std::vector<Record*> ProcRecords = - Records.getAllDerivedDefinitions("Processor"); - std::sort(ProcRecords.begin(), ProcRecords.end(), LessRecordFieldName()); +/// Find an SchedClass that has been inferred from a per-operand list of +/// SchedWrites and SchedReads. +unsigned CodeGenSchedModels::findSchedClassIdx(const IdxVec &Writes, + const IdxVec &Reads) const { + for (SchedClassIter I = schedClassBegin(), E = schedClassEnd(); I != E; ++I) { + // Classes with InstRWs may have the same Writes/Reads as a class originally + // produced by a SchedRW definition. We need to be able to recover the + // original class index for processors that don't match any InstRWs. + if (I->ItinClassDef || !I->InstRWs.empty()) + continue; - // Reserve space because we can. Reallocation would be ok. - ProcModels.reserve(ProcRecords.size()); + if (I->Writes == Writes && I->Reads == Reads) { + return I - schedClassBegin(); + } + } + return 0; +} - // For each processor, find a unique machine model. - for (unsigned i = 0, N = ProcRecords.size(); i < N; ++i) - addProcModel(ProcRecords[i]); +// Get the SchedClass index for an instruction. +unsigned CodeGenSchedModels::getSchedClassIdx( + const CodeGenInstruction &Inst) const { + + unsigned SCIdx = InstrClassMap.lookup(Inst.TheDef); + if (SCIdx) + return SCIdx; + + // If this opcode isn't mapped by the subtarget fallback to the instruction + // definition's SchedRW or ItinDef values. + if (Inst.TheDef->isSubClassOf("Sched")) { + RecVec RWs = Inst.TheDef->getValueAsListOfDefs("SchedRW"); + return getSchedClassIdx(RWs); + } + Record *ItinDef = Inst.TheDef->getValueAsDef("Itinerary"); + assert(SchedClassIdxMap.count(ItinDef->getName()) && "missing ItinClass"); + unsigned Idx = SchedClassIdxMap.lookup(ItinDef->getName()); + assert(Idx <= NumItineraryClasses && "bad ItinClass index"); + return Idx; } -// Get a unique processor model based on the defined MachineModel and -// ProcessorItineraries. -void CodeGenSchedModels::addProcModel(Record *ProcDef) { - unsigned Idx = getProcModelIdx(ProcDef); - if (Idx < ProcModels.size()) - return; +std::string CodeGenSchedModels::createSchedClassName( + const IdxVec &OperWrites, const IdxVec &OperReads) { + + std::string Name; + for (IdxIter WI = OperWrites.begin(), WE = OperWrites.end(); WI != WE; ++WI) { + if (WI != OperWrites.begin()) + Name += '_'; + Name += SchedWrites[*WI].Name; + } + for (IdxIter RI = OperReads.begin(), RE = OperReads.end(); RI != RE; ++RI) { + Name += '_'; + Name += SchedReads[*RI].Name; + } + return Name; +} + +std::string CodeGenSchedModels::createSchedClassName(const RecVec &InstDefs) { + + std::string Name; + for (RecIter I = InstDefs.begin(), E = InstDefs.end(); I != E; ++I) { + if (I != InstDefs.begin()) + Name += '_'; + Name += (*I)->getName(); + } + return Name; +} + +/// Add an inferred sched class from a per-operand list of SchedWrites and +/// SchedReads. ProcIndices contains the set of IDs of processors that may +/// utilize this class. +unsigned CodeGenSchedModels::addSchedClass(const IdxVec &OperWrites, + const IdxVec &OperReads, + const IdxVec &ProcIndices) +{ + assert(!ProcIndices.empty() && "expect at least one ProcIdx"); + + unsigned Idx = findSchedClassIdx(OperWrites, OperReads); + if (Idx) { + IdxVec PI; + std::set_union(SchedClasses[Idx].ProcIndices.begin(), + SchedClasses[Idx].ProcIndices.end(), + ProcIndices.begin(), ProcIndices.end(), + std::back_inserter(PI)); + SchedClasses[Idx].ProcIndices.swap(PI); + return Idx; + } + Idx = SchedClasses.size(); + SchedClasses.resize(Idx+1); + CodeGenSchedClass &SC = SchedClasses.back(); + SC.Name = createSchedClassName(OperWrites, OperReads); + SC.Writes = OperWrites; + SC.Reads = OperReads; + SC.ProcIndices = ProcIndices; + + return Idx; +} + +// Create classes for each set of opcodes that are in the same InstReadWrite +// definition across all processors. +void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) { + // ClassInstrs will hold an entry for each subset of Instrs in InstRWDef that + // intersects with an existing class via a previous InstRWDef. Instrs that do + // not intersect with an existing class refer back to their former class as + // determined from ItinDef or SchedRW. + SmallVector<std::pair<unsigned, SmallVector<Record *, 8> >, 4> ClassInstrs; + // Sort Instrs into sets. + const RecVec *InstDefs = Sets.expand(InstRWDef); + if (InstDefs->empty()) + PrintFatalError(InstRWDef->getLoc(), "No matching instruction opcodes"); + + for (RecIter I = InstDefs->begin(), E = InstDefs->end(); I != E; ++I) { + unsigned SCIdx = 0; + InstClassMapTy::const_iterator Pos = InstrClassMap.find(*I); + if (Pos != InstrClassMap.end()) + SCIdx = Pos->second; + else { + // This instruction has not been mapped yet. Get the original class. All + // instructions in the same InstrRW class must be from the same original + // class because that is the fall-back class for other processors. + Record *ItinDef = (*I)->getValueAsDef("Itinerary"); + SCIdx = SchedClassIdxMap.lookup(ItinDef->getName()); + if (!SCIdx && (*I)->isSubClassOf("Sched")) + SCIdx = getSchedClassIdx((*I)->getValueAsListOfDefs("SchedRW")); + } + unsigned CIdx = 0, CEnd = ClassInstrs.size(); + for (; CIdx != CEnd; ++CIdx) { + if (ClassInstrs[CIdx].first == SCIdx) + break; + } + if (CIdx == CEnd) { + ClassInstrs.resize(CEnd + 1); + ClassInstrs[CIdx].first = SCIdx; + } + ClassInstrs[CIdx].second.push_back(*I); + } + // For each set of Instrs, create a new class if necessary, and map or remap + // the Instrs to it. + unsigned CIdx = 0, CEnd = ClassInstrs.size(); + for (; CIdx != CEnd; ++CIdx) { + unsigned OldSCIdx = ClassInstrs[CIdx].first; + ArrayRef<Record*> InstDefs = ClassInstrs[CIdx].second; + // If the all instrs in the current class are accounted for, then leave + // them mapped to their old class. + if (SchedClasses[OldSCIdx].InstRWs.size() == InstDefs.size()) { + assert(SchedClasses[OldSCIdx].ProcIndices[0] == 0 && + "expected a generic SchedClass"); + continue; + } + unsigned SCIdx = SchedClasses.size(); + SchedClasses.resize(SCIdx+1); + CodeGenSchedClass &SC = SchedClasses.back(); + SC.Name = createSchedClassName(InstDefs); + // Preserve ItinDef and Writes/Reads for processors without an InstRW entry. + SC.ItinClassDef = SchedClasses[OldSCIdx].ItinClassDef; + SC.Writes = SchedClasses[OldSCIdx].Writes; + SC.Reads = SchedClasses[OldSCIdx].Reads; + SC.ProcIndices.push_back(0); + // Map each Instr to this new class. + // Note that InstDefs may be a smaller list than InstRWDef's "Instrs". + Record *RWModelDef = InstRWDef->getValueAsDef("SchedModel"); + SmallSet<unsigned, 4> RemappedClassIDs; + for (ArrayRef<Record*>::const_iterator + II = InstDefs.begin(), IE = InstDefs.end(); II != IE; ++II) { + unsigned OldSCIdx = InstrClassMap[*II]; + if (OldSCIdx && RemappedClassIDs.insert(OldSCIdx)) { + for (RecIter RI = SchedClasses[OldSCIdx].InstRWs.begin(), + RE = SchedClasses[OldSCIdx].InstRWs.end(); RI != RE; ++RI) { + if ((*RI)->getValueAsDef("SchedModel") == RWModelDef) { + PrintFatalError(InstRWDef->getLoc(), "Overlapping InstRW def " + + (*II)->getName() + " also matches " + + (*RI)->getValue("Instrs")->getValue()->getAsString()); + } + assert(*RI != InstRWDef && "SchedClass has duplicate InstRW def"); + SC.InstRWs.push_back(*RI); + } + } + InstrClassMap[*II] = SCIdx; + } + SC.InstRWs.push_back(InstRWDef); + } +} + +// Gather the processor itineraries. +void CodeGenSchedModels::collectProcItins() { + for (std::vector<CodeGenProcModel>::iterator PI = ProcModels.begin(), + PE = ProcModels.end(); PI != PE; ++PI) { + CodeGenProcModel &ProcModel = *PI; + RecVec ItinRecords = ProcModel.ItinsDef->getValueAsListOfDefs("IID"); + // Skip empty itinerary. + if (ItinRecords.empty()) + continue; + + ProcModel.ItinDefList.resize(NumItineraryClasses+1); + + // Insert each itinerary data record in the correct position within + // the processor model's ItinDefList. + for (unsigned i = 0, N = ItinRecords.size(); i < N; i++) { + Record *ItinData = ItinRecords[i]; + Record *ItinDef = ItinData->getValueAsDef("TheClass"); + if (!SchedClassIdxMap.count(ItinDef->getName())) { + DEBUG(dbgs() << ProcModel.ItinsDef->getName() + << " has unused itinerary class " << ItinDef->getName() << '\n'); + continue; + } + assert(SchedClassIdxMap.count(ItinDef->getName()) && "missing ItinClass"); + unsigned Idx = SchedClassIdxMap.lookup(ItinDef->getName()); + assert(Idx <= NumItineraryClasses && "bad ItinClass index"); + ProcModel.ItinDefList[Idx] = ItinData; + } + // Check for missing itinerary entries. + assert(!ProcModel.ItinDefList[0] && "NoItinerary class can't have rec"); + DEBUG( + for (unsigned i = 1, N = ProcModel.ItinDefList.size(); i < N; ++i) { + if (!ProcModel.ItinDefList[i]) + dbgs() << ProcModel.ItinsDef->getName() + << " missing itinerary for class " + << SchedClasses[i].Name << '\n'; + }); + } +} + +// Gather the read/write types for each itinerary class. +void CodeGenSchedModels::collectProcItinRW() { + RecVec ItinRWDefs = Records.getAllDerivedDefinitions("ItinRW"); + std::sort(ItinRWDefs.begin(), ItinRWDefs.end(), LessRecord()); + for (RecIter II = ItinRWDefs.begin(), IE = ItinRWDefs.end(); II != IE; ++II) { + if (!(*II)->getValueInit("SchedModel")->isComplete()) + PrintFatalError((*II)->getLoc(), "SchedModel is undefined"); + Record *ModelDef = (*II)->getValueAsDef("SchedModel"); + ProcModelMapTy::const_iterator I = ProcModelMap.find(ModelDef); + if (I == ProcModelMap.end()) { + PrintFatalError((*II)->getLoc(), "Undefined SchedMachineModel " + + ModelDef->getName()); + } + ProcModels[I->second].ItinRWDefs.push_back(*II); + } +} + +/// Infer new classes from existing classes. In the process, this may create new +/// SchedWrites from sequences of existing SchedWrites. +void CodeGenSchedModels::inferSchedClasses() { + // Visit all existing classes and newly created classes. + for (unsigned Idx = 0; Idx != SchedClasses.size(); ++Idx) { + if (SchedClasses[Idx].ItinClassDef) + inferFromItinClass(SchedClasses[Idx].ItinClassDef, Idx); + else if (!SchedClasses[Idx].InstRWs.empty()) + inferFromInstRWs(Idx); + else { + inferFromRW(SchedClasses[Idx].Writes, SchedClasses[Idx].Reads, + Idx, SchedClasses[Idx].ProcIndices); + } + assert(SchedClasses.size() < (NumInstrSchedClasses*6) && + "too many SchedVariants"); + } +} + +/// Infer classes from per-processor itinerary resources. +void CodeGenSchedModels::inferFromItinClass(Record *ItinClassDef, + unsigned FromClassIdx) { + for (unsigned PIdx = 0, PEnd = ProcModels.size(); PIdx != PEnd; ++PIdx) { + const CodeGenProcModel &PM = ProcModels[PIdx]; + // For all ItinRW entries. + bool HasMatch = false; + for (RecIter II = PM.ItinRWDefs.begin(), IE = PM.ItinRWDefs.end(); + II != IE; ++II) { + RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses"); + if (!std::count(Matched.begin(), Matched.end(), ItinClassDef)) + continue; + if (HasMatch) + PrintFatalError((*II)->getLoc(), "Duplicate itinerary class " + + ItinClassDef->getName() + + " in ItinResources for " + PM.ModelName); + HasMatch = true; + IdxVec Writes, Reads; + findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); + IdxVec ProcIndices(1, PIdx); + inferFromRW(Writes, Reads, FromClassIdx, ProcIndices); + } + } +} + +/// Infer classes from per-processor InstReadWrite definitions. +void CodeGenSchedModels::inferFromInstRWs(unsigned SCIdx) { + const RecVec &RWDefs = SchedClasses[SCIdx].InstRWs; + for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end(); RWI != RWE; ++RWI) { + const RecVec *InstDefs = Sets.expand(*RWI); + RecIter II = InstDefs->begin(), IE = InstDefs->end(); + for (; II != IE; ++II) { + if (InstrClassMap[*II] == SCIdx) + break; + } + // If this class no longer has any instructions mapped to it, it has become + // irrelevant. + if (II == IE) + continue; + IdxVec Writes, Reads; + findRWs((*RWI)->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); + unsigned PIdx = getProcModel((*RWI)->getValueAsDef("SchedModel")).Index; + IdxVec ProcIndices(1, PIdx); + inferFromRW(Writes, Reads, SCIdx, ProcIndices); + } +} + +namespace { +// Helper for substituteVariantOperand. +struct TransVariant { + Record *VarOrSeqDef; // Variant or sequence. + unsigned RWIdx; // Index of this variant or sequence's matched type. + unsigned ProcIdx; // Processor model index or zero for any. + unsigned TransVecIdx; // Index into PredTransitions::TransVec. + + TransVariant(Record *def, unsigned rwi, unsigned pi, unsigned ti): + VarOrSeqDef(def), RWIdx(rwi), ProcIdx(pi), TransVecIdx(ti) {} +}; + +// Associate a predicate with the SchedReadWrite that it guards. +// RWIdx is the index of the read/write variant. +struct PredCheck { + bool IsRead; + unsigned RWIdx; + Record *Predicate; + + PredCheck(bool r, unsigned w, Record *p): IsRead(r), RWIdx(w), Predicate(p) {} +}; + +// A Predicate transition is a list of RW sequences guarded by a PredTerm. +struct PredTransition { + // A predicate term is a conjunction of PredChecks. + SmallVector<PredCheck, 4> PredTerm; + SmallVector<SmallVector<unsigned,4>, 16> WriteSequences; + SmallVector<SmallVector<unsigned,4>, 16> ReadSequences; + SmallVector<unsigned, 4> ProcIndices; +}; + +// Encapsulate a set of partially constructed transitions. +// The results are built by repeated calls to substituteVariants. +class PredTransitions { + CodeGenSchedModels &SchedModels; + +public: + std::vector<PredTransition> TransVec; + + PredTransitions(CodeGenSchedModels &sm): SchedModels(sm) {} + + void substituteVariantOperand(const SmallVectorImpl<unsigned> &RWSeq, + bool IsRead, unsigned StartIdx); + + void substituteVariants(const PredTransition &Trans); + +#ifndef NDEBUG + void dump() const; +#endif + +private: + bool mutuallyExclusive(Record *PredDef, ArrayRef<PredCheck> Term); + void getIntersectingVariants( + const CodeGenSchedRW &SchedRW, unsigned TransIdx, + std::vector<TransVariant> &IntersectingVariants); + void pushVariant(const TransVariant &VInfo, bool IsRead); +}; +} // anonymous + +// Return true if this predicate is mutually exclusive with a PredTerm. This +// degenerates into checking if the predicate is mutually exclusive with any +// predicate in the Term's conjunction. +// +// All predicates associated with a given SchedRW are considered mutually +// exclusive. This should work even if the conditions expressed by the +// predicates are not exclusive because the predicates for a given SchedWrite +// are always checked in the order they are defined in the .td file. Later +// conditions implicitly negate any prior condition. +bool PredTransitions::mutuallyExclusive(Record *PredDef, + ArrayRef<PredCheck> Term) { + + for (ArrayRef<PredCheck>::iterator I = Term.begin(), E = Term.end(); + I != E; ++I) { + if (I->Predicate == PredDef) + return false; - Record *ModelDef = ProcDef->getValueAsDef("SchedModel"); - Record *ItinsDef = ProcDef->getValueAsDef("ProcItin"); + const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(I->RWIdx, I->IsRead); + assert(SchedRW.HasVariants && "PredCheck must refer to a SchedVariant"); + RecVec Variants = SchedRW.TheDef->getValueAsListOfDefs("Variants"); + for (RecIter VI = Variants.begin(), VE = Variants.end(); VI != VE; ++VI) { + if ((*VI)->getValueAsDef("Predicate") == PredDef) + return true; + } + } + return false; +} - std::string ModelName = ModelDef->getName(); - const std::string &ItinName = ItinsDef->getName(); +static bool hasAliasedVariants(const CodeGenSchedRW &RW, + CodeGenSchedModels &SchedModels) { + if (RW.HasVariants) + return true; - bool NoModel = ModelDef->getValueAsBit("NoModel"); - bool hasTopLevelItin = !ItinsDef->getValueAsListOfDefs("IID").empty(); - if (NoModel) { - // If an itinerary is defined without a machine model, infer a new model. - if (NoModel && hasTopLevelItin) { - ModelName = ItinName + "Model"; - ModelDef = NULL; + for (RecIter I = RW.Aliases.begin(), E = RW.Aliases.end(); I != E; ++I) { + const CodeGenSchedRW &AliasRW = + SchedModels.getSchedRW((*I)->getValueAsDef("AliasRW")); + if (AliasRW.HasVariants) + return true; + if (AliasRW.IsSequence) { + IdxVec ExpandedRWs; + SchedModels.expandRWSequence(AliasRW.Index, ExpandedRWs, AliasRW.IsRead); + for (IdxIter SI = ExpandedRWs.begin(), SE = ExpandedRWs.end(); + SI != SE; ++SI) { + if (hasAliasedVariants(SchedModels.getSchedRW(*SI, AliasRW.IsRead), + SchedModels)) { + return true; + } + } + } + } + return false; +} + +static bool hasVariant(ArrayRef<PredTransition> Transitions, + CodeGenSchedModels &SchedModels) { + for (ArrayRef<PredTransition>::iterator + PTI = Transitions.begin(), PTE = Transitions.end(); + PTI != PTE; ++PTI) { + for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator + WSI = PTI->WriteSequences.begin(), WSE = PTI->WriteSequences.end(); + WSI != WSE; ++WSI) { + for (SmallVectorImpl<unsigned>::const_iterator + WI = WSI->begin(), WE = WSI->end(); WI != WE; ++WI) { + if (hasAliasedVariants(SchedModels.getSchedWrite(*WI), SchedModels)) + return true; + } + } + for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator + RSI = PTI->ReadSequences.begin(), RSE = PTI->ReadSequences.end(); + RSI != RSE; ++RSI) { + for (SmallVectorImpl<unsigned>::const_iterator + RI = RSI->begin(), RE = RSI->end(); RI != RE; ++RI) { + if (hasAliasedVariants(SchedModels.getSchedRead(*RI), SchedModels)) + return true; + } + } + } + return false; +} + +// Populate IntersectingVariants with any variants or aliased sequences of the +// given SchedRW whose processor indices and predicates are not mutually +// exclusive with the given transition, +void PredTransitions::getIntersectingVariants( + const CodeGenSchedRW &SchedRW, unsigned TransIdx, + std::vector<TransVariant> &IntersectingVariants) { + + std::vector<TransVariant> Variants; + if (SchedRW.HasVariants) { + unsigned VarProcIdx = 0; + if (SchedRW.TheDef->getValueInit("SchedModel")->isComplete()) { + Record *ModelDef = SchedRW.TheDef->getValueAsDef("SchedModel"); + VarProcIdx = SchedModels.getProcModel(ModelDef).Index; + } + // Push each variant. Assign TransVecIdx later. + const RecVec VarDefs = SchedRW.TheDef->getValueAsListOfDefs("Variants"); + for (RecIter RI = VarDefs.begin(), RE = VarDefs.end(); RI != RE; ++RI) + Variants.push_back(TransVariant(*RI, SchedRW.Index, VarProcIdx, 0)); + } + for (RecIter AI = SchedRW.Aliases.begin(), AE = SchedRW.Aliases.end(); + AI != AE; ++AI) { + // If either the SchedAlias itself or the SchedReadWrite that it aliases + // to is defined within a processor model, constrain all variants to + // that processor. + unsigned AliasProcIdx = 0; + if ((*AI)->getValueInit("SchedModel")->isComplete()) { + Record *ModelDef = (*AI)->getValueAsDef("SchedModel"); + AliasProcIdx = SchedModels.getProcModel(ModelDef).Index; + } + const CodeGenSchedRW &AliasRW = + SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW")); + + if (AliasRW.HasVariants) { + const RecVec VarDefs = AliasRW.TheDef->getValueAsListOfDefs("Variants"); + for (RecIter RI = VarDefs.begin(), RE = VarDefs.end(); RI != RE; ++RI) + Variants.push_back(TransVariant(*RI, AliasRW.Index, AliasProcIdx, 0)); + } + if (AliasRW.IsSequence) { + Variants.push_back( + TransVariant(AliasRW.TheDef, SchedRW.Index, AliasProcIdx, 0)); + } + } + for (unsigned VIdx = 0, VEnd = Variants.size(); VIdx != VEnd; ++VIdx) { + TransVariant &Variant = Variants[VIdx]; + // Don't expand variants if the processor models don't intersect. + // A zero processor index means any processor. + SmallVector<unsigned, 4> &ProcIndices = TransVec[TransIdx].ProcIndices; + if (ProcIndices[0] && Variants[VIdx].ProcIdx) { + unsigned Cnt = std::count(ProcIndices.begin(), ProcIndices.end(), + Variant.ProcIdx); + if (!Cnt) + continue; + if (Cnt > 1) { + const CodeGenProcModel &PM = + *(SchedModels.procModelBegin() + Variant.ProcIdx); + PrintFatalError(Variant.VarOrSeqDef->getLoc(), + "Multiple variants defined for processor " + + PM.ModelName + + " Ensure only one SchedAlias exists per RW."); + } + } + if (Variant.VarOrSeqDef->isSubClassOf("SchedVar")) { + Record *PredDef = Variant.VarOrSeqDef->getValueAsDef("Predicate"); + if (mutuallyExclusive(PredDef, TransVec[TransIdx].PredTerm)) + continue; + } + if (IntersectingVariants.empty()) { + // The first variant builds on the existing transition. + Variant.TransVecIdx = TransIdx; + IntersectingVariants.push_back(Variant); + } + else { + // Push another copy of the current transition for more variants. + Variant.TransVecIdx = TransVec.size(); + IntersectingVariants.push_back(Variant); + TransVec.push_back(TransVec[TransIdx]); } } +} + +// Push the Reads/Writes selected by this variant onto the PredTransition +// specified by VInfo. +void PredTransitions:: +pushVariant(const TransVariant &VInfo, bool IsRead) { + + PredTransition &Trans = TransVec[VInfo.TransVecIdx]; + + // If this operand transition is reached through a processor-specific alias, + // then the whole transition is specific to this processor. + if (VInfo.ProcIdx != 0) + Trans.ProcIndices.assign(1, VInfo.ProcIdx); + + IdxVec SelectedRWs; + if (VInfo.VarOrSeqDef->isSubClassOf("SchedVar")) { + Record *PredDef = VInfo.VarOrSeqDef->getValueAsDef("Predicate"); + Trans.PredTerm.push_back(PredCheck(IsRead, VInfo.RWIdx,PredDef)); + RecVec SelectedDefs = VInfo.VarOrSeqDef->getValueAsListOfDefs("Selected"); + SchedModels.findRWs(SelectedDefs, SelectedRWs, IsRead); + } else { - // If a machine model is defined, the itinerary must be defined within it - // rather than in the Processor definition itself. - assert(!hasTopLevelItin && "Itinerary must be defined in SchedModel"); - ItinsDef = ModelDef->getValueAsDef("Itineraries"); + assert(VInfo.VarOrSeqDef->isSubClassOf("WriteSequence") && + "variant must be a SchedVariant or aliased WriteSequence"); + SelectedRWs.push_back(SchedModels.getSchedRWIdx(VInfo.VarOrSeqDef, IsRead)); } - ProcModelMap[getProcModelKey(ProcDef)]= ProcModels.size(); + const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(VInfo.RWIdx, IsRead); - ProcModels.push_back(CodeGenProcModel(ModelName, ModelDef, ItinsDef)); + SmallVectorImpl<SmallVector<unsigned,4> > &RWSequences = IsRead + ? Trans.ReadSequences : Trans.WriteSequences; + if (SchedRW.IsVariadic) { + unsigned OperIdx = RWSequences.size()-1; + // Make N-1 copies of this transition's last sequence. + for (unsigned i = 1, e = SelectedRWs.size(); i != e; ++i) { + RWSequences.push_back(RWSequences[OperIdx]); + } + // Push each of the N elements of the SelectedRWs onto a copy of the last + // sequence (split the current operand into N operands). + // Note that write sequences should be expanded within this loop--the entire + // sequence belongs to a single operand. + for (IdxIter RWI = SelectedRWs.begin(), RWE = SelectedRWs.end(); + RWI != RWE; ++RWI, ++OperIdx) { + IdxVec ExpandedRWs; + if (IsRead) + ExpandedRWs.push_back(*RWI); + else + SchedModels.expandRWSequence(*RWI, ExpandedRWs, IsRead); + RWSequences[OperIdx].insert(RWSequences[OperIdx].end(), + ExpandedRWs.begin(), ExpandedRWs.end()); + } + assert(OperIdx == RWSequences.size() && "missed a sequence"); + } + else { + // Push this transition's expanded sequence onto this transition's last + // sequence (add to the current operand's sequence). + SmallVectorImpl<unsigned> &Seq = RWSequences.back(); + IdxVec ExpandedRWs; + for (IdxIter RWI = SelectedRWs.begin(), RWE = SelectedRWs.end(); + RWI != RWE; ++RWI) { + if (IsRead) + ExpandedRWs.push_back(*RWI); + else + SchedModels.expandRWSequence(*RWI, ExpandedRWs, IsRead); + } + Seq.insert(Seq.end(), ExpandedRWs.begin(), ExpandedRWs.end()); + } +} + +// RWSeq is a sequence of all Reads or all Writes for the next read or write +// operand. StartIdx is an index into TransVec where partial results +// starts. RWSeq must be applied to all transitions between StartIdx and the end +// of TransVec. +void PredTransitions::substituteVariantOperand( + const SmallVectorImpl<unsigned> &RWSeq, bool IsRead, unsigned StartIdx) { - std::vector<Record*> ItinRecords = ItinsDef->getValueAsListOfDefs("IID"); - CollectProcItin(ProcModels.back(), ItinRecords); + // Visit each original RW within the current sequence. + for (SmallVectorImpl<unsigned>::const_iterator + RWI = RWSeq.begin(), RWE = RWSeq.end(); RWI != RWE; ++RWI) { + const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(*RWI, IsRead); + // Push this RW on all partial PredTransitions or distribute variants. + // New PredTransitions may be pushed within this loop which should not be + // revisited (TransEnd must be loop invariant). + for (unsigned TransIdx = StartIdx, TransEnd = TransVec.size(); + TransIdx != TransEnd; ++TransIdx) { + // In the common case, push RW onto the current operand's sequence. + if (!hasAliasedVariants(SchedRW, SchedModels)) { + if (IsRead) + TransVec[TransIdx].ReadSequences.back().push_back(*RWI); + else + TransVec[TransIdx].WriteSequences.back().push_back(*RWI); + continue; + } + // Distribute this partial PredTransition across intersecting variants. + // This will push a copies of TransVec[TransIdx] on the back of TransVec. + std::vector<TransVariant> IntersectingVariants; + getIntersectingVariants(SchedRW, TransIdx, IntersectingVariants); + if (IntersectingVariants.empty()) + PrintFatalError(SchedRW.TheDef->getLoc(), + "No variant of this type has " + "a matching predicate on any processor"); + // Now expand each variant on top of its copy of the transition. + for (std::vector<TransVariant>::const_iterator + IVI = IntersectingVariants.begin(), + IVE = IntersectingVariants.end(); + IVI != IVE; ++IVI) { + pushVariant(*IVI, IsRead); + } + } + } } -// Gather the processor itineraries. -void CodeGenSchedModels::CollectProcItin(CodeGenProcModel &ProcModel, - std::vector<Record*> ItinRecords) { - // Skip empty itinerary. - if (ItinRecords.empty()) +// For each variant of a Read/Write in Trans, substitute the sequence of +// Read/Writes guarded by the variant. This is exponential in the number of +// variant Read/Writes, but in practice detection of mutually exclusive +// predicates should result in linear growth in the total number variants. +// +// This is one step in a breadth-first search of nested variants. +void PredTransitions::substituteVariants(const PredTransition &Trans) { + // Build up a set of partial results starting at the back of + // PredTransitions. Remember the first new transition. + unsigned StartIdx = TransVec.size(); + TransVec.resize(TransVec.size() + 1); + TransVec.back().PredTerm = Trans.PredTerm; + TransVec.back().ProcIndices = Trans.ProcIndices; + + // Visit each original write sequence. + for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator + WSI = Trans.WriteSequences.begin(), WSE = Trans.WriteSequences.end(); + WSI != WSE; ++WSI) { + // Push a new (empty) write sequence onto all partial Transitions. + for (std::vector<PredTransition>::iterator I = + TransVec.begin() + StartIdx, E = TransVec.end(); I != E; ++I) { + I->WriteSequences.resize(I->WriteSequences.size() + 1); + } + substituteVariantOperand(*WSI, /*IsRead=*/false, StartIdx); + } + // Visit each original read sequence. + for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator + RSI = Trans.ReadSequences.begin(), RSE = Trans.ReadSequences.end(); + RSI != RSE; ++RSI) { + // Push a new (empty) read sequence onto all partial Transitions. + for (std::vector<PredTransition>::iterator I = + TransVec.begin() + StartIdx, E = TransVec.end(); I != E; ++I) { + I->ReadSequences.resize(I->ReadSequences.size() + 1); + } + substituteVariantOperand(*RSI, /*IsRead=*/true, StartIdx); + } +} + +// Create a new SchedClass for each variant found by inferFromRW. Pass +static void inferFromTransitions(ArrayRef<PredTransition> LastTransitions, + unsigned FromClassIdx, + CodeGenSchedModels &SchedModels) { + // For each PredTransition, create a new CodeGenSchedTransition, which usually + // requires creating a new SchedClass. + for (ArrayRef<PredTransition>::iterator + I = LastTransitions.begin(), E = LastTransitions.end(); I != E; ++I) { + IdxVec OperWritesVariant; + for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator + WSI = I->WriteSequences.begin(), WSE = I->WriteSequences.end(); + WSI != WSE; ++WSI) { + // Create a new write representing the expanded sequence. + OperWritesVariant.push_back( + SchedModels.findOrInsertRW(*WSI, /*IsRead=*/false)); + } + IdxVec OperReadsVariant; + for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator + RSI = I->ReadSequences.begin(), RSE = I->ReadSequences.end(); + RSI != RSE; ++RSI) { + // Create a new read representing the expanded sequence. + OperReadsVariant.push_back( + SchedModels.findOrInsertRW(*RSI, /*IsRead=*/true)); + } + IdxVec ProcIndices(I->ProcIndices.begin(), I->ProcIndices.end()); + CodeGenSchedTransition SCTrans; + SCTrans.ToClassIdx = + SchedModels.addSchedClass(OperWritesVariant, OperReadsVariant, + ProcIndices); + SCTrans.ProcIndices = ProcIndices; + // The final PredTerm is unique set of predicates guarding the transition. + RecVec Preds; + for (SmallVectorImpl<PredCheck>::const_iterator + PI = I->PredTerm.begin(), PE = I->PredTerm.end(); PI != PE; ++PI) { + Preds.push_back(PI->Predicate); + } + RecIter PredsEnd = std::unique(Preds.begin(), Preds.end()); + Preds.resize(PredsEnd - Preds.begin()); + SCTrans.PredTerm = Preds; + SchedModels.getSchedClass(FromClassIdx).Transitions.push_back(SCTrans); + } +} + +// Create new SchedClasses for the given ReadWrite list. If any of the +// ReadWrites refers to a SchedVariant, create a new SchedClass for each variant +// of the ReadWrite list, following Aliases if necessary. +void CodeGenSchedModels::inferFromRW(const IdxVec &OperWrites, + const IdxVec &OperReads, + unsigned FromClassIdx, + const IdxVec &ProcIndices) { + DEBUG(dbgs() << "INFER RW: "); + + // Create a seed transition with an empty PredTerm and the expanded sequences + // of SchedWrites for the current SchedClass. + std::vector<PredTransition> LastTransitions; + LastTransitions.resize(1); + LastTransitions.back().ProcIndices.append(ProcIndices.begin(), + ProcIndices.end()); + + for (IdxIter I = OperWrites.begin(), E = OperWrites.end(); I != E; ++I) { + IdxVec WriteSeq; + expandRWSequence(*I, WriteSeq, /*IsRead=*/false); + unsigned Idx = LastTransitions[0].WriteSequences.size(); + LastTransitions[0].WriteSequences.resize(Idx + 1); + SmallVectorImpl<unsigned> &Seq = LastTransitions[0].WriteSequences[Idx]; + for (IdxIter WI = WriteSeq.begin(), WE = WriteSeq.end(); WI != WE; ++WI) + Seq.push_back(*WI); + DEBUG(dbgs() << "("; dumpIdxVec(Seq); dbgs() << ") "); + } + DEBUG(dbgs() << " Reads: "); + for (IdxIter I = OperReads.begin(), E = OperReads.end(); I != E; ++I) { + IdxVec ReadSeq; + expandRWSequence(*I, ReadSeq, /*IsRead=*/true); + unsigned Idx = LastTransitions[0].ReadSequences.size(); + LastTransitions[0].ReadSequences.resize(Idx + 1); + SmallVectorImpl<unsigned> &Seq = LastTransitions[0].ReadSequences[Idx]; + for (IdxIter RI = ReadSeq.begin(), RE = ReadSeq.end(); RI != RE; ++RI) + Seq.push_back(*RI); + DEBUG(dbgs() << "("; dumpIdxVec(Seq); dbgs() << ") "); + } + DEBUG(dbgs() << '\n'); + + // Collect all PredTransitions for individual operands. + // Iterate until no variant writes remain. + while (hasVariant(LastTransitions, *this)) { + PredTransitions Transitions(*this); + for (std::vector<PredTransition>::const_iterator + I = LastTransitions.begin(), E = LastTransitions.end(); + I != E; ++I) { + Transitions.substituteVariants(*I); + } + DEBUG(Transitions.dump()); + LastTransitions.swap(Transitions.TransVec); + } + // If the first transition has no variants, nothing to do. + if (LastTransitions[0].PredTerm.empty()) return; - HasProcItineraries = true; + // WARNING: We are about to mutate the SchedClasses vector. Do not refer to + // OperWrites, OperReads, or ProcIndices after calling inferFromTransitions. + inferFromTransitions(LastTransitions, FromClassIdx, *this); +} - ProcModel.ItinDefList.resize(NumItineraryClasses+1); +// Collect and sort WriteRes, ReadAdvance, and ProcResources. +void CodeGenSchedModels::collectProcResources() { + // Add any subtarget-specific SchedReadWrites that are directly associated + // with processor resources. Refer to the parent SchedClass's ProcIndices to + // determine which processors they apply to. + for (SchedClassIter SCI = schedClassBegin(), SCE = schedClassEnd(); + SCI != SCE; ++SCI) { + if (SCI->ItinClassDef) + collectItinProcResources(SCI->ItinClassDef); + else + collectRWResources(SCI->Writes, SCI->Reads, SCI->ProcIndices); + } + // Add resources separately defined by each subtarget. + RecVec WRDefs = Records.getAllDerivedDefinitions("WriteRes"); + for (RecIter WRI = WRDefs.begin(), WRE = WRDefs.end(); WRI != WRE; ++WRI) { + Record *ModelDef = (*WRI)->getValueAsDef("SchedModel"); + addWriteRes(*WRI, getProcModel(ModelDef).Index); + } + RecVec RADefs = Records.getAllDerivedDefinitions("ReadAdvance"); + for (RecIter RAI = RADefs.begin(), RAE = RADefs.end(); RAI != RAE; ++RAI) { + Record *ModelDef = (*RAI)->getValueAsDef("SchedModel"); + addReadAdvance(*RAI, getProcModel(ModelDef).Index); + } + // Finalize each ProcModel by sorting the record arrays. + for (unsigned PIdx = 0, PEnd = ProcModels.size(); PIdx != PEnd; ++PIdx) { + CodeGenProcModel &PM = ProcModels[PIdx]; + std::sort(PM.WriteResDefs.begin(), PM.WriteResDefs.end(), + LessRecord()); + std::sort(PM.ReadAdvanceDefs.begin(), PM.ReadAdvanceDefs.end(), + LessRecord()); + std::sort(PM.ProcResourceDefs.begin(), PM.ProcResourceDefs.end(), + LessRecord()); + DEBUG( + PM.dump(); + dbgs() << "WriteResDefs: "; + for (RecIter RI = PM.WriteResDefs.begin(), + RE = PM.WriteResDefs.end(); RI != RE; ++RI) { + if ((*RI)->isSubClassOf("WriteRes")) + dbgs() << (*RI)->getValueAsDef("WriteType")->getName() << " "; + else + dbgs() << (*RI)->getName() << " "; + } + dbgs() << "\nReadAdvanceDefs: "; + for (RecIter RI = PM.ReadAdvanceDefs.begin(), + RE = PM.ReadAdvanceDefs.end(); RI != RE; ++RI) { + if ((*RI)->isSubClassOf("ReadAdvance")) + dbgs() << (*RI)->getValueAsDef("ReadType")->getName() << " "; + else + dbgs() << (*RI)->getName() << " "; + } + dbgs() << "\nProcResourceDefs: "; + for (RecIter RI = PM.ProcResourceDefs.begin(), + RE = PM.ProcResourceDefs.end(); RI != RE; ++RI) { + dbgs() << (*RI)->getName() << " "; + } + dbgs() << '\n'); + } +} - // Insert each itinerary data record in the correct position within - // the processor model's ItinDefList. - for (unsigned i = 0, N = ItinRecords.size(); i < N; i++) { - Record *ItinData = ItinRecords[i]; - Record *ItinDef = ItinData->getValueAsDef("TheClass"); - if (!SchedClassIdxMap.count(ItinDef->getName())) { - DEBUG(dbgs() << ProcModel.ItinsDef->getName() - << " has unused itinerary class " << ItinDef->getName() << '\n'); - continue; +// Collect itinerary class resources for each processor. +void CodeGenSchedModels::collectItinProcResources(Record *ItinClassDef) { + for (unsigned PIdx = 0, PEnd = ProcModels.size(); PIdx != PEnd; ++PIdx) { + const CodeGenProcModel &PM = ProcModels[PIdx]; + // For all ItinRW entries. + bool HasMatch = false; + for (RecIter II = PM.ItinRWDefs.begin(), IE = PM.ItinRWDefs.end(); + II != IE; ++II) { + RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses"); + if (!std::count(Matched.begin(), Matched.end(), ItinClassDef)) + continue; + if (HasMatch) + PrintFatalError((*II)->getLoc(), "Duplicate itinerary class " + + ItinClassDef->getName() + + " in ItinResources for " + PM.ModelName); + HasMatch = true; + IdxVec Writes, Reads; + findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); + IdxVec ProcIndices(1, PIdx); + collectRWResources(Writes, Reads, ProcIndices); + } + } +} + +void CodeGenSchedModels::collectRWResources(unsigned RWIdx, bool IsRead, + const IdxVec &ProcIndices) { + const CodeGenSchedRW &SchedRW = getSchedRW(RWIdx, IsRead); + if (SchedRW.TheDef) { + if (!IsRead && SchedRW.TheDef->isSubClassOf("SchedWriteRes")) { + for (IdxIter PI = ProcIndices.begin(), PE = ProcIndices.end(); + PI != PE; ++PI) { + addWriteRes(SchedRW.TheDef, *PI); + } + } + else if (IsRead && SchedRW.TheDef->isSubClassOf("SchedReadAdvance")) { + for (IdxIter PI = ProcIndices.begin(), PE = ProcIndices.end(); + PI != PE; ++PI) { + addReadAdvance(SchedRW.TheDef, *PI); + } + } + } + for (RecIter AI = SchedRW.Aliases.begin(), AE = SchedRW.Aliases.end(); + AI != AE; ++AI) { + IdxVec AliasProcIndices; + if ((*AI)->getValueInit("SchedModel")->isComplete()) { + AliasProcIndices.push_back( + getProcModel((*AI)->getValueAsDef("SchedModel")).Index); + } + else + AliasProcIndices = ProcIndices; + const CodeGenSchedRW &AliasRW = getSchedRW((*AI)->getValueAsDef("AliasRW")); + assert(AliasRW.IsRead == IsRead && "cannot alias reads to writes"); + + IdxVec ExpandedRWs; + expandRWSequence(AliasRW.Index, ExpandedRWs, IsRead); + for (IdxIter SI = ExpandedRWs.begin(), SE = ExpandedRWs.end(); + SI != SE; ++SI) { + collectRWResources(*SI, IsRead, AliasProcIndices); + } + } +} + +// Collect resources for a set of read/write types and processor indices. +void CodeGenSchedModels::collectRWResources(const IdxVec &Writes, + const IdxVec &Reads, + const IdxVec &ProcIndices) { + + for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI) + collectRWResources(*WI, /*IsRead=*/false, ProcIndices); + + for (IdxIter RI = Reads.begin(), RE = Reads.end(); RI != RE; ++RI) + collectRWResources(*RI, /*IsRead=*/true, ProcIndices); +} + + +// Find the processor's resource units for this kind of resource. +Record *CodeGenSchedModels::findProcResUnits(Record *ProcResKind, + const CodeGenProcModel &PM) const { + if (ProcResKind->isSubClassOf("ProcResourceUnits")) + return ProcResKind; + + Record *ProcUnitDef = 0; + RecVec ProcResourceDefs = + Records.getAllDerivedDefinitions("ProcResourceUnits"); + + for (RecIter RI = ProcResourceDefs.begin(), RE = ProcResourceDefs.end(); + RI != RE; ++RI) { + + if ((*RI)->getValueAsDef("Kind") == ProcResKind + && (*RI)->getValueAsDef("SchedModel") == PM.ModelDef) { + if (ProcUnitDef) { + PrintFatalError((*RI)->getLoc(), + "Multiple ProcessorResourceUnits associated with " + + ProcResKind->getName()); + } + ProcUnitDef = *RI; } - ProcModel.ItinDefList[getItinClassIdx(ItinDef)] = ItinData; } + if (!ProcUnitDef) { + PrintFatalError(ProcResKind->getLoc(), + "No ProcessorResources associated with " + + ProcResKind->getName()); + } + return ProcUnitDef; +} + +// Iteratively add a resource and its super resources. +void CodeGenSchedModels::addProcResource(Record *ProcResKind, + CodeGenProcModel &PM) { + for (;;) { + Record *ProcResUnits = findProcResUnits(ProcResKind, PM); + + // See if this ProcResource is already associated with this processor. + RecIter I = std::find(PM.ProcResourceDefs.begin(), + PM.ProcResourceDefs.end(), ProcResUnits); + if (I != PM.ProcResourceDefs.end()) + return; + + PM.ProcResourceDefs.push_back(ProcResUnits); + if (!ProcResUnits->getValueInit("Super")->isComplete()) + return; + + ProcResKind = ProcResUnits->getValueAsDef("Super"); + } +} + +// Add resources for a SchedWrite to this processor if they don't exist. +void CodeGenSchedModels::addWriteRes(Record *ProcWriteResDef, unsigned PIdx) { + assert(PIdx && "don't add resources to an invalid Processor model"); + + RecVec &WRDefs = ProcModels[PIdx].WriteResDefs; + RecIter WRI = std::find(WRDefs.begin(), WRDefs.end(), ProcWriteResDef); + if (WRI != WRDefs.end()) + return; + WRDefs.push_back(ProcWriteResDef); + + // Visit ProcResourceKinds referenced by the newly discovered WriteRes. + RecVec ProcResDefs = ProcWriteResDef->getValueAsListOfDefs("ProcResources"); + for (RecIter WritePRI = ProcResDefs.begin(), WritePRE = ProcResDefs.end(); + WritePRI != WritePRE; ++WritePRI) { + addProcResource(*WritePRI, ProcModels[PIdx]); + } +} + +// Add resources for a ReadAdvance to this processor if they don't exist. +void CodeGenSchedModels::addReadAdvance(Record *ProcReadAdvanceDef, + unsigned PIdx) { + RecVec &RADefs = ProcModels[PIdx].ReadAdvanceDefs; + RecIter I = std::find(RADefs.begin(), RADefs.end(), ProcReadAdvanceDef); + if (I != RADefs.end()) + return; + RADefs.push_back(ProcReadAdvanceDef); +} + +unsigned CodeGenProcModel::getProcResourceIdx(Record *PRDef) const { + RecIter PRPos = std::find(ProcResourceDefs.begin(), ProcResourceDefs.end(), + PRDef); + if (PRPos == ProcResourceDefs.end()) + PrintFatalError(PRDef->getLoc(), "ProcResource def is not included in " + "the ProcResources list for " + ModelName); + // Idx=0 is reserved for invalid. + return 1 + (PRPos - ProcResourceDefs.begin()); +} + #ifndef NDEBUG - // Check for missing itinerary entries. - assert(!ProcModel.ItinDefList[0] && "NoItinerary class can't have rec"); - for (unsigned i = 1, N = ProcModel.ItinDefList.size(); i < N; ++i) { - if (!ProcModel.ItinDefList[i]) - DEBUG(dbgs() << ProcModel.ItinsDef->getName() - << " missing itinerary for class " << SchedClasses[i].Name << '\n'); +void CodeGenProcModel::dump() const { + dbgs() << Index << ": " << ModelName << " " + << (ModelDef ? ModelDef->getName() : "inferred") << " " + << (ItinsDef ? ItinsDef->getName() : "no itinerary") << '\n'; +} + +void CodeGenSchedRW::dump() const { + dbgs() << Name << (IsVariadic ? " (V) " : " "); + if (IsSequence) { + dbgs() << "("; + dumpIdxVec(Sequence); + dbgs() << ")"; + } +} + +void CodeGenSchedClass::dump(const CodeGenSchedModels* SchedModels) const { + dbgs() << "SCHEDCLASS " << Name << '\n' + << " Writes: "; + for (unsigned i = 0, N = Writes.size(); i < N; ++i) { + SchedModels->getSchedWrite(Writes[i]).dump(); + if (i < N-1) { + dbgs() << '\n'; + dbgs().indent(10); + } + } + dbgs() << "\n Reads: "; + for (unsigned i = 0, N = Reads.size(); i < N; ++i) { + SchedModels->getSchedRead(Reads[i]).dump(); + if (i < N-1) { + dbgs() << '\n'; + dbgs().indent(10); + } + } + dbgs() << "\n ProcIdx: "; dumpIdxVec(ProcIndices); dbgs() << '\n'; +} + +void PredTransitions::dump() const { + dbgs() << "Expanded Variants:\n"; + for (std::vector<PredTransition>::const_iterator + TI = TransVec.begin(), TE = TransVec.end(); TI != TE; ++TI) { + dbgs() << "{"; + for (SmallVectorImpl<PredCheck>::const_iterator + PCI = TI->PredTerm.begin(), PCE = TI->PredTerm.end(); + PCI != PCE; ++PCI) { + if (PCI != TI->PredTerm.begin()) + dbgs() << ", "; + dbgs() << SchedModels.getSchedRW(PCI->RWIdx, PCI->IsRead).Name + << ":" << PCI->Predicate->getName(); + } + dbgs() << "},\n => {"; + for (SmallVectorImpl<SmallVector<unsigned,4> >::const_iterator + WSI = TI->WriteSequences.begin(), WSE = TI->WriteSequences.end(); + WSI != WSE; ++WSI) { + dbgs() << "("; + for (SmallVectorImpl<unsigned>::const_iterator + WI = WSI->begin(), WE = WSI->end(); WI != WE; ++WI) { + if (WI != WSI->begin()) + dbgs() << ", "; + dbgs() << SchedModels.getSchedWrite(*WI).Name; + } + dbgs() << "),"; + } + dbgs() << "}\n"; } -#endif } +#endif // NDEBUG diff --git a/contrib/llvm/utils/TableGen/CodeGenSchedule.h b/contrib/llvm/utils/TableGen/CodeGenSchedule.h index 9da0145..eed0589 100644 --- a/contrib/llvm/utils/TableGen/CodeGenSchedule.h +++ b/contrib/llvm/utils/TableGen/CodeGenSchedule.h @@ -15,6 +15,7 @@ #ifndef CODEGEN_SCHEDULE_H #define CODEGEN_SCHEDULE_H +#include "SetTheory.h" #include "llvm/TableGen/Record.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/ADT/DenseMap.h" @@ -23,21 +24,131 @@ namespace llvm { class CodeGenTarget; +class CodeGenSchedModels; +class CodeGenInstruction; -// Scheduling class. -// -// Each instruction description will be mapped to a scheduling class. It may be -// an explicitly defined itinerary class, or an inferred class in which case -// ItinClassDef == NULL. +typedef std::vector<Record*> RecVec; +typedef std::vector<Record*>::const_iterator RecIter; + +typedef std::vector<unsigned> IdxVec; +typedef std::vector<unsigned>::const_iterator IdxIter; + +void splitSchedReadWrites(const RecVec &RWDefs, + RecVec &WriteDefs, RecVec &ReadDefs); + +/// We have two kinds of SchedReadWrites. Explicitly defined and inferred +/// sequences. TheDef is nonnull for explicit SchedWrites, but Sequence may or +/// may not be empty. TheDef is null for inferred sequences, and Sequence must +/// be nonempty. +/// +/// IsVariadic controls whether the variants are expanded into multiple operands +/// or a sequence of writes on one operand. +struct CodeGenSchedRW { + unsigned Index; + std::string Name; + Record *TheDef; + bool IsRead; + bool IsAlias; + bool HasVariants; + bool IsVariadic; + bool IsSequence; + IdxVec Sequence; + RecVec Aliases; + + CodeGenSchedRW(): Index(0), TheDef(0), IsAlias(false), HasVariants(false), + IsVariadic(false), IsSequence(false) {} + CodeGenSchedRW(unsigned Idx, Record *Def): Index(Idx), TheDef(Def), + IsAlias(false), IsVariadic(false) { + Name = Def->getName(); + IsRead = Def->isSubClassOf("SchedRead"); + HasVariants = Def->isSubClassOf("SchedVariant"); + if (HasVariants) + IsVariadic = Def->getValueAsBit("Variadic"); + + // Read records don't currently have sequences, but it can be easily + // added. Note that implicit Reads (from ReadVariant) may have a Sequence + // (but no record). + IsSequence = Def->isSubClassOf("WriteSequence"); + } + + CodeGenSchedRW(unsigned Idx, bool Read, const IdxVec &Seq, + const std::string &Name): + Index(Idx), Name(Name), TheDef(0), IsRead(Read), IsAlias(false), + HasVariants(false), IsVariadic(false), IsSequence(true), Sequence(Seq) { + assert(Sequence.size() > 1 && "implied sequence needs >1 RWs"); + } + + bool isValid() const { + assert((!HasVariants || TheDef) && "Variant write needs record def"); + assert((!IsVariadic || HasVariants) && "Variadic write needs variants"); + assert((!IsSequence || !HasVariants) && "Sequence can't have variant"); + assert((!IsSequence || !Sequence.empty()) && "Sequence should be nonempty"); + assert((!IsAlias || Aliases.empty()) && "Alias cannot have aliases"); + return TheDef || !Sequence.empty(); + } + +#ifndef NDEBUG + void dump() const; +#endif +}; + +/// Represent a transition between SchedClasses induced by SchedVariant. +struct CodeGenSchedTransition { + unsigned ToClassIdx; + IdxVec ProcIndices; + RecVec PredTerm; +}; + +/// Scheduling class. +/// +/// Each instruction description will be mapped to a scheduling class. There are +/// four types of classes: +/// +/// 1) An explicitly defined itinerary class with ItinClassDef set. +/// Writes and ReadDefs are empty. ProcIndices contains 0 for any processor. +/// +/// 2) An implied class with a list of SchedWrites and SchedReads that are +/// defined in an instruction definition and which are common across all +/// subtargets. ProcIndices contains 0 for any processor. +/// +/// 3) An implied class with a list of InstRW records that map instructions to +/// SchedWrites and SchedReads per-processor. InstrClassMap should map the same +/// instructions to this class. ProcIndices contains all the processors that +/// provided InstrRW records for this class. ItinClassDef or Writes/Reads may +/// still be defined for processors with no InstRW entry. +/// +/// 4) An inferred class represents a variant of another class that may be +/// resolved at runtime. ProcIndices contains the set of processors that may +/// require the class. ProcIndices are propagated through SchedClasses as +/// variants are expanded. Multiple SchedClasses may be inferred from an +/// itinerary class. Each inherits the processor index from the ItinRW record +/// that mapped the itinerary class to the variant Writes or Reads. struct CodeGenSchedClass { std::string Name; - unsigned Index; Record *ItinClassDef; - CodeGenSchedClass(): Index(0), ItinClassDef(0) {} - CodeGenSchedClass(Record *rec): Index(0), ItinClassDef(rec) { + IdxVec Writes; + IdxVec Reads; + // Sorted list of ProcIdx, where ProcIdx==0 implies any processor. + IdxVec ProcIndices; + + std::vector<CodeGenSchedTransition> Transitions; + + // InstRW records associated with this class. These records may refer to an + // Instruction no longer mapped to this class by InstrClassMap. These + // Instructions should be ignored by this class because they have been split + // off to join another inferred class. + RecVec InstRWs; + + CodeGenSchedClass(): ItinClassDef(0) {} + CodeGenSchedClass(Record *rec): ItinClassDef(rec) { Name = rec->getName(); + ProcIndices.push_back(0); } + +#ifndef NDEBUG + void dump(const CodeGenSchedModels *SchedModels) const; +#endif }; // Processor model. @@ -55,28 +166,69 @@ struct CodeGenSchedClass { // // ItinDefList orders this processor's InstrItinData records by SchedClass idx. struct CodeGenProcModel { + unsigned Index; std::string ModelName; Record *ModelDef; Record *ItinsDef; - // Array of InstrItinData records indexed by CodeGenSchedClass::Index. - // The list is empty if the subtarget has no itineraries. - std::vector<Record *> ItinDefList; + // Derived members... - CodeGenProcModel(const std::string &Name, Record *MDef, Record *IDef): - ModelName(Name), ModelDef(MDef), ItinsDef(IDef) {} + // Array of InstrItinData records indexed by a CodeGenSchedClass index. + // This list is empty if the Processor has no value for Itineraries. + // Initialized by collectProcItins(). + RecVec ItinDefList; + + // Map itinerary classes to per-operand resources. + // This list is empty if no ItinRW refers to this Processor. + RecVec ItinRWDefs; + + // All read/write resources associated with this processor. + RecVec WriteResDefs; + RecVec ReadAdvanceDefs; + + // Per-operand machine model resources associated with this processor. + RecVec ProcResourceDefs; + + CodeGenProcModel(unsigned Idx, const std::string &Name, Record *MDef, + Record *IDef) : + Index(Idx), ModelName(Name), ModelDef(MDef), ItinsDef(IDef) {} + + bool hasInstrSchedModel() const { + return !WriteResDefs.empty() || !ItinRWDefs.empty(); + } + + unsigned getProcResourceIdx(Record *PRDef) const; + +#ifndef NDEBUG + void dump() const; +#endif }; -// Top level container for machine model data. +/// Top level container for machine model data. class CodeGenSchedModels { RecordKeeper &Records; const CodeGenTarget &Target; + // Map dag expressions to Instruction lists. + SetTheory Sets; + + // List of unique processor models. + std::vector<CodeGenProcModel> ProcModels; + + // Map Processor's MachineModel or ProcItin to a CodeGenProcModel index. + typedef DenseMap<Record*, unsigned> ProcModelMapTy; + ProcModelMapTy ProcModelMap; + + // Per-operand SchedReadWrite types. + std::vector<CodeGenSchedRW> SchedWrites; + std::vector<CodeGenSchedRW> SchedReads; + // List of unique SchedClasses. std::vector<CodeGenSchedClass> SchedClasses; // Map SchedClass name to itinerary index. - // These are either explicit itinerary classes or inferred classes. + // These are either explicit itinerary classes or classes implied by + // instruction definitions with SchedReadWrite lists. StringMap<unsigned> SchedClassIdxMap; // SchedClass indices 1 up to and including NumItineraryClasses identify @@ -84,22 +236,80 @@ class CodeGenSchedModels { // definitions. NoItinerary always has index 0 regardless of whether it is // explicitly referenced. // - // Any inferred SchedClass have a index greater than NumItineraryClasses. + // Any implied SchedClass has an index greater than NumItineraryClasses. unsigned NumItineraryClasses; - // List of unique processor models. - std::vector<CodeGenProcModel> ProcModels; - - // Map Processor's MachineModel + ProcItin fields to a CodeGenProcModel index. - typedef DenseMap<std::pair<Record*, Record*>, unsigned> ProcModelMapTy; - ProcModelMapTy ProcModelMap; + // Any inferred SchedClass has an index greater than NumInstrSchedClassses. + unsigned NumInstrSchedClasses; - // True if any processors have nonempty itineraries. - bool HasProcItineraries; + // Map Instruction to SchedClass index. Only for Instructions mentioned in + // InstRW records. + typedef DenseMap<Record*, unsigned> InstClassMapTy; + InstClassMapTy InstrClassMap; public: CodeGenSchedModels(RecordKeeper& RK, const CodeGenTarget &TGT); + Record *getModelOrItinDef(Record *ProcDef) const { + Record *ModelDef = ProcDef->getValueAsDef("SchedModel"); + Record *ItinsDef = ProcDef->getValueAsDef("ProcItin"); + if (!ItinsDef->getValueAsListOfDefs("IID").empty()) { + assert(ModelDef->getValueAsBit("NoModel") + && "Itineraries must be defined within SchedMachineModel"); + return ItinsDef; + } + return ModelDef; + } + + const CodeGenProcModel &getModelForProc(Record *ProcDef) const { + Record *ModelDef = getModelOrItinDef(ProcDef); + ProcModelMapTy::const_iterator I = ProcModelMap.find(ModelDef); + assert(I != ProcModelMap.end() && "missing machine model"); + return ProcModels[I->second]; + } + + const CodeGenProcModel &getProcModel(Record *ModelDef) const { + ProcModelMapTy::const_iterator I = ProcModelMap.find(ModelDef); + assert(I != ProcModelMap.end() && "missing machine model"); + return ProcModels[I->second]; + } + + // Iterate over the unique processor models. + typedef std::vector<CodeGenProcModel>::const_iterator ProcIter; + ProcIter procModelBegin() const { return ProcModels.begin(); } + ProcIter procModelEnd() const { return ProcModels.end(); } + + // Get a SchedWrite from its index. + const CodeGenSchedRW &getSchedWrite(unsigned Idx) const { + assert(Idx < SchedWrites.size() && "bad SchedWrite index"); + assert(SchedWrites[Idx].isValid() && "invalid SchedWrite"); + return SchedWrites[Idx]; + } + // Get a SchedWrite from its index. + const CodeGenSchedRW &getSchedRead(unsigned Idx) const { + assert(Idx < SchedReads.size() && "bad SchedRead index"); + assert(SchedReads[Idx].isValid() && "invalid SchedRead"); + return SchedReads[Idx]; + } + + const CodeGenSchedRW &getSchedRW(unsigned Idx, bool IsRead) const { + return IsRead ? getSchedRead(Idx) : getSchedWrite(Idx); + } + CodeGenSchedRW &getSchedRW(Record *Def) { + bool IsRead = Def->isSubClassOf("SchedRead"); + unsigned Idx = getSchedRWIdx(Def, IsRead); + return const_cast<CodeGenSchedRW&>( + IsRead ? getSchedRead(Idx) : getSchedWrite(Idx)); + } + const CodeGenSchedRW &getSchedRW(Record*Def) const { + return const_cast<CodeGenSchedModels&>(*this).getSchedRW(Def); + } + + unsigned getSchedRWIdx(Record *Def, bool IsRead, unsigned After = 0) const; + + // Return true if the given write record is referenced by a ReadAdvance. + bool hasReadOfWrite(Record *WriteDef) const; + // Check if any instructions are assigned to an explicit itinerary class other // than NoItinerary. bool hasItineraryClasses() const { return NumItineraryClasses > 0; } @@ -111,60 +321,90 @@ public: } // Get a SchedClass from its index. - const CodeGenSchedClass &getSchedClass(unsigned Idx) { + CodeGenSchedClass &getSchedClass(unsigned Idx) { assert(Idx < SchedClasses.size() && "bad SchedClass index"); return SchedClasses[Idx]; } - - // Get an itinerary class's index. Value indices are '0' for NoItinerary up to - // and including numItineraryClasses(). - unsigned getItinClassIdx(Record *ItinDef) const { - assert(SchedClassIdxMap.count(ItinDef->getName()) && "missing ItinClass"); - unsigned Idx = SchedClassIdxMap.lookup(ItinDef->getName()); - assert(Idx <= NumItineraryClasses && "bad ItinClass index"); - return Idx; + const CodeGenSchedClass &getSchedClass(unsigned Idx) const { + assert(Idx < SchedClasses.size() && "bad SchedClass index"); + return SchedClasses[Idx]; } - bool hasProcessorItineraries() const { - return HasProcItineraries; - } + // Get the SchedClass index for an instruction. Instructions with no + // itinerary, no SchedReadWrites, and no InstrReadWrites references return 0 + // for NoItinerary. + unsigned getSchedClassIdx(const CodeGenInstruction &Inst) const; + + unsigned getSchedClassIdx(const RecVec &RWDefs) const; - // Get an existing machine model for a processor definition. - const CodeGenProcModel &getProcModel(Record *ProcDef) const { - unsigned idx = getProcModelIdx(ProcDef); - assert(idx < ProcModels.size() && "missing machine model"); - return ProcModels[idx]; + unsigned getSchedClassIdxForItin(const Record *ItinDef) { + return SchedClassIdxMap[ItinDef->getName()]; } - // Iterate over the unique processor models. - typedef std::vector<CodeGenProcModel>::const_iterator ProcIter; - ProcIter procModelBegin() const { return ProcModels.begin(); } - ProcIter procModelEnd() const { return ProcModels.end(); } + typedef std::vector<CodeGenSchedClass>::const_iterator SchedClassIter; + SchedClassIter schedClassBegin() const { return SchedClasses.begin(); } + SchedClassIter schedClassEnd() const { return SchedClasses.end(); } -private: - // Get a key that can uniquely identify a machine model. - ProcModelMapTy::key_type getProcModelKey(Record *ProcDef) const { - Record *ModelDef = ProcDef->getValueAsDef("SchedModel"); - Record *ItinsDef = ProcDef->getValueAsDef("ProcItin"); - return std::make_pair(ModelDef, ItinsDef); - } + void findRWs(const RecVec &RWDefs, IdxVec &Writes, IdxVec &Reads) const; + void findRWs(const RecVec &RWDefs, IdxVec &RWs, bool IsRead) const; + void expandRWSequence(unsigned RWIdx, IdxVec &RWSeq, bool IsRead) const; + void expandRWSeqForProc(unsigned RWIdx, IdxVec &RWSeq, bool IsRead, + const CodeGenProcModel &ProcModel) const; - // Get the unique index of a machine model. - unsigned getProcModelIdx(Record *ProcDef) const { - ProcModelMapTy::const_iterator I = - ProcModelMap.find(getProcModelKey(ProcDef)); - if (I == ProcModelMap.end()) - return ProcModels.size(); - return I->second; - } + unsigned addSchedClass(const IdxVec &OperWrites, const IdxVec &OperReads, + const IdxVec &ProcIndices); + + unsigned findOrInsertRW(ArrayRef<unsigned> Seq, bool IsRead); + + unsigned findSchedClassIdx(const IdxVec &Writes, const IdxVec &Reads) const; + + Record *findProcResUnits(Record *ProcResKind, + const CodeGenProcModel &PM) const; + +private: + void collectProcModels(); // Initialize a new processor model if it is unique. void addProcModel(Record *ProcDef); - void CollectSchedClasses(); - void CollectProcModels(); - void CollectProcItin(CodeGenProcModel &ProcModel, - std::vector<Record*> ItinRecords); + void collectSchedRW(); + + std::string genRWName(const IdxVec& Seq, bool IsRead); + unsigned findRWForSequence(const IdxVec &Seq, bool IsRead); + + void collectSchedClasses(); + + std::string createSchedClassName(const IdxVec &OperWrites, + const IdxVec &OperReads); + std::string createSchedClassName(const RecVec &InstDefs); + void createInstRWClass(Record *InstRWDef); + + void collectProcItins(); + + void collectProcItinRW(); + + void inferSchedClasses(); + + void inferFromRW(const IdxVec &OperWrites, const IdxVec &OperReads, + unsigned FromClassIdx, const IdxVec &ProcIndices); + void inferFromItinClass(Record *ItinClassDef, unsigned FromClassIdx); + void inferFromInstRWs(unsigned SCIdx); + + void collectProcResources(); + + void collectItinProcResources(Record *ItinClassDef); + + void collectRWResources(unsigned RWIdx, bool IsRead, + const IdxVec &ProcIndices); + + void collectRWResources(const IdxVec &Writes, const IdxVec &Reads, + const IdxVec &ProcIndices); + + void addProcResource(Record *ProcResourceKind, CodeGenProcModel &PM); + + void addWriteRes(Record *ProcWriteResDef, unsigned PIdx); + + void addReadAdvance(Record *ProcReadAdvanceDef, unsigned PIdx); }; } // namespace llvm diff --git a/contrib/llvm/utils/TableGen/CodeGenTarget.cpp b/contrib/llvm/utils/TableGen/CodeGenTarget.cpp index 1dd2efc..c9992eb 100644 --- a/contrib/llvm/utils/TableGen/CodeGenTarget.cpp +++ b/contrib/llvm/utils/TableGen/CodeGenTarget.cpp @@ -10,13 +10,14 @@ // This class wraps target description classes used by the various code // generation TableGen backends. This makes it easier to access the data and // provides a single place that needs to check it for validity. All of these -// classes throw exceptions on error conditions. +// classes abort on error conditions. // //===----------------------------------------------------------------------===// #include "CodeGenTarget.h" #include "CodeGenIntrinsics.h" #include "CodeGenSchedule.h" +#include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/STLExtras.h" @@ -68,22 +69,30 @@ std::string llvm::getEnumName(MVT::SimpleValueType T) { case MVT::x86mmx: return "MVT::x86mmx"; case MVT::Glue: return "MVT::Glue"; case MVT::isVoid: return "MVT::isVoid"; + case MVT::v2i1: return "MVT::v2i1"; + case MVT::v4i1: return "MVT::v4i1"; + case MVT::v8i1: return "MVT::v8i1"; + case MVT::v16i1: return "MVT::v16i1"; case MVT::v2i8: return "MVT::v2i8"; case MVT::v4i8: return "MVT::v4i8"; case MVT::v8i8: return "MVT::v8i8"; case MVT::v16i8: return "MVT::v16i8"; case MVT::v32i8: return "MVT::v32i8"; + case MVT::v1i16: return "MVT::v1i16"; case MVT::v2i16: return "MVT::v2i16"; case MVT::v4i16: return "MVT::v4i16"; case MVT::v8i16: return "MVT::v8i16"; case MVT::v16i16: return "MVT::v16i16"; + case MVT::v1i32: return "MVT::v1i32"; case MVT::v2i32: return "MVT::v2i32"; case MVT::v4i32: return "MVT::v4i32"; case MVT::v8i32: return "MVT::v8i32"; + case MVT::v16i32: return "MVT::v16i32"; case MVT::v1i64: return "MVT::v1i64"; case MVT::v2i64: return "MVT::v2i64"; case MVT::v4i64: return "MVT::v4i64"; case MVT::v8i64: return "MVT::v8i64"; + case MVT::v16i64: return "MVT::v16i64"; case MVT::v2f16: return "MVT::v2f16"; case MVT::v2f32: return "MVT::v2f32"; case MVT::v4f32: return "MVT::v4f32"; @@ -116,9 +125,9 @@ CodeGenTarget::CodeGenTarget(RecordKeeper &records) : Records(records), RegBank(0), SchedModels(0) { std::vector<Record*> Targets = Records.getAllDerivedDefinitions("Target"); if (Targets.size() == 0) - throw std::string("ERROR: No 'Target' subclasses defined!"); + PrintFatalError("ERROR: No 'Target' subclasses defined!"); if (Targets.size() != 1) - throw std::string("ERROR: Multiple subclasses of Target defined!"); + PrintFatalError("ERROR: Multiple subclasses of Target defined!"); TargetRec = Targets[0]; } @@ -152,7 +161,7 @@ Record *CodeGenTarget::getInstructionSet() const { Record *CodeGenTarget::getAsmParser() const { std::vector<Record*> LI = TargetRec->getValueAsListOfDefs("AssemblyParsers"); if (AsmParserNum >= LI.size()) - throw "Target does not have an AsmParser #" + utostr(AsmParserNum) + "!"; + PrintFatalError("Target does not have an AsmParser #" + utostr(AsmParserNum) + "!"); return LI[AsmParserNum]; } @@ -163,7 +172,7 @@ 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) + "!"; + PrintFatalError("Target does not have an AsmParserVariant #" + utostr(i) + "!"); return LI[i]; } @@ -181,7 +190,7 @@ unsigned CodeGenTarget::getAsmParserVariantCount() const { Record *CodeGenTarget::getAsmWriter() const { std::vector<Record*> LI = TargetRec->getValueAsListOfDefs("AssemblyWriters"); if (AsmWriterNum >= LI.size()) - throw "Target does not have an AsmWriter #" + utostr(AsmWriterNum) + "!"; + PrintFatalError("Target does not have an AsmWriter #" + utostr(AsmWriterNum) + "!"); return LI[AsmWriterNum]; } @@ -199,12 +208,11 @@ void CodeGenTarget::ReadRegAltNameIndices() const { /// getRegisterByName - If there is a register with the specific AsmName, /// return it. const CodeGenRegister *CodeGenTarget::getRegisterByName(StringRef Name) const { - const std::vector<CodeGenRegister*> &Regs = getRegBank().getRegisters(); - for (unsigned i = 0, e = Regs.size(); i != e; ++i) - if (Regs[i]->TheDef->getValueAsString("AsmName") == Name) - return Regs[i]; - - return 0; + const StringMap<CodeGenRegister*> &Regs = getRegBank().getRegistersByName(); + StringMap<CodeGenRegister*>::const_iterator I = Regs.find(Name); + if (I == Regs.end()) + return 0; + return I->second; } std::vector<MVT::SimpleValueType> CodeGenTarget:: @@ -249,7 +257,7 @@ CodeGenSchedModels &CodeGenTarget::getSchedModels() const { void CodeGenTarget::ReadInstructions() const { std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction"); if (Insts.size() <= 2) - throw std::string("No 'Instruction' subclasses defined!"); + PrintFatalError("No 'Instruction' subclasses defined!"); // Parse the instructions defined in the .td file. for (unsigned i = 0, e = Insts.size(); i != e; ++i) @@ -265,7 +273,7 @@ GetInstByName(const char *Name, DenseMap<const Record*, CodeGenInstruction*>::const_iterator I = Insts.find(Rec); if (Rec == 0 || I == Insts.end()) - throw std::string("Could not find '") + Name + "' instruction!"; + PrintFatalError(std::string("Could not find '") + Name + "' instruction!"); return I->second; } @@ -300,6 +308,8 @@ void CodeGenTarget::ComputeInstrsByEnum() const { "REG_SEQUENCE", "COPY", "BUNDLE", + "LIFETIME_START", + "LIFETIME_END", 0 }; const DenseMap<const Record*, CodeGenInstruction*> &Insts = getInstructions(); @@ -334,6 +344,15 @@ bool CodeGenTarget::isLittleEndianEncoding() const { return getInstructionSet()->getValueAsBit("isLittleEndianEncoding"); } +/// guessInstructionProperties - Return true if it's OK to guess instruction +/// properties instead of raising an error. +/// +/// This is configurable as a temporary migration aid. It will eventually be +/// permanently false. +bool CodeGenTarget::guessInstructionProperties() const { + return getInstructionSet()->getValueAsBit("guessInstructionProperties"); +} + //===----------------------------------------------------------------------===// // ComplexPattern implementation // @@ -401,7 +420,7 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { if (DefName.size() <= 4 || std::string(DefName.begin(), DefName.begin() + 4) != "int_") - throw "Intrinsic '" + DefName + "' does not start with 'int_'!"; + PrintFatalError("Intrinsic '" + DefName + "' does not start with 'int_'!"); EnumName = std::string(DefName.begin()+4, DefName.end()); @@ -421,7 +440,7 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { // Verify it starts with "llvm.". if (Name.size() <= 5 || std::string(Name.begin(), Name.begin() + 5) != "llvm.") - throw "Intrinsic '" + DefName + "'s name does not start with 'llvm.'!"; + PrintFatalError("Intrinsic '" + DefName + "'s name does not start with 'llvm.'!"); } // If TargetPrefix is specified, make sure that Name starts with @@ -430,8 +449,8 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { if (Name.size() < 6+TargetPrefix.size() || std::string(Name.begin() + 5, Name.begin() + 6 + TargetPrefix.size()) != (TargetPrefix + ".")) - throw "Intrinsic '" + DefName + "' does not start with 'llvm." + - TargetPrefix + ".'!"; + PrintFatalError("Intrinsic '" + DefName + "' does not start with 'llvm." + + TargetPrefix + ".'!"); } // Parse the list of return types. @@ -463,7 +482,7 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { // Reject invalid types. if (VT == MVT::isVoid) - throw "Intrinsic '" + DefName + " has void in result type list!"; + PrintFatalError("Intrinsic '" + DefName + " has void in result type list!"); IS.RetVTs.push_back(VT); IS.RetTypeDefs.push_back(TyEl); @@ -497,7 +516,7 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { // Reject invalid types. if (VT == MVT::isVoid && i != e-1 /*void at end means varargs*/) - throw "Intrinsic '" + DefName + " has void in result type list!"; + PrintFatalError("Intrinsic '" + DefName + " has void in result type list!"); IS.ParamVTs.push_back(VT); IS.ParamTypeDefs.push_back(TyEl); diff --git a/contrib/llvm/utils/TableGen/CodeGenTarget.h b/contrib/llvm/utils/TableGen/CodeGenTarget.h index 2f8cee4..ddeecee 100644 --- a/contrib/llvm/utils/TableGen/CodeGenTarget.h +++ b/contrib/llvm/utils/TableGen/CodeGenTarget.h @@ -9,8 +9,8 @@ // // This file defines wrappers for the Target class and related global // functionality. This makes it easier to access the data and provides a single -// place that needs to check it for validity. All of these classes throw -// exceptions on error conditions. +// place that needs to check it for validity. All of these classes abort +// on error conditions. // //===----------------------------------------------------------------------===// @@ -177,6 +177,10 @@ public: /// bool isLittleEndianEncoding() const; + /// guessInstructionProperties - should we just guess unset instruction + /// properties? + bool guessInstructionProperties() const; + private: void ComputeInstrsByEnum() const; }; diff --git a/contrib/llvm/utils/TableGen/DAGISelMatcher.h b/contrib/llvm/utils/TableGen/DAGISelMatcher.h index 3ca16f0..7c6ce3b 100644 --- a/contrib/llvm/utils/TableGen/DAGISelMatcher.h +++ b/contrib/llvm/utils/TableGen/DAGISelMatcher.h @@ -99,8 +99,6 @@ public: OwningPtr<Matcher> &getNextPtr() { return Next; } - static inline bool classof(const Matcher *) { return true; } - bool isEqual(const Matcher *M) const { if (getKind() != M->getKind()) return false; return isEqualImpl(M); diff --git a/contrib/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp b/contrib/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp index 1445edb..713f174 100644 --- a/contrib/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp +++ b/contrib/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp @@ -598,7 +598,7 @@ EmitMatcherList(const Matcher *N, unsigned Indent, unsigned CurrentIdx, void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) { // Emit pattern predicates. if (!PatternPredicates.empty()) { - OS << "bool CheckPatternPredicate(unsigned PredNo) const {\n"; + OS << "virtual bool CheckPatternPredicate(unsigned PredNo) const {\n"; OS << " switch (PredNo) {\n"; OS << " default: llvm_unreachable(\"Invalid predicate in table?\");\n"; for (unsigned i = 0, e = PatternPredicates.size(); i != e; ++i) @@ -616,7 +616,8 @@ void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) { PFsByName[I->first->getName()] = I->second; if (!NodePredicates.empty()) { - OS << "bool CheckNodePredicate(SDNode *Node, unsigned PredNo) const {\n"; + OS << "virtual bool CheckNodePredicate(SDNode *Node,\n"; + OS << " unsigned PredNo) const {\n"; OS << " switch (PredNo) {\n"; OS << " default: llvm_unreachable(\"Invalid predicate in table?\");\n"; for (unsigned i = 0, e = NodePredicates.size(); i != e; ++i) { @@ -635,8 +636,8 @@ void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) { // Emit CompletePattern matchers. // FIXME: This should be const. if (!ComplexPatterns.empty()) { - OS << "bool CheckComplexPattern(SDNode *Root, SDNode *Parent, SDValue N,\n"; - OS << " unsigned PatternNo,\n"; + OS << "virtual bool CheckComplexPattern(SDNode *Root, SDNode *Parent,\n"; + OS << " SDValue N, unsigned PatternNo,\n"; OS << " SmallVectorImpl<std::pair<SDValue, SDNode*> > &Result) {\n"; OS << " unsigned NextRes = Result.size();\n"; OS << " switch (PatternNo) {\n"; @@ -676,7 +677,7 @@ void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) { // Emit SDNodeXForm handlers. // FIXME: This should be const. if (!NodeXForms.empty()) { - OS << "SDValue RunSDNodeXForm(SDValue V, unsigned XFormNo) {\n"; + OS << "virtual SDValue RunSDNodeXForm(SDValue V, unsigned XFormNo) {\n"; OS << " switch (XFormNo) {\n"; OS << " default: llvm_unreachable(\"Invalid xform # in table?\");\n"; diff --git a/contrib/llvm/utils/TableGen/DAGISelMatcherGen.cpp b/contrib/llvm/utils/TableGen/DAGISelMatcherGen.cpp index aed222c..573f558 100644 --- a/contrib/llvm/utils/TableGen/DAGISelMatcherGen.cpp +++ b/contrib/llvm/utils/TableGen/DAGISelMatcherGen.cpp @@ -10,6 +10,7 @@ #include "DAGISelMatcher.h" #include "CodeGenDAGPatterns.h" #include "CodeGenRegisters.h" +#include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" @@ -172,15 +173,10 @@ void MatcherGen::InferPossibleTypes() { // diagnostics, which we know are impossible at this point. TreePattern &TP = *CGP.pf_begin()->second; - try { - bool MadeChange = true; - while (MadeChange) - MadeChange = PatWithNoTypes->ApplyTypeConstraints(TP, - true/*Ignore reg constraints*/); - } catch (...) { - errs() << "Type constraint application shouldn't fail!"; - abort(); - } + bool MadeChange = true; + while (MadeChange) + MadeChange = PatWithNoTypes->ApplyTypeConstraints(TP, + true/*Ignore reg constraints*/); } @@ -203,7 +199,7 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) { assert(N->isLeaf() && "Not a leaf?"); // Direct match against an integer constant. - if (IntInit *II = dynamic_cast<IntInit*>(N->getLeafValue())) { + if (IntInit *II = dyn_cast<IntInit>(N->getLeafValue())) { // If this is the root of the dag we're matching, we emit a redundant opcode // check to ensure that this gets folded into the normal top-level // OpcodeSwitch. @@ -215,7 +211,7 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) { return AddMatcher(new CheckIntegerMatcher(II->getValue())); } - DefInit *DI = dynamic_cast<DefInit*>(N->getLeafValue()); + DefInit *DI = dyn_cast<DefInit>(N->getLeafValue()); if (DI == 0) { errs() << "Unknown leaf kind: " << *N << "\n"; abort(); @@ -283,7 +279,7 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N, N->getOperator()->getName() == "or") && N->getChild(1)->isLeaf() && N->getChild(1)->getPredicateFns().empty() && N->getPredicateFns().empty()) { - if (IntInit *II = dynamic_cast<IntInit*>(N->getChild(1)->getLeafValue())) { + if (IntInit *II = dyn_cast<IntInit>(N->getChild(1)->getLeafValue())) { if (!isPowerOf2_32(II->getValue())) { // Don't bother with single bits. // If this is at the root of the pattern, we emit a redundant // CheckOpcode so that the following checks get factored properly under @@ -572,14 +568,14 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N, SmallVectorImpl<unsigned> &ResultOps) { assert(N->isLeaf() && "Must be a leaf"); - if (IntInit *II = dynamic_cast<IntInit*>(N->getLeafValue())) { + if (IntInit *II = dyn_cast<IntInit>(N->getLeafValue())) { AddMatcher(new EmitIntegerMatcher(II->getValue(), N->getType(0))); ResultOps.push_back(NextRecordedOperandNo++); return; } // If this is an explicit register reference, handle it. - if (DefInit *DI = dynamic_cast<DefInit*>(N->getLeafValue())) { + if (DefInit *DI = dyn_cast<DefInit>(N->getLeafValue())) { Record *Def = DI->getDef(); if (Def->isSubClassOf("Register")) { const CodeGenRegister *Reg = @@ -727,8 +723,7 @@ EmitResultInstructionAsOperand(const TreePatternNode *N, // Determine what to emit for this operand. Record *OperandNode = II.Operands[InstOpNo].Rec; - if ((OperandNode->isSubClassOf("PredicateOperand") || - OperandNode->isSubClassOf("OptionalDefOperand")) && + if (OperandNode->isSubClassOf("OperandWithDefaultOps") && !CGP.getDefaultOperand(OperandNode).DefaultOps.empty()) { // This is a predicate or optional def operand; emit the // 'default ops' operands. @@ -877,7 +872,7 @@ void MatcherGen::EmitResultOperand(const TreePatternNode *N, if (OpRec->isSubClassOf("SDNodeXForm")) return EmitResultSDNodeXFormAsOperand(N, ResultOps); errs() << "Unknown result node to emit code for: " << *N << '\n'; - throw std::string("Unknown node in result pattern!"); + PrintFatalError("Unknown node in result pattern!"); } void MatcherGen::EmitResultCode() { diff --git a/contrib/llvm/utils/TableGen/DFAPacketizerEmitter.cpp b/contrib/llvm/utils/TableGen/DFAPacketizerEmitter.cpp index 8bfecea..0ad25a5 100644 --- a/contrib/llvm/utils/TableGen/DFAPacketizerEmitter.cpp +++ b/contrib/llvm/utils/TableGen/DFAPacketizerEmitter.cpp @@ -17,6 +17,7 @@ #include "CodeGenTarget.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" #include <list> @@ -74,6 +75,8 @@ public: // Another way of thinking about this transition is we are mapping a NDFA with // two states [0x01] and [0x10] into a DFA with a single state [0x01, 0x10]. // +// A State instance also contains a collection of transitions from that state: +// a map from inputs to new states. // namespace { class State { @@ -82,10 +85,16 @@ class State { int stateNum; bool isInitial; std::set<unsigned> stateInfo; + typedef std::map<unsigned, State *> TransitionMap; + TransitionMap Transitions; State(); State(const State &S); + bool operator<(const State &s) const { + return stateNum < s.stateNum; + } + // // canAddInsnClass - Returns true if an instruction of type InsnClass is a // valid transition from this state, i.e., can an instruction of type InsnClass @@ -100,38 +109,18 @@ class State { // which are possible from this state (PossibleStates). // void AddInsnClass(unsigned InsnClass, std::set<unsigned> &PossibleStates); + // + // addTransition - Add a transition from this state given the input InsnClass + // + void addTransition(unsigned InsnClass, State *To); + // + // hasTransition - Returns true if there is a transition from this state + // given the input InsnClass + // + bool hasTransition(unsigned InsnClass); }; } // End anonymous namespace. - -namespace { -struct Transition { - public: - static int currentTransitionNum; - int transitionNum; - State *from; - unsigned input; - State *to; - - Transition(State *from_, unsigned input_, State *to_); -}; -} // End anonymous namespace. - - -// -// Comparators to keep set of states sorted. -// -namespace { -struct ltState { - bool operator()(const State *s1, const State *s2) const; -}; - -struct ltTransition { - bool operator()(const Transition *s1, const Transition *s2) const; -}; -} // End anonymous namespace. - - // // class DFA: deterministic finite automaton for processor resource tracking. // @@ -139,36 +128,19 @@ namespace { class DFA { public: DFA(); + ~DFA(); // Set of states. Need to keep this sorted to emit the transition table. - std::set<State*, ltState> states; + typedef std::set<State *, less_ptr<State> > StateSet; + StateSet states; - // Map from a state to the list of transitions with that state as source. - std::map<State*, std::set<Transition*, ltTransition>, ltState> - stateTransitions; State *currentState; - // Highest valued Input seen. - unsigned LargestInput; - // // Modify the DFA. // void initialize(); void addState(State *); - void addTransition(Transition *); - - // - // getTransition - Return the state when a transition is made from - // State From with Input I. If a transition is not found, return NULL. - // - State *getTransition(State *, unsigned); - - // - // isValidTransition: Predicate that checks if there is a valid transition - // from state From on input InsnClass. - // - bool isValidTransition(State *From, unsigned InsnClass); // // writeTable: Print out a table representing the DFA. @@ -179,7 +151,7 @@ public: // -// Constructors for State, Transition, and DFA +// Constructors and destructors for State and DFA // State::State() : stateNum(currentStateNum++), isInitial(false) {} @@ -189,22 +161,27 @@ State::State(const State &S) : stateNum(currentStateNum++), isInitial(S.isInitial), stateInfo(S.stateInfo) {} +DFA::DFA(): currentState(NULL) {} -Transition::Transition(State *from_, unsigned input_, State *to_) : - transitionNum(currentTransitionNum++), from(from_), input(input_), - to(to_) {} - - -DFA::DFA() : - LargestInput(0) {} - +DFA::~DFA() { + DeleteContainerPointers(states); +} -bool ltState::operator()(const State *s1, const State *s2) const { - return (s1->stateNum < s2->stateNum); +// +// addTransition - Add a transition from this state given the input InsnClass +// +void State::addTransition(unsigned InsnClass, State *To) { + assert(!Transitions.count(InsnClass) && + "Cannot have multiple transitions for the same input"); + Transitions[InsnClass] = To; } -bool ltTransition::operator()(const Transition *s1, const Transition *s2) const { - return (s1->input < s2->input); +// +// hasTransition - Returns true if there is a transition from this state +// given the input InsnClass +// +bool State::hasTransition(unsigned InsnClass) { + return Transitions.count(InsnClass) > 0; } // @@ -272,6 +249,7 @@ bool State::canAddInsnClass(unsigned InsnClass) const { void DFA::initialize() { + assert(currentState && "Missing current state"); currentState->isInitial = true; } @@ -282,47 +260,7 @@ void DFA::addState(State *S) { } -void DFA::addTransition(Transition *T) { - // Update LargestInput. - if (T->input > LargestInput) - LargestInput = T->input; - - // Add the new transition. - bool Added = stateTransitions[T->from].insert(T).second; - assert(Added && "Cannot have multiple states for the same input"); - (void)Added; -} - - -// -// getTransition - Return the state when a transition is made from -// State From with Input I. If a transition is not found, return NULL. -// -State *DFA::getTransition(State *From, unsigned I) { - // Do we have a transition from state From? - if (!stateTransitions.count(From)) - return NULL; - - // Do we have a transition from state From with Input I? - Transition TVal(NULL, I, NULL); - // Do not count this temporal instance - Transition::currentTransitionNum--; - std::set<Transition*, ltTransition>::iterator T = - stateTransitions[From].find(&TVal); - if (T != stateTransitions[From].end()) - return (*T)->to; - - return NULL; -} - - -bool DFA::isValidTransition(State *From, unsigned InsnClass) { - return (getTransition(From, InsnClass) != NULL); -} - - int State::currentStateNum = 0; -int Transition::currentTransitionNum = 0; DFAPacketizerEmitter::DFAPacketizerEmitter(RecordKeeper &R): TargetName(CodeGenTarget(R).getName()), @@ -341,7 +279,7 @@ DFAPacketizerEmitter::DFAPacketizerEmitter(RecordKeeper &R): // // void DFA::writeTableAndAPI(raw_ostream &OS, const std::string &TargetName) { - std::set<State*, ltState>::iterator SI = states.begin(); + DFA::StateSet::iterator SI = states.begin(); // This table provides a map to the beginning of the transitions for State s // in DFAStateInputTable. std::vector<int> StateEntry(states.size()); @@ -353,18 +291,16 @@ void DFA::writeTableAndAPI(raw_ostream &OS, const std::string &TargetName) { // to construct the StateEntry table. int ValidTransitions = 0; for (unsigned i = 0; i < states.size(); ++i, ++SI) { + assert (((*SI)->stateNum == (int) i) && "Mismatch in state numbers"); StateEntry[i] = ValidTransitions; - for (unsigned j = 0; j <= LargestInput; ++j) { - assert (((*SI)->stateNum == (int) i) && "Mismatch in state numbers"); - State *To = getTransition(*SI, j); - if (To == NULL) - continue; - - OS << "{" << j << ", " - << To->stateNum + for (State::TransitionMap::iterator + II = (*SI)->Transitions.begin(), IE = (*SI)->Transitions.end(); + II != IE; ++II) { + OS << "{" << II->first << ", " + << II->second->stateNum << "}, "; - ++ValidTransitions; } + ValidTransitions += (*SI)->Transitions.size(); // If there are no valid transitions from this stage, we need a sentinel // transition. @@ -539,7 +475,7 @@ void DFAPacketizerEmitter::run(raw_ostream &OS) { // If we haven't already created a transition for this input // and the state can accommodate this InsnClass, create a transition. // - if (!D.getTransition(current, InsnClass) && + if (!current->hasTransition(InsnClass) && current->canAddInsnClass(InsnClass)) { State *NewState = NULL; current->AddInsnClass(InsnClass, NewStateResources); @@ -559,10 +495,8 @@ void DFAPacketizerEmitter::run(raw_ostream &OS) { Visited[NewStateResources] = NewState; WorkList.push_back(NewState); } - - Transition *NewTransition = new Transition(current, InsnClass, - NewState); - D.addTransition(NewTransition); + + current->addTransition(InsnClass, NewState); } } } diff --git a/contrib/llvm/utils/TableGen/DisassemblerEmitter.cpp b/contrib/llvm/utils/TableGen/DisassemblerEmitter.cpp index 826465a..2d11d24 100644 --- a/contrib/llvm/utils/TableGen/DisassemblerEmitter.cpp +++ b/contrib/llvm/utils/TableGen/DisassemblerEmitter.cpp @@ -117,11 +117,9 @@ void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) { for (unsigned i = 0, e = numberedInstructions.size(); i != e; ++i) RecognizableInstr::processInstr(Tables, *numberedInstructions[i], i); - // FIXME: As long as we are using exceptions, might as well drop this to the - // actual conflict site. if (Tables.hasConflicts()) - throw TGError(Target.getTargetRecord()->getLoc(), - "Primary decode conflict"); + PrintFatalError(Target.getTargetRecord()->getLoc(), + "Primary decode conflict"); Tables.emit(OS); return; diff --git a/contrib/llvm/utils/TableGen/EDEmitter.cpp b/contrib/llvm/utils/TableGen/EDEmitter.cpp index 0c8b28d..ea25450 100644 --- a/contrib/llvm/utils/TableGen/EDEmitter.cpp +++ b/contrib/llvm/utils/TableGen/EDEmitter.cpp @@ -19,6 +19,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" #include <string> @@ -358,8 +359,8 @@ static int X86TypeFromOpName(LiteralConstantEmitter *type, /// X86PopulateOperands - Handles all the operands in an X86 instruction, adding /// the appropriate flags to their descriptors /// -/// @operandFlags - A reference the array of operand flag objects -/// @inst - The instruction to use as a source of information +/// \param operandTypes A reference the array of operand type objects +/// \param inst The instruction to use as a source of information static void X86PopulateOperands( LiteralConstantEmitter *(&operandTypes)[EDIS_MAX_OPERANDS], const CodeGenInstruction &inst) { @@ -385,11 +386,12 @@ static void X86PopulateOperands( /// decorate1 - Decorates a named operand with a new flag /// -/// @operandFlags - The array of operand flag objects, which don't have names -/// @inst - The CodeGenInstruction, which provides a way to translate -/// between names and operand indices -/// @opName - The name of the operand -/// @flag - The name of the flag to add +/// \param operandFlags The array of operand flag objects, which don't have +/// names +/// \param inst The CodeGenInstruction, which provides a way to +// translate between names and operand indices +/// \param opName The name of the operand +/// \param opFlag The name of the flag to add static inline void decorate1( FlagsConstantEmitter *(&operandFlags)[EDIS_MAX_OPERANDS], const CodeGenInstruction &inst, @@ -438,9 +440,9 @@ static inline void decorate1( /// instruction to determine what sort of an instruction it is and then adds /// the appropriate flags to the instruction and its operands /// -/// @arg instType - A reference to the type for the instruction as a whole -/// @arg operandFlags - A reference to the array of operand flag object pointers -/// @arg inst - A reference to the original instruction +/// \param instType A reference to the type for the instruction as a whole +/// \param operandFlags A reference to the array of operand flag object pointers +/// \param inst A reference to the original instruction static void X86ExtractSemantics( LiteralConstantEmitter &instType, FlagsConstantEmitter *(&operandFlags)[EDIS_MAX_OPERANDS], @@ -567,8 +569,8 @@ static void X86ExtractSemantics( /// ARMFlagFromOpName - Processes the name of a single ARM operand (which is /// actually its type) and translates it into an operand type /// -/// @arg type - The type object to set -/// @arg name - The name of the operand +/// \param type The type object to set +/// \param name The name of the operand static int ARMFlagFromOpName(LiteralConstantEmitter *type, const std::string &name) { REG("GPR"); @@ -750,8 +752,8 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type, /// ARMPopulateOperands - Handles all the operands in an ARM instruction, adding /// the appropriate flags to their descriptors /// -/// @operandFlags - A reference the array of operand flag objects -/// @inst - The instruction to use as a source of information +/// \param operandTypes A reference the array of operand type objects +/// \param inst The instruction to use as a source of information static void ARMPopulateOperands( LiteralConstantEmitter *(&operandTypes)[EDIS_MAX_OPERANDS], const CodeGenInstruction &inst) { @@ -776,7 +778,7 @@ static void ARMPopulateOperands( errs() << "Operand type: " << rec.getName() << '\n'; errs() << "Operand name: " << operandInfo.Name << '\n'; errs() << "Instruction name: " << inst.TheDef->getName() << '\n'; - throw("Unhandled type in EDEmitter"); + PrintFatalError("Unhandled type in EDEmitter"); } } } @@ -790,10 +792,10 @@ static void ARMPopulateOperands( /// instruction to determine what sort of an instruction it is and then adds /// the appropriate flags to the instruction and its operands /// -/// @arg instType - A reference to the type for the instruction as a whole -/// @arg operandTypes - A reference to the array of operand type object pointers -/// @arg operandFlags - A reference to the array of operand flag object pointers -/// @arg inst - A reference to the original instruction +/// \param instType A reference to the type for the instruction as a whole +/// \param operandTypes A reference to the array of operand type object pointers +/// \param operandFlags A reference to the array of operand flag object pointers +/// \param inst A reference to the original instruction static void ARMExtractSemantics( LiteralConstantEmitter &instType, LiteralConstantEmitter *(&operandTypes)[EDIS_MAX_OPERANDS], @@ -831,8 +833,8 @@ static void ARMExtractSemantics( /// populateInstInfo - Fills an array of InstInfos with information about each /// instruction in a target /// -/// @arg infoArray - The array of InstInfo objects to populate -/// @arg target - The CodeGenTarget to use as a source of instructions +/// \param infoArray The array of InstInfo objects to populate +/// \param target The CodeGenTarget to use as a source of instructions static void populateInstInfo(CompoundConstantEmitter &infoArray, CodeGenTarget &target) { const std::vector<const CodeGenInstruction*> &numberedInstructions = diff --git a/contrib/llvm/utils/TableGen/FastISelEmitter.cpp b/contrib/llvm/utils/TableGen/FastISelEmitter.cpp index ca784d0..8b1e7f9 100644 --- a/contrib/llvm/utils/TableGen/FastISelEmitter.cpp +++ b/contrib/llvm/utils/TableGen/FastISelEmitter.cpp @@ -245,7 +245,7 @@ struct OperandsSignature { if (Op->getType(0) != VT) return false; - DefInit *OpDI = dynamic_cast<DefInit*>(Op->getLeafValue()); + DefInit *OpDI = dyn_cast<DefInit>(Op->getLeafValue()); if (!OpDI) return false; Record *OpLeafRec = OpDI->getDef(); @@ -406,13 +406,12 @@ static std::string PhyRegForNode(TreePatternNode *Op, if (!Op->isLeaf()) return PhysReg; - DefInit *OpDI = dynamic_cast<DefInit*>(Op->getLeafValue()); - Record *OpLeafRec = OpDI->getDef(); + Record *OpLeafRec = cast<DefInit>(Op->getLeafValue())->getDef(); if (!OpLeafRec->isSubClassOf("Register")) return PhysReg; - PhysReg += static_cast<StringInit*>(OpLeafRec->getValue( \ - "Namespace")->getValue())->getValue(); + PhysReg += cast<StringInit>(OpLeafRec->getValue("Namespace")->getValue()) + ->getValue(); PhysReg += "::"; PhysReg += Target.getRegBank().getReg(OpLeafRec)->getName(); return PhysReg; @@ -473,7 +472,7 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) { // a bit too complicated for now. if (!Dst->getChild(1)->isLeaf()) continue; - DefInit *SR = dynamic_cast<DefInit*>(Dst->getChild(1)->getLeafValue()); + DefInit *SR = dyn_cast<DefInit>(Dst->getChild(1)->getLeafValue()); if (SR) SubRegNo = getQualifiedName(SR->getDef()); else @@ -550,7 +549,7 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) { }; if (SimplePatterns[Operands][OpcodeName][VT][RetVT].count(PredicateCheck)) - throw TGError(Pattern.getSrcRecord()->getLoc(), + PrintFatalError(Pattern.getSrcRecord()->getLoc(), "Duplicate record in FastISel table!"); SimplePatterns[Operands][OpcodeName][VT][RetVT][PredicateCheck] = Memo; diff --git a/contrib/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp b/contrib/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp index e89c393..5cabcad 100644 --- a/contrib/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp +++ b/contrib/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp @@ -15,6 +15,7 @@ #define DEBUG_TYPE "decoder-emitter" #include "CodeGenTarget.h" +#include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/SmallString.h" @@ -142,7 +143,7 @@ static int Value(bit_value_t V) { return ValueNotSet(V) ? -1 : (V == BIT_FALSE ? 0 : 1); } static bit_value_t bitFromBits(const BitsInit &bits, unsigned index) { - if (BitInit *bit = dynamic_cast<BitInit*>(bits.getBit(index))) + if (BitInit *bit = dyn_cast<BitInit>(bits.getBit(index))) return bit->getValue() ? BIT_TRUE : BIT_FALSE; // The bit is uninitialized. @@ -741,7 +742,7 @@ void FixedLenDecoderEmitter::emitTable(formatted_raw_ostream &OS, switch (*I) { default: - throw "invalid decode table opcode"; + PrintFatalError("invalid decode table opcode"); case MCD::OPC_ExtractField: { ++I; unsigned Start = *I++; @@ -1757,8 +1758,8 @@ static bool populateInstruction(const CodeGenInstruction &CGI, unsigned Opc, // for decoding register classes. // FIXME: This need to be extended to handle instructions with custom // decoder methods, and operands with (simple) MIOperandInfo's. - TypedInit *TI = dynamic_cast<TypedInit*>(NI->first); - RecordRecTy *Type = dynamic_cast<RecordRecTy*>(TI->getType()); + TypedInit *TI = cast<TypedInit>(NI->first); + RecordRecTy *Type = cast<RecordRecTy>(TI->getType()); Record *TypeRecord = Type->getRecord(); bool isReg = false; if (TypeRecord->isSubClassOf("RegisterOperand")) @@ -1770,7 +1771,7 @@ static bool populateInstruction(const CodeGenInstruction &CGI, unsigned Opc, RecordVal *DecoderString = TypeRecord->getValue("DecoderMethod"); StringInit *String = DecoderString ? - dynamic_cast<StringInit*>(DecoderString->getValue()) : 0; + dyn_cast<StringInit>(DecoderString->getValue()) : 0; if (!isReg && String && String->getValue() != "") Decoder = String->getValue(); @@ -1781,11 +1782,11 @@ static bool populateInstruction(const CodeGenInstruction &CGI, unsigned Opc, for (unsigned bi = 0; bi < Bits.getNumBits(); ++bi) { VarInit *Var = 0; - VarBitInit *BI = dynamic_cast<VarBitInit*>(Bits.getBit(bi)); + VarBitInit *BI = dyn_cast<VarBitInit>(Bits.getBit(bi)); if (BI) - Var = dynamic_cast<VarInit*>(BI->getVariable()); + Var = dyn_cast<VarInit>(BI->getBitVar()); else - Var = dynamic_cast<VarInit*>(Bits.getBit(bi)); + Var = dyn_cast<VarInit>(Bits.getBit(bi)); if (!Var) { if (Base != ~0U) { @@ -1882,7 +1883,7 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS) { << " uint64_t Bits = STI.getFeatureBits();\n" << "\n" << " const uint8_t *Ptr = DecodeTable;\n" - << " uint32_t CurFieldValue;\n" + << " uint32_t CurFieldValue = 0;\n" << " DecodeStatus S = MCDisassembler::Success;\n" << " for (;;) {\n" << " ptrdiff_t Loc = Ptr - DecodeTable;\n" diff --git a/contrib/llvm/utils/TableGen/InstrInfoEmitter.cpp b/contrib/llvm/utils/TableGen/InstrInfoEmitter.cpp index b41ad94..48d41d7 100644 --- a/contrib/llvm/utils/TableGen/InstrInfoEmitter.cpp +++ b/contrib/llvm/utils/TableGen/InstrInfoEmitter.cpp @@ -16,8 +16,10 @@ #include "CodeGenDAGPatterns.h" #include "CodeGenSchedule.h" #include "CodeGenTarget.h" +#include "TableGenBackends.h" #include "SequenceToOffsetTable.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" #include <algorithm> @@ -89,7 +91,7 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) { for (unsigned j = 0, e = Inst.Operands[i].MINumOperands; j != e; ++j) { OperandList.push_back(Inst.Operands[i]); - Record *OpR = dynamic_cast<DefInit*>(MIOI->getArg(j))->getDef(); + Record *OpR = cast<DefInit>(MIOI->getArg(j))->getDef(); OperandList.back().Rec = OpR; } } @@ -299,16 +301,15 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, const OperandInfoMapTy &OpInfo, raw_ostream &OS) { int MinOperands = 0; - if (!Inst.Operands.size() == 0) + if (!Inst.Operands.empty()) // Each logical operand can be multiple MI operands. MinOperands = Inst.Operands.back().MIOperandNo + Inst.Operands.back().MINumOperands; - Record *ItinDef = Inst.TheDef->getValueAsDef("Itinerary"); OS << " { "; OS << Num << ",\t" << MinOperands << ",\t" << Inst.Operands.NumDefs << ",\t" - << SchedModels.getItinClassIdx(ItinDef) << ",\t" + << SchedModels.getSchedClassIdx(Inst) << ",\t" << Inst.TheDef->getValueAsInt("Size") << ",\t0"; // Emit all of the target indepedent flags... @@ -343,13 +344,14 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, // Emit all of the target-specific flags... BitsInit *TSF = Inst.TheDef->getValueAsBitsInit("TSFlags"); - if (!TSF) throw "no TSFlags?"; + if (!TSF) + PrintFatalError("no TSFlags?"); uint64_t Value = 0; for (unsigned i = 0, e = TSF->getNumBits(); i != e; ++i) { - if (BitInit *Bit = dynamic_cast<BitInit*>(TSF->getBit(i))) + if (BitInit *Bit = dyn_cast<BitInit>(TSF->getBit(i))) Value |= uint64_t(Bit->getValue()) << i; else - throw "Invalid TSFlags bit in " + Inst.TheDef->getName(); + PrintFatalError("Invalid TSFlags bit in " + Inst.TheDef->getName()); } OS << ", 0x"; OS.write_hex(Value); @@ -416,6 +418,7 @@ namespace llvm { void EmitInstrInfo(RecordKeeper &RK, raw_ostream &OS) { InstrInfoEmitter(RK).run(OS); + EmitMapTable(RK, OS); } } // End llvm namespace diff --git a/contrib/llvm/utils/TableGen/IntrinsicEmitter.cpp b/contrib/llvm/utils/TableGen/IntrinsicEmitter.cpp index 155d1ab..fe55242 100644 --- a/contrib/llvm/utils/TableGen/IntrinsicEmitter.cpp +++ b/contrib/llvm/utils/TableGen/IntrinsicEmitter.cpp @@ -15,6 +15,7 @@ #include "CodeGenTarget.h" #include "SequenceToOffsetTable.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/StringMatcher.h" #include "llvm/TableGen/TableGenBackend.h" @@ -249,7 +250,7 @@ static void EncodeFixedValueType(MVT::SimpleValueType VT, if (EVT(VT).isInteger()) { unsigned BitWidth = EVT(VT).getSizeInBits(); switch (BitWidth) { - default: throw "unhandled integer type width in intrinsic!"; + default: PrintFatalError("unhandled integer type width in intrinsic!"); case 1: return Sig.push_back(IIT_I1); case 8: return Sig.push_back(IIT_I8); case 16: return Sig.push_back(IIT_I16); @@ -259,7 +260,7 @@ static void EncodeFixedValueType(MVT::SimpleValueType VT, } switch (VT) { - default: throw "unhandled MVT in intrinsic!"; + default: PrintFatalError("unhandled MVT in intrinsic!"); case MVT::f32: return Sig.push_back(IIT_F32); case MVT::f64: return Sig.push_back(IIT_F64); case MVT::Metadata: return Sig.push_back(IIT_METADATA); @@ -328,7 +329,7 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes, if (EVT(VT).isVector()) { EVT VVT = VT; switch (VVT.getVectorNumElements()) { - default: throw "unhandled vector type width in intrinsic!"; + default: PrintFatalError("unhandled vector type width in intrinsic!"); case 2: Sig.push_back(IIT_V2); break; case 4: Sig.push_back(IIT_V4); break; case 8: Sig.push_back(IIT_V8); break; @@ -510,10 +511,10 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) { OS << "// Add parameter attributes that are not common to all intrinsics.\n"; OS << "#ifdef GET_INTRINSIC_ATTRIBUTES\n"; if (TargetOnly) - OS << "static AttrListPtr getAttributes(" << TargetPrefix + OS << "static AttrListPtr getAttributes(LLVMContext &C, " << TargetPrefix << "Intrinsic::ID id) {\n"; else - OS << "AttrListPtr Intrinsic::getAttributes(ID id) {\n"; + OS << "AttrListPtr Intrinsic::getAttributes(LLVMContext &C, ID id) {\n"; // Compute the maximum number of attribute arguments and the map typedef std::map<const CodeGenIntrinsic*, unsigned, @@ -547,6 +548,7 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) { OS << " AttributeWithIndex AWI[" << maxArgAttrs+1 << "];\n"; OS << " unsigned NumAttrs = 0;\n"; OS << " if (id != 0) {\n"; + OS << " SmallVector<Attributes::AttrVal, 8> AttrVec;\n"; OS << " switch(IntrinsicsToAttributesMap[id - "; if (TargetOnly) OS << "Intrinsic::num_intrinsics"; @@ -564,58 +566,49 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) { unsigned numAttrs = 0; // 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; + unsigned ai = 0, ae = intrinsic.ArgumentAttributes.size(); + if (ae) { + while (ai != ae) { + unsigned argNo = intrinsic.ArgumentAttributes[ai].first; - OS << " AWI[" << numAttrs++ << "] = AttributeWithIndex::get(" - << argNo+1 << ", "; + OS << " AttrVec.clear();\n"; - bool moreThanOne = false; + do { + switch (intrinsic.ArgumentAttributes[ai].second) { + case CodeGenIntrinsic::NoCapture: + OS << " AttrVec.push_back(Attributes::NoCapture);\n"; + break; + } - do { - if (moreThanOne) OS << '|'; + ++ai; + } while (ai != ae && intrinsic.ArgumentAttributes[ai].first == argNo); - switch (intrinsic.ArgumentAttributes[ai].second) { - case CodeGenIntrinsic::NoCapture: - OS << "Attribute::NoCapture"; - break; - } - - ++ai; - moreThanOne = true; - } while (ai != ae && intrinsic.ArgumentAttributes[ai].first == argNo); - - OS << ");\n"; + OS << " AWI[" << numAttrs++ << "] = AttributeWithIndex::get(C, " + << argNo+1 << ", AttrVec);\n"; + } } ModRefKind modRef = getModRefKind(intrinsic); if (!intrinsic.canThrow || modRef || intrinsic.isNoReturn) { - OS << " AWI[" << numAttrs++ << "] = AttributeWithIndex::get(~0, "; - bool Emitted = false; - if (!intrinsic.canThrow) { - OS << "Attribute::NoUnwind"; - Emitted = true; - } - - if (intrinsic.isNoReturn) { - if (Emitted) OS << '|'; - OS << "Attribute::NoReturn"; - Emitted = true; - } + OS << " AttrVec.clear();\n"; + + if (!intrinsic.canThrow) + OS << " AttrVec.push_back(Attributes::NoUnwind);\n"; + if (intrinsic.isNoReturn) + OS << " AttrVec.push_back(Attributes::NoReturn);\n"; switch (modRef) { case MRK_none: break; case MRK_readonly: - if (Emitted) OS << '|'; - OS << "Attribute::ReadOnly"; + OS << " AttrVec.push_back(Attributes::ReadOnly);\n"; break; case MRK_readnone: - if (Emitted) OS << '|'; - OS << "Attribute::ReadNone"; + OS << " AttrVec.push_back(Attributes::ReadNone);\n"; break; } - OS << ");\n"; + OS << " AWI[" << numAttrs++ << "] = AttributeWithIndex::get(C, " + << "AttrListPtr::FunctionIndex, AttrVec);\n"; } if (numAttrs) { @@ -628,7 +621,7 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) { OS << " }\n"; OS << " }\n"; - OS << " return AttrListPtr::get(ArrayRef<AttributeWithIndex>(AWI, " + OS << " return AttrListPtr::get(C, ArrayRef<AttributeWithIndex>(AWI, " "NumAttrs));\n"; OS << "}\n"; OS << "#endif // GET_INTRINSIC_ATTRIBUTES\n\n"; @@ -700,8 +693,8 @@ EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints, if (!BIM.insert(std::make_pair(Ints[i].GCCBuiltinName, Ints[i].EnumName)).second) - throw "Intrinsic '" + Ints[i].TheDef->getName() + - "': duplicate GCC builtin name!"; + PrintFatalError("Intrinsic '" + Ints[i].TheDef->getName() + + "': duplicate GCC builtin name!"); } } diff --git a/contrib/llvm/utils/TableGen/PseudoLoweringEmitter.cpp b/contrib/llvm/utils/TableGen/PseudoLoweringEmitter.cpp index 8d9d419..64aaee7 100644 --- a/contrib/llvm/utils/TableGen/PseudoLoweringEmitter.cpp +++ b/contrib/llvm/utils/TableGen/PseudoLoweringEmitter.cpp @@ -74,7 +74,7 @@ addDagOperandMapping(Record *Rec, DagInit *Dag, CodeGenInstruction &Insn, IndexedMap<OpData> &OperandMap, unsigned BaseIdx) { unsigned OpsAdded = 0; for (unsigned i = 0, e = Dag->getNumArgs(); i != e; ++i) { - if (DefInit *DI = dynamic_cast<DefInit*>(Dag->getArg(i))) { + if (DefInit *DI = dyn_cast<DefInit>(Dag->getArg(i))) { // Physical register reference. Explicit check for the special case // "zero_reg" definition. if (DI->getDef()->isSubClassOf("Register") || @@ -90,7 +90,7 @@ addDagOperandMapping(Record *Rec, DagInit *Dag, CodeGenInstruction &Insn, // FIXME: We probably shouldn't ever get a non-zero BaseIdx here. assert(BaseIdx == 0 && "Named subargument in pseudo expansion?!"); if (DI->getDef() != Insn.Operands[BaseIdx + i].Rec) - throw TGError(Rec->getLoc(), + PrintFatalError(Rec->getLoc(), "Pseudo operand type '" + DI->getDef()->getName() + "' does not match expansion operand type '" + Insn.Operands[BaseIdx + i].Rec->getName() + "'"); @@ -100,11 +100,11 @@ addDagOperandMapping(Record *Rec, DagInit *Dag, CodeGenInstruction &Insn, for (unsigned I = 0, E = Insn.Operands[i].MINumOperands; I != E; ++I) OperandMap[BaseIdx + i + I].Kind = OpData::Operand; OpsAdded += Insn.Operands[i].MINumOperands; - } else if (IntInit *II = dynamic_cast<IntInit*>(Dag->getArg(i))) { + } else if (IntInit *II = dyn_cast<IntInit>(Dag->getArg(i))) { OperandMap[BaseIdx + i].Kind = OpData::Imm; OperandMap[BaseIdx + i].Data.Imm = II->getValue(); ++OpsAdded; - } else if (DagInit *SubDag = dynamic_cast<DagInit*>(Dag->getArg(i))) { + } else if (DagInit *SubDag = dyn_cast<DagInit>(Dag->getArg(i))) { // Just add the operands recursively. This is almost certainly // a constant value for a complex operand (> 1 MI operand). unsigned NewOps = @@ -127,24 +127,24 @@ void PseudoLoweringEmitter::evaluateExpansion(Record *Rec) { assert(Dag && "Missing result instruction in pseudo expansion!"); DEBUG(dbgs() << " Result: " << *Dag << "\n"); - DefInit *OpDef = dynamic_cast<DefInit*>(Dag->getOperator()); + DefInit *OpDef = dyn_cast<DefInit>(Dag->getOperator()); if (!OpDef) - throw TGError(Rec->getLoc(), Rec->getName() + + PrintFatalError(Rec->getLoc(), Rec->getName() + " has unexpected operator type!"); Record *Operator = OpDef->getDef(); if (!Operator->isSubClassOf("Instruction")) - throw TGError(Rec->getLoc(), "Pseudo result '" + Operator->getName() + - "' is not an instruction!"); + PrintFatalError(Rec->getLoc(), "Pseudo result '" + Operator->getName() + + "' is not an instruction!"); CodeGenInstruction Insn(Operator); if (Insn.isCodeGenOnly || Insn.isPseudo) - throw TGError(Rec->getLoc(), "Pseudo result '" + Operator->getName() + - "' cannot be another pseudo instruction!"); + PrintFatalError(Rec->getLoc(), "Pseudo result '" + Operator->getName() + + "' cannot be another pseudo instruction!"); if (Insn.Operands.size() != Dag->getNumArgs()) - throw TGError(Rec->getLoc(), "Pseudo result '" + Operator->getName() + - "' operand count mismatch"); + PrintFatalError(Rec->getLoc(), "Pseudo result '" + Operator->getName() + + "' operand count mismatch"); unsigned NumMIOperands = 0; for (unsigned i = 0, e = Insn.Operands.size(); i != e; ++i) @@ -156,7 +156,7 @@ void PseudoLoweringEmitter::evaluateExpansion(Record *Rec) { // If there are more operands that weren't in the DAG, they have to // be operands that have default values, or we have an error. Currently, - // PredicateOperand and OptionalDefOperand both have default values. + // Operands that are a sublass of OperandWithDefaultOp have default values. // Validate that each result pattern argument has a matching (by name) @@ -179,9 +179,9 @@ void PseudoLoweringEmitter::evaluateExpansion(Record *Rec) { StringMap<unsigned>::iterator SourceOp = SourceOperands.find(Dag->getArgName(i)); if (SourceOp == SourceOperands.end()) - throw TGError(Rec->getLoc(), - "Pseudo output operand '" + Dag->getArgName(i) + - "' has no matching source operand."); + PrintFatalError(Rec->getLoc(), + "Pseudo output operand '" + Dag->getArgName(i) + + "' has no matching source operand."); // Map the source operand to the destination operand index for each // MachineInstr operand. for (unsigned I = 0, E = Insn.Operands[i].MINumOperands; I != E; ++I) @@ -267,7 +267,7 @@ void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) { void PseudoLoweringEmitter::run(raw_ostream &o) { Record *ExpansionClass = Records.getClass("PseudoInstExpansion"); - Record *InstructionClass = Records.getClass("PseudoInstExpansion"); + Record *InstructionClass = Records.getClass("Instruction"); assert(ExpansionClass && "PseudoInstExpansion class definition missing!"); assert(InstructionClass && "Instruction class definition missing!"); diff --git a/contrib/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/contrib/llvm/utils/TableGen/RegisterInfoEmitter.cpp index 02546df..95b6267 100644 --- a/contrib/llvm/utils/TableGen/RegisterInfoEmitter.cpp +++ b/contrib/llvm/utils/TableGen/RegisterInfoEmitter.cpp @@ -62,6 +62,8 @@ private: void EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank, const std::string &ClassName); + void emitComposeSubRegIndices(raw_ostream &OS, CodeGenRegBank &RegBank, + const std::string &ClassName); }; } // End anonymous namespace @@ -325,7 +327,7 @@ RegisterInfoEmitter::EmitRegMappingTables(raw_ostream &OS, if (!V || !V->getValue()) continue; - DefInit *DI = dynamic_cast<DefInit*>(V->getValue()); + DefInit *DI = cast<DefInit>(V->getValue()); Record *Alias = DI->getDef(); DwarfRegNums[Reg] = DwarfRegNums[Alias]; } @@ -530,6 +532,102 @@ static void printDiff16(raw_ostream &OS, uint16_t Val) { OS << Val; } +// Try to combine Idx's compose map into Vec if it is compatible. +// Return false if it's not possible. +static bool combine(const CodeGenSubRegIndex *Idx, + SmallVectorImpl<CodeGenSubRegIndex*> &Vec) { + const CodeGenSubRegIndex::CompMap &Map = Idx->getComposites(); + for (CodeGenSubRegIndex::CompMap::const_iterator + I = Map.begin(), E = Map.end(); I != E; ++I) { + CodeGenSubRegIndex *&Entry = Vec[I->first->EnumValue - 1]; + if (Entry && Entry != I->second) + return false; + } + + // All entries are compatible. Make it so. + for (CodeGenSubRegIndex::CompMap::const_iterator + I = Map.begin(), E = Map.end(); I != E; ++I) + Vec[I->first->EnumValue - 1] = I->second; + return true; +} + +static const char *getMinimalTypeForRange(uint64_t Range) { + assert(Range < 0xFFFFFFFFULL && "Enum too large"); + if (Range > 0xFFFF) + return "uint32_t"; + if (Range > 0xFF) + return "uint16_t"; + return "uint8_t"; +} + +void +RegisterInfoEmitter::emitComposeSubRegIndices(raw_ostream &OS, + CodeGenRegBank &RegBank, + const std::string &ClName) { + ArrayRef<CodeGenSubRegIndex*> SubRegIndices = RegBank.getSubRegIndices(); + OS << "unsigned " << ClName + << "::composeSubRegIndicesImpl(unsigned IdxA, unsigned IdxB) const {\n"; + + // Many sub-register indexes are composition-compatible, meaning that + // + // compose(IdxA, IdxB) == compose(IdxA', IdxB) + // + // for many IdxA, IdxA' pairs. Not all sub-register indexes can be composed. + // The illegal entries can be use as wildcards to compress the table further. + + // Map each Sub-register index to a compatible table row. + SmallVector<unsigned, 4> RowMap; + SmallVector<SmallVector<CodeGenSubRegIndex*, 4>, 4> Rows; + + for (unsigned i = 0, e = SubRegIndices.size(); i != e; ++i) { + unsigned Found = ~0u; + for (unsigned r = 0, re = Rows.size(); r != re; ++r) { + if (combine(SubRegIndices[i], Rows[r])) { + Found = r; + break; + } + } + if (Found == ~0u) { + Found = Rows.size(); + Rows.resize(Found + 1); + Rows.back().resize(SubRegIndices.size()); + combine(SubRegIndices[i], Rows.back()); + } + RowMap.push_back(Found); + } + + // Output the row map if there is multiple rows. + if (Rows.size() > 1) { + OS << " static const " << getMinimalTypeForRange(Rows.size()) + << " RowMap[" << SubRegIndices.size() << "] = {\n "; + for (unsigned i = 0, e = SubRegIndices.size(); i != e; ++i) + OS << RowMap[i] << ", "; + OS << "\n };\n"; + } + + // Output the rows. + OS << " static const " << getMinimalTypeForRange(SubRegIndices.size()+1) + << " Rows[" << Rows.size() << "][" << SubRegIndices.size() << "] = {\n"; + for (unsigned r = 0, re = Rows.size(); r != re; ++r) { + OS << " { "; + for (unsigned i = 0, e = SubRegIndices.size(); i != e; ++i) + if (Rows[r][i]) + OS << Rows[r][i]->EnumValue << ", "; + else + OS << "0, "; + OS << "},\n"; + } + OS << " };\n\n"; + + OS << " --IdxA; assert(IdxA < " << SubRegIndices.size() << ");\n" + << " --IdxB; assert(IdxB < " << SubRegIndices.size() << ");\n"; + if (Rows.size() > 1) + OS << " return Rows[RowMap[IdxA]][IdxB];\n"; + else + OS << " return Rows[0][IdxB];\n"; + OS << "}\n\n"; +} + // // runMCDesc - Print out MC register descriptions. // @@ -751,7 +849,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, BitsInit *BI = Reg->getValueAsBitsInit("HWEncoding"); uint64_t Value = 0; for (unsigned b = 0, be = BI->getNumBits(); b != be; ++b) { - if (BitInit *B = dynamic_cast<BitInit*>(BI->getBit(b))) + if (BitInit *B = dyn_cast<BitInit>(BI->getBit(b))) Value |= (uint64_t)B->getValue() << b; } OS << " " << Value << ",\n"; @@ -770,7 +868,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, << TargetName << "RegDiffLists, " << TargetName << "RegStrings, " << TargetName << "SubRegIdxLists, " - << SubRegIndices.size() << ",\n" + << (SubRegIndices.size() + 1) << ",\n" << " " << TargetName << "RegEncodingTable);\n\n"; EmitRegMapping(OS, Regs, false); @@ -802,16 +900,17 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target, << " virtual bool needsStackRealignment(const MachineFunction &) const\n" << " { return false; }\n"; if (!RegBank.getSubRegIndices().empty()) { - OS << " unsigned composeSubRegIndices(unsigned, unsigned) const;\n" - << " const TargetRegisterClass *" + OS << " virtual unsigned composeSubRegIndicesImpl" + << "(unsigned, unsigned) const;\n" + << " virtual const TargetRegisterClass *" "getSubClassWithSubReg(const TargetRegisterClass*, unsigned) const;\n"; } - OS << " const RegClassWeight &getRegClassWeight(" + OS << " virtual const RegClassWeight &getRegClassWeight(" << "const TargetRegisterClass *RC) const;\n" - << " unsigned getNumRegPressureSets() const;\n" - << " const char *getRegPressureSetName(unsigned Idx) const;\n" - << " unsigned getRegPressureSetLimit(unsigned Idx) const;\n" - << " const int *getRegClassPressureSets(" + << " virtual unsigned getNumRegPressureSets() const;\n" + << " virtual const char *getRegPressureSetName(unsigned Idx) const;\n" + << " virtual unsigned getRegPressureSetLimit(unsigned Idx) const;\n" + << " virtual const int *getRegClassPressureSets(" << "const TargetRegisterClass *RC) const;\n" << "};\n\n"; @@ -876,15 +975,23 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, VTSeqs.emit(OS, printSimpleValueType, "MVT::Other"); OS << "};\n"; - // Emit SubRegIndex names, skipping 0 - OS << "\nstatic const char *const SubRegIndexTable[] = { \""; + // Emit SubRegIndex names, skipping 0. + OS << "\nstatic const char *const SubRegIndexNameTable[] = { \""; for (unsigned i = 0, e = SubRegIndices.size(); i != e; ++i) { OS << SubRegIndices[i]->getName(); - if (i+1 != e) + if (i + 1 != e) OS << "\", \""; } OS << "\" };\n\n"; + // Emit SubRegIndex lane masks, including 0. + OS << "\nstatic const unsigned SubRegIndexLaneMaskTable[] = {\n ~0u,\n"; + for (unsigned i = 0, e = SubRegIndices.size(); i != e; ++i) { + OS << format(" 0x%08x, // ", SubRegIndices[i]->LaneMask) + << SubRegIndices[i]->getName() << '\n'; + } + OS << " };\n\n"; + OS << "\n"; // Now that all of the structs have been emitted, emit the instances. @@ -1046,31 +1153,8 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, std::string ClassName = Target.getName() + "GenRegisterInfo"; - // Emit composeSubRegIndices - if (!SubRegIndices.empty()) { - OS << "unsigned " << ClassName - << "::composeSubRegIndices(unsigned IdxA, unsigned IdxB) const {\n" - << " switch (IdxA) {\n" - << " default:\n return IdxB;\n"; - for (unsigned i = 0, e = SubRegIndices.size(); i != e; ++i) { - bool Open = false; - for (unsigned j = 0; j != e; ++j) { - if (CodeGenSubRegIndex *Comp = - SubRegIndices[i]->compose(SubRegIndices[j])) { - if (!Open) { - OS << " case " << SubRegIndices[i]->getQualifiedName() - << ": switch(IdxB) {\n default: return IdxB;\n"; - Open = true; - } - OS << " case " << SubRegIndices[j]->getQualifiedName() - << ": return " << Comp->getQualifiedName() << ";\n"; - } - } - if (Open) - OS << " }\n"; - } - OS << " }\n}\n\n"; - } + if (!SubRegIndices.empty()) + emitComposeSubRegIndices(OS, RegBank, ClassName); // Emit getSubClassWithSubReg. if (!SubRegIndices.empty()) { @@ -1084,7 +1168,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, else if (RegisterClasses.size() < UINT16_MAX) OS << " static const uint16_t Table["; else - throw "Too many register classes."; + PrintFatalError("Too many register classes."); OS << RegisterClasses.size() << "][" << SubRegIndices.size() << "] = {\n"; for (unsigned rci = 0, rce = RegisterClasses.size(); rci != rce; ++rci) { const CodeGenRegisterClass &RC = *RegisterClasses[rci]; @@ -1122,7 +1206,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, << "(unsigned RA, unsigned DwarfFlavour, unsigned EHFlavour)\n" << " : TargetRegisterInfo(" << TargetName << "RegInfoDesc" << ", RegisterClasses, RegisterClasses+" << RegisterClasses.size() <<",\n" - << " SubRegIndexTable) {\n" + << " SubRegIndexNameTable, SubRegIndexLaneMaskTable) {\n" << " InitMCRegisterInfo(" << TargetName << "RegDesc, " << Regs.size()+1 << ", RA,\n " << TargetName << "MCRegisterClasses, " << RegisterClasses.size() << ",\n" @@ -1131,7 +1215,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, << " " << TargetName << "RegDiffLists,\n" << " " << TargetName << "RegStrings,\n" << " " << TargetName << "SubRegIdxLists,\n" - << " " << SubRegIndices.size() << ",\n" + << " " << SubRegIndices.size() + 1 << ",\n" << " " << TargetName << "RegEncodingTable);\n\n"; EmitRegMapping(OS, Regs, true); diff --git a/contrib/llvm/utils/TableGen/SequenceToOffsetTable.h b/contrib/llvm/utils/TableGen/SequenceToOffsetTable.h index d8ab2ee..d4db152 100644 --- a/contrib/llvm/utils/TableGen/SequenceToOffsetTable.h +++ b/contrib/llvm/utils/TableGen/SequenceToOffsetTable.h @@ -29,8 +29,8 @@ namespace llvm { /// Compute the layout of a table that contains all the sequences, possibly by /// reusing entries. /// -/// @param SeqT The sequence container. (vector or string). -/// @param Less A stable comparator for SeqT elements. +/// @tparam SeqT The sequence container. (vector or string). +/// @tparam Less A stable comparator for SeqT elements. template<typename SeqT, typename Less = std::less<typename SeqT::value_type> > class SequenceToOffsetTable { typedef typename SeqT::value_type ElemT; @@ -82,7 +82,7 @@ public: } bool empty() const { return Seqs.empty(); } - + /// layout - Computes the final table layout. void layout() { assert(Entries == 0 && "Can only call layout() once"); diff --git a/contrib/llvm/utils/TableGen/SetTheory.cpp b/contrib/llvm/utils/TableGen/SetTheory.cpp index 46e6db1..0dd9853 100644 --- a/contrib/llvm/utils/TableGen/SetTheory.cpp +++ b/contrib/llvm/utils/TableGen/SetTheory.cpp @@ -27,20 +27,20 @@ typedef SetTheory::RecVec RecVec; // (add a, b, ...) Evaluate and union all arguments. struct AddOp : public SetTheory::Operator { - void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts) { - ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts); + void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef<SMLoc> Loc) { + ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc); } }; // (sub Add, Sub, ...) Set difference. struct SubOp : public SetTheory::Operator { - void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts) { + void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef<SMLoc> Loc) { if (Expr->arg_size() < 2) - throw "Set difference needs at least two arguments: " + - Expr->getAsString(); + PrintFatalError(Loc, "Set difference needs at least two arguments: " + + Expr->getAsString()); RecSet Add, Sub; - ST.evaluate(*Expr->arg_begin(), Add); - ST.evaluate(Expr->arg_begin() + 1, Expr->arg_end(), Sub); + ST.evaluate(*Expr->arg_begin(), Add, Loc); + ST.evaluate(Expr->arg_begin() + 1, Expr->arg_end(), Sub, Loc); for (RecSet::iterator I = Add.begin(), E = Add.end(); I != E; ++I) if (!Sub.count(*I)) Elts.insert(*I); @@ -49,12 +49,13 @@ struct SubOp : public SetTheory::Operator { // (and S1, S2) Set intersection. struct AndOp : public SetTheory::Operator { - void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts) { + void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef<SMLoc> Loc) { if (Expr->arg_size() != 2) - throw "Set intersection requires two arguments: " + Expr->getAsString(); + PrintFatalError(Loc, "Set intersection requires two arguments: " + + Expr->getAsString()); RecSet S1, S2; - ST.evaluate(Expr->arg_begin()[0], S1); - ST.evaluate(Expr->arg_begin()[1], S2); + ST.evaluate(Expr->arg_begin()[0], S1, Loc); + ST.evaluate(Expr->arg_begin()[1], S2, Loc); for (RecSet::iterator I = S1.begin(), E = S1.end(); I != E; ++I) if (S2.count(*I)) Elts.insert(*I); @@ -65,17 +66,19 @@ struct AndOp : public SetTheory::Operator { struct SetIntBinOp : public SetTheory::Operator { virtual void apply2(SetTheory &ST, DagInit *Expr, RecSet &Set, int64_t N, - RecSet &Elts) =0; + RecSet &Elts, ArrayRef<SMLoc> Loc) =0; - void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts) { + void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef<SMLoc> Loc) { if (Expr->arg_size() != 2) - throw "Operator requires (Op Set, Int) arguments: " + Expr->getAsString(); + PrintFatalError(Loc, "Operator requires (Op Set, Int) arguments: " + + Expr->getAsString()); RecSet Set; - ST.evaluate(Expr->arg_begin()[0], Set); - IntInit *II = dynamic_cast<IntInit*>(Expr->arg_begin()[1]); + ST.evaluate(Expr->arg_begin()[0], Set, Loc); + IntInit *II = dyn_cast<IntInit>(Expr->arg_begin()[1]); if (!II) - throw "Second argument must be an integer: " + Expr->getAsString(); - apply2(ST, Expr, Set, II->getValue(), Elts); + PrintFatalError(Loc, "Second argument must be an integer: " + + Expr->getAsString()); + apply2(ST, Expr, Set, II->getValue(), Elts, Loc); } }; @@ -83,9 +86,10 @@ struct SetIntBinOp : public SetTheory::Operator { struct ShlOp : public SetIntBinOp { void apply2(SetTheory &ST, DagInit *Expr, RecSet &Set, int64_t N, - RecSet &Elts) { + RecSet &Elts, ArrayRef<SMLoc> Loc) { if (N < 0) - throw "Positive shift required: " + Expr->getAsString(); + PrintFatalError(Loc, "Positive shift required: " + + Expr->getAsString()); if (unsigned(N) < Set.size()) Elts.insert(Set.begin() + N, Set.end()); } @@ -95,9 +99,10 @@ struct ShlOp : public SetIntBinOp { struct TruncOp : public SetIntBinOp { void apply2(SetTheory &ST, DagInit *Expr, RecSet &Set, int64_t N, - RecSet &Elts) { + RecSet &Elts, ArrayRef<SMLoc> Loc) { if (N < 0) - throw "Positive length required: " + Expr->getAsString(); + PrintFatalError(Loc, "Positive length required: " + + Expr->getAsString()); if (unsigned(N) > Set.size()) N = Set.size(); Elts.insert(Set.begin(), Set.begin() + N); @@ -112,7 +117,7 @@ struct RotOp : public SetIntBinOp { void apply2(SetTheory &ST, DagInit *Expr, RecSet &Set, int64_t N, - RecSet &Elts) { + RecSet &Elts, ArrayRef<SMLoc> Loc) { if (Reverse) N = -N; // N > 0 -> rotate left, N < 0 -> rotate right. @@ -131,9 +136,10 @@ struct RotOp : public SetIntBinOp { struct DecimateOp : public SetIntBinOp { void apply2(SetTheory &ST, DagInit *Expr, RecSet &Set, int64_t N, - RecSet &Elts) { + RecSet &Elts, ArrayRef<SMLoc> Loc) { if (N <= 0) - throw "Positive stride required: " + Expr->getAsString(); + PrintFatalError(Loc, "Positive stride required: " + + Expr->getAsString()); for (unsigned I = 0; I < Set.size(); I += N) Elts.insert(Set[I]); } @@ -141,12 +147,12 @@ 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) { + void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef<SMLoc> Loc) { // 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]); + ST.evaluate(Expr->getArg(i), Args[i], Loc); MaxSize = std::max(MaxSize, unsigned(Args[i].size())); } // Interleave arguments into Elts. @@ -159,41 +165,42 @@ struct InterleaveOp : public SetTheory::Operator { // (sequence "Format", From, To) Generate a sequence of records by name. struct SequenceOp : public SetTheory::Operator { - void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts) { + void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef<SMLoc> Loc) { int Step = 1; if (Expr->arg_size() > 4) - throw "Bad args to (sequence \"Format\", From, To): " + - Expr->getAsString(); + PrintFatalError(Loc, "Bad args to (sequence \"Format\", From, To): " + + Expr->getAsString()); else if (Expr->arg_size() == 4) { - if (IntInit *II = dynamic_cast<IntInit*>(Expr->arg_begin()[3])) { + if (IntInit *II = dyn_cast<IntInit>(Expr->arg_begin()[3])) { Step = II->getValue(); } else - throw "Stride must be an integer: " + Expr->getAsString(); + PrintFatalError(Loc, "Stride must be an integer: " + + Expr->getAsString()); } std::string Format; - if (StringInit *SI = dynamic_cast<StringInit*>(Expr->arg_begin()[0])) + if (StringInit *SI = dyn_cast<StringInit>(Expr->arg_begin()[0])) Format = SI->getValue(); else - throw "Format must be a string: " + Expr->getAsString(); + PrintFatalError(Loc, "Format must be a string: " + Expr->getAsString()); int64_t From, To; - if (IntInit *II = dynamic_cast<IntInit*>(Expr->arg_begin()[1])) + if (IntInit *II = dyn_cast<IntInit>(Expr->arg_begin()[1])) From = II->getValue(); else - throw "From must be an integer: " + Expr->getAsString(); + PrintFatalError(Loc, "From must be an integer: " + Expr->getAsString()); if (From < 0 || From >= (1 << 30)) - throw "From out of range"; + PrintFatalError(Loc, "From out of range"); - if (IntInit *II = dynamic_cast<IntInit*>(Expr->arg_begin()[2])) + if (IntInit *II = dyn_cast<IntInit>(Expr->arg_begin()[2])) To = II->getValue(); else - throw "From must be an integer: " + Expr->getAsString(); + PrintFatalError(Loc, "From must be an integer: " + Expr->getAsString()); if (To < 0 || To >= (1 << 30)) - throw "To out of range"; + PrintFatalError(Loc, "To out of range"); RecordKeeper &Records = - dynamic_cast<DefInit&>(*Expr->getOperator()).getDef()->getRecords(); + cast<DefInit>(Expr->getOperator())->getDef()->getRecords(); Step *= From <= To ? 1 : -1; while (true) { @@ -206,7 +213,8 @@ struct SequenceOp : public SetTheory::Operator { OS << format(Format.c_str(), unsigned(From)); Record *Rec = Records.getDef(OS.str()); if (!Rec) - throw "No def named '" + Name + "': " + Expr->getAsString(); + PrintFatalError(Loc, "No def named '" + Name + "': " + + Expr->getAsString()); // Try to reevaluate Rec in case it is a set. if (const RecVec *Result = ST.expand(Rec)) Elts.insert(Result->begin(), Result->end()); @@ -225,7 +233,7 @@ struct FieldExpander : public SetTheory::Expander { FieldExpander(StringRef fn) : FieldName(fn) {} void expand(SetTheory &ST, Record *Def, RecSet &Elts) { - ST.evaluate(Def->getValueInit(FieldName), Elts); + ST.evaluate(Def->getValueInit(FieldName), Elts, Def->getLoc()); } }; } // end anonymous namespace @@ -259,9 +267,9 @@ void SetTheory::addFieldExpander(StringRef ClassName, StringRef FieldName) { addExpander(ClassName, new FieldExpander(FieldName)); } -void SetTheory::evaluate(Init *Expr, RecSet &Elts) { +void SetTheory::evaluate(Init *Expr, RecSet &Elts, ArrayRef<SMLoc> Loc) { // A def in a list can be a just an element, or it may expand. - if (DefInit *Def = dynamic_cast<DefInit*>(Expr)) { + if (DefInit *Def = dyn_cast<DefInit>(Expr)) { if (const RecVec *Result = expand(Def->getDef())) return Elts.insert(Result->begin(), Result->end()); Elts.insert(Def->getDef()); @@ -269,20 +277,20 @@ void SetTheory::evaluate(Init *Expr, RecSet &Elts) { } // Lists simply expand. - if (ListInit *LI = dynamic_cast<ListInit*>(Expr)) - return evaluate(LI->begin(), LI->end(), Elts); + if (ListInit *LI = dyn_cast<ListInit>(Expr)) + return evaluate(LI->begin(), LI->end(), Elts, Loc); // Anything else must be a DAG. - DagInit *DagExpr = dynamic_cast<DagInit*>(Expr); + DagInit *DagExpr = dyn_cast<DagInit>(Expr); if (!DagExpr) - throw "Invalid set element: " + Expr->getAsString(); - DefInit *OpInit = dynamic_cast<DefInit*>(DagExpr->getOperator()); + PrintFatalError(Loc, "Invalid set element: " + Expr->getAsString()); + DefInit *OpInit = dyn_cast<DefInit>(DagExpr->getOperator()); if (!OpInit) - throw "Bad set expression: " + Expr->getAsString(); + PrintFatalError(Loc, "Bad set expression: " + Expr->getAsString()); Operator *Op = Operators.lookup(OpInit->getDef()->getName()); if (!Op) - throw "Unknown set operator: " + Expr->getAsString(); - Op->apply(*this, DagExpr, Elts); + PrintFatalError(Loc, "Unknown set operator: " + Expr->getAsString()); + Op->apply(*this, DagExpr, Elts, Loc); } const RecVec *SetTheory::expand(Record *Set) { @@ -292,19 +300,19 @@ const RecVec *SetTheory::expand(Record *Set) { return &I->second; // This is the first time we see Set. Find a suitable expander. - try { - const std::vector<Record*> &SC = Set->getSuperClasses(); - for (unsigned i = 0, e = SC.size(); i != e; ++i) - if (Expander *Exp = Expanders.lookup(SC[i]->getName())) { - // This breaks recursive definitions. - RecVec &EltVec = Expansions[Set]; - RecSet Elts; - Exp->expand(*this, Set, Elts); - EltVec.assign(Elts.begin(), Elts.end()); - return &EltVec; - } - } catch (const std::string &Error) { - throw TGError(Set->getLoc(), Error); + const std::vector<Record*> &SC = Set->getSuperClasses(); + for (unsigned i = 0, e = SC.size(); i != e; ++i) { + // Skip unnamed superclasses. + if (!dyn_cast<StringInit>(SC[i]->getNameInit())) + continue; + if (Expander *Exp = Expanders.lookup(SC[i]->getName())) { + // This breaks recursive definitions. + RecVec &EltVec = Expansions[Set]; + RecSet Elts; + Exp->expand(*this, Set, Elts); + EltVec.assign(Elts.begin(), Elts.end()); + return &EltVec; + } } // Set is not expandable. diff --git a/contrib/llvm/utils/TableGen/SetTheory.h b/contrib/llvm/utils/TableGen/SetTheory.h index b394058..122372a 100644 --- a/contrib/llvm/utils/TableGen/SetTheory.h +++ b/contrib/llvm/utils/TableGen/SetTheory.h @@ -49,6 +49,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/SetVector.h" +#include "llvm/Support/SourceMgr.h" #include <map> #include <vector> @@ -72,7 +73,8 @@ public: /// apply - Apply this operator to Expr's arguments and insert the result /// in Elts. - virtual void apply(SetTheory&, DagInit *Expr, RecSet &Elts) =0; + virtual void apply(SetTheory&, DagInit *Expr, RecSet &Elts, + ArrayRef<SMLoc> Loc) =0; }; /// Expander - A callback function that can transform a Record representing a @@ -119,13 +121,13 @@ public: void addOperator(StringRef Name, Operator*); /// evaluate - Evaluate Expr and append the resulting set to Elts. - void evaluate(Init *Expr, RecSet &Elts); + void evaluate(Init *Expr, RecSet &Elts, ArrayRef<SMLoc> Loc); /// evaluate - Evaluate a sequence of Inits and append to Elts. template<typename Iter> - void evaluate(Iter begin, Iter end, RecSet &Elts) { + void evaluate(Iter begin, Iter end, RecSet &Elts, ArrayRef<SMLoc> Loc) { while (begin != end) - evaluate(*begin++, Elts); + evaluate(*begin++, Elts, Loc); } /// expand - Expand a record into a set of elements if possible. Return a diff --git a/contrib/llvm/utils/TableGen/SubtargetEmitter.cpp b/contrib/llvm/utils/TableGen/SubtargetEmitter.cpp index 3472343..f1a06bb 100644 --- a/contrib/llvm/utils/TableGen/SubtargetEmitter.cpp +++ b/contrib/llvm/utils/TableGen/SubtargetEmitter.cpp @@ -11,13 +11,18 @@ // //===----------------------------------------------------------------------===// +#define DEBUG_TYPE "subtarget-emitter" + #include "CodeGenTarget.h" #include "CodeGenSchedule.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/MC/MCInstrItineraries.h" -#include "llvm/Support/Debug.h" +#include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" #include <algorithm> #include <map> #include <string> @@ -26,6 +31,32 @@ using namespace llvm; namespace { class SubtargetEmitter { + // Each processor has a SchedClassDesc table with an entry for each SchedClass. + // The SchedClassDesc table indexes into a global write resource table, write + // latency table, and read advance table. + struct SchedClassTables { + std::vector<std::vector<MCSchedClassDesc> > ProcSchedClasses; + std::vector<MCWriteProcResEntry> WriteProcResources; + std::vector<MCWriteLatencyEntry> WriteLatencies; + std::vector<std::string> WriterNames; + std::vector<MCReadAdvanceEntry> ReadAdvanceEntries; + + // Reserve an invalid entry at index 0 + SchedClassTables() { + ProcSchedClasses.resize(1); + WriteProcResources.resize(1); + WriteLatencies.resize(1); + WriterNames.push_back("InvalidWrite"); + ReadAdvanceEntries.resize(1); + } + }; + + struct LessWriteProcResources { + bool operator()(const MCWriteProcResEntry &LHS, + const MCWriteProcResEntry &RHS) { + return LHS.ProcResourceIdx < RHS.ProcResourceIdx; + } + }; RecordKeeper &Records; CodeGenSchedModels &SchedModels; @@ -50,8 +81,18 @@ class SubtargetEmitter { &ProcItinLists); void EmitProcessorProp(raw_ostream &OS, const Record *R, const char *Name, char Separator); + void EmitProcessorResources(const CodeGenProcModel &ProcModel, + raw_ostream &OS); + Record *FindWriteResources(const CodeGenSchedRW &SchedWrite, + const CodeGenProcModel &ProcModel); + Record *FindReadAdvance(const CodeGenSchedRW &SchedRead, + const CodeGenProcModel &ProcModel); + void GenSchedClassTables(const CodeGenProcModel &ProcModel, + SchedClassTables &SchedTables); + void EmitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS); void EmitProcessorModels(raw_ostream &OS); void EmitProcessorLookup(raw_ostream &OS); + void EmitSchedModelHelpers(std::string ClassName, raw_ostream &OS); void EmitSchedModel(raw_ostream &OS); void ParseFeaturesFunction(raw_ostream &OS, unsigned NumFeatures, unsigned NumProcs); @@ -521,7 +562,7 @@ EmitItineraries(raw_ostream &OS, std::vector<std::vector<InstrItinerary> >::iterator ProcItinListsIter = ProcItinLists.begin(); for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), - PE = SchedModels.procModelEnd(); PI != PE; ++PI) { + PE = SchedModels.procModelEnd(); PI != PE; ++PI, ++ProcItinListsIter) { Record *ItinsDef = PI->ItinsDef; if (!ItinsDefSet.insert(ItinsDef)) @@ -532,7 +573,7 @@ EmitItineraries(raw_ostream &OS, // Get the itinerary list for the processor. assert(ProcItinListsIter != ProcItinLists.end() && "bad iterator"); - std::vector<InstrItinerary> &ItinList = *ProcItinListsIter++; + std::vector<InstrItinerary> &ItinList = *ProcItinListsIter; OS << "\n"; OS << "static const llvm::InstrItinerary "; @@ -578,11 +619,488 @@ void SubtargetEmitter::EmitProcessorProp(raw_ostream &OS, const Record *R, OS << '\n'; } +void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel, + raw_ostream &OS) { + char Sep = ProcModel.ProcResourceDefs.empty() ? ' ' : ','; + + OS << "\n// {Name, NumUnits, SuperIdx, IsBuffered}\n"; + OS << "static const llvm::MCProcResourceDesc " + << ProcModel.ModelName << "ProcResources" << "[] = {\n" + << " {DBGFIELD(\"InvalidUnit\") 0, 0, 0}" << Sep << "\n"; + + for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) { + Record *PRDef = ProcModel.ProcResourceDefs[i]; + + // Find the SuperIdx + unsigned SuperIdx = 0; + Record *SuperDef = 0; + if (PRDef->getValueInit("Super")->isComplete()) { + SuperDef = + SchedModels.findProcResUnits(PRDef->getValueAsDef("Super"), ProcModel); + SuperIdx = ProcModel.getProcResourceIdx(SuperDef); + } + // Emit the ProcResourceDesc + if (i+1 == e) + Sep = ' '; + OS << " {DBGFIELD(\"" << PRDef->getName() << "\") "; + if (PRDef->getName().size() < 15) + OS.indent(15 - PRDef->getName().size()); + OS << PRDef->getValueAsInt("NumUnits") << ", " << SuperIdx << ", " + << PRDef->getValueAsBit("Buffered") << "}" << Sep << " // #" << i+1; + if (SuperDef) + OS << ", Super=" << SuperDef->getName(); + OS << "\n"; + } + OS << "};\n"; +} + +// Find the WriteRes Record that defines processor resources for this +// SchedWrite. +Record *SubtargetEmitter::FindWriteResources( + const CodeGenSchedRW &SchedWrite, const CodeGenProcModel &ProcModel) { + + // Check if the SchedWrite is already subtarget-specific and directly + // specifies a set of processor resources. + if (SchedWrite.TheDef->isSubClassOf("SchedWriteRes")) + return SchedWrite.TheDef; + + Record *AliasDef = 0; + for (RecIter AI = SchedWrite.Aliases.begin(), AE = SchedWrite.Aliases.end(); + AI != AE; ++AI) { + const CodeGenSchedRW &AliasRW = + SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW")); + if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) { + Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); + if (&SchedModels.getProcModel(ModelDef) != &ProcModel) + continue; + } + if (AliasDef) + PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases " + "defined for processor " + ProcModel.ModelName + + " Ensure only one SchedAlias exists per RW."); + AliasDef = AliasRW.TheDef; + } + if (AliasDef && AliasDef->isSubClassOf("SchedWriteRes")) + return AliasDef; + + // Check this processor's list of write resources. + Record *ResDef = 0; + for (RecIter WRI = ProcModel.WriteResDefs.begin(), + WRE = ProcModel.WriteResDefs.end(); WRI != WRE; ++WRI) { + if (!(*WRI)->isSubClassOf("WriteRes")) + continue; + if (AliasDef == (*WRI)->getValueAsDef("WriteType") + || SchedWrite.TheDef == (*WRI)->getValueAsDef("WriteType")) { + if (ResDef) { + PrintFatalError((*WRI)->getLoc(), "Resources are defined for both " + "SchedWrite and its alias on processor " + + ProcModel.ModelName); + } + ResDef = *WRI; + } + } + // TODO: If ProcModel has a base model (previous generation processor), + // then call FindWriteResources recursively with that model here. + if (!ResDef) { + PrintFatalError(ProcModel.ModelDef->getLoc(), + std::string("Processor does not define resources for ") + + SchedWrite.TheDef->getName()); + } + return ResDef; +} + +/// Find the ReadAdvance record for the given SchedRead on this processor or +/// return NULL. +Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead, + const CodeGenProcModel &ProcModel) { + // Check for SchedReads that directly specify a ReadAdvance. + if (SchedRead.TheDef->isSubClassOf("SchedReadAdvance")) + return SchedRead.TheDef; + + // Check this processor's list of aliases for SchedRead. + Record *AliasDef = 0; + for (RecIter AI = SchedRead.Aliases.begin(), AE = SchedRead.Aliases.end(); + AI != AE; ++AI) { + const CodeGenSchedRW &AliasRW = + SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW")); + if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) { + Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel"); + if (&SchedModels.getProcModel(ModelDef) != &ProcModel) + continue; + } + if (AliasDef) + PrintFatalError(AliasRW.TheDef->getLoc(), "Multiple aliases " + "defined for processor " + ProcModel.ModelName + + " Ensure only one SchedAlias exists per RW."); + AliasDef = AliasRW.TheDef; + } + if (AliasDef && AliasDef->isSubClassOf("SchedReadAdvance")) + return AliasDef; + + // Check this processor's ReadAdvanceList. + Record *ResDef = 0; + for (RecIter RAI = ProcModel.ReadAdvanceDefs.begin(), + RAE = ProcModel.ReadAdvanceDefs.end(); RAI != RAE; ++RAI) { + if (!(*RAI)->isSubClassOf("ReadAdvance")) + continue; + if (AliasDef == (*RAI)->getValueAsDef("ReadType") + || SchedRead.TheDef == (*RAI)->getValueAsDef("ReadType")) { + if (ResDef) { + PrintFatalError((*RAI)->getLoc(), "Resources are defined for both " + "SchedRead and its alias on processor " + + ProcModel.ModelName); + } + ResDef = *RAI; + } + } + // TODO: If ProcModel has a base model (previous generation processor), + // then call FindReadAdvance recursively with that model here. + if (!ResDef && SchedRead.TheDef->getName() != "ReadDefault") { + PrintFatalError(ProcModel.ModelDef->getLoc(), + std::string("Processor does not define resources for ") + + SchedRead.TheDef->getName()); + } + return ResDef; +} + +// Generate the SchedClass table for this processor and update global +// tables. Must be called for each processor in order. +void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, + SchedClassTables &SchedTables) { + SchedTables.ProcSchedClasses.resize(SchedTables.ProcSchedClasses.size() + 1); + if (!ProcModel.hasInstrSchedModel()) + return; + + std::vector<MCSchedClassDesc> &SCTab = SchedTables.ProcSchedClasses.back(); + for (CodeGenSchedModels::SchedClassIter SCI = SchedModels.schedClassBegin(), + SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) { + DEBUG(SCI->dump(&SchedModels)); + + SCTab.resize(SCTab.size() + 1); + MCSchedClassDesc &SCDesc = SCTab.back(); + // SCDesc.Name is guarded by NDEBUG + SCDesc.NumMicroOps = 0; + SCDesc.BeginGroup = false; + SCDesc.EndGroup = false; + SCDesc.WriteProcResIdx = 0; + SCDesc.WriteLatencyIdx = 0; + SCDesc.ReadAdvanceIdx = 0; + + // A Variant SchedClass has no resources of its own. + if (!SCI->Transitions.empty()) { + SCDesc.NumMicroOps = MCSchedClassDesc::VariantNumMicroOps; + continue; + } + + // Determine if the SchedClass is actually reachable on this processor. If + // not don't try to locate the processor resources, it will fail. + // If ProcIndices contains 0, this class applies to all processors. + assert(!SCI->ProcIndices.empty() && "expect at least one procidx"); + if (SCI->ProcIndices[0] != 0) { + IdxIter PIPos = std::find(SCI->ProcIndices.begin(), + SCI->ProcIndices.end(), ProcModel.Index); + if (PIPos == SCI->ProcIndices.end()) + continue; + } + IdxVec Writes = SCI->Writes; + IdxVec Reads = SCI->Reads; + if (SCI->ItinClassDef) { + assert(SCI->InstRWs.empty() && "ItinClass should not have InstRWs"); + // Check this processor's itinerary class resources. + for (RecIter II = ProcModel.ItinRWDefs.begin(), + IE = ProcModel.ItinRWDefs.end(); II != IE; ++II) { + RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses"); + if (std::find(Matched.begin(), Matched.end(), SCI->ItinClassDef) + != Matched.end()) { + SchedModels.findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), + Writes, Reads); + break; + } + } + if (Writes.empty()) { + DEBUG(dbgs() << ProcModel.ItinsDef->getName() + << " does not have resources for itinerary class " + << SCI->ItinClassDef->getName() << '\n'); + } + } + else if (!SCI->InstRWs.empty()) { + // This class may have a default ReadWrite list which can be overriden by + // InstRW definitions. + Record *RWDef = 0; + for (RecIter RWI = SCI->InstRWs.begin(), RWE = SCI->InstRWs.end(); + RWI != RWE; ++RWI) { + Record *RWModelDef = (*RWI)->getValueAsDef("SchedModel"); + if (&ProcModel == &SchedModels.getProcModel(RWModelDef)) { + RWDef = *RWI; + break; + } + } + if (RWDef) { + Writes.clear(); + Reads.clear(); + SchedModels.findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"), + Writes, Reads); + } + } + // Sum resources across all operand writes. + std::vector<MCWriteProcResEntry> WriteProcResources; + std::vector<MCWriteLatencyEntry> WriteLatencies; + std::vector<std::string> WriterNames; + std::vector<MCReadAdvanceEntry> ReadAdvanceEntries; + for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI) { + IdxVec WriteSeq; + SchedModels.expandRWSeqForProc(*WI, WriteSeq, /*IsRead=*/false, + ProcModel); + + // For each operand, create a latency entry. + MCWriteLatencyEntry WLEntry; + WLEntry.Cycles = 0; + unsigned WriteID = WriteSeq.back(); + WriterNames.push_back(SchedModels.getSchedWrite(WriteID).Name); + // If this Write is not referenced by a ReadAdvance, don't distinguish it + // from other WriteLatency entries. + if (!SchedModels.hasReadOfWrite(SchedModels.getSchedWrite(WriteID).TheDef)) { + WriteID = 0; + } + WLEntry.WriteResourceID = WriteID; + + for (IdxIter WSI = WriteSeq.begin(), WSE = WriteSeq.end(); + WSI != WSE; ++WSI) { + + Record *WriteRes = + FindWriteResources(SchedModels.getSchedWrite(*WSI), ProcModel); + + // Mark the parent class as invalid for unsupported write types. + if (WriteRes->getValueAsBit("Unsupported")) { + SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps; + break; + } + WLEntry.Cycles += WriteRes->getValueAsInt("Latency"); + SCDesc.NumMicroOps += WriteRes->getValueAsInt("NumMicroOps"); + SCDesc.BeginGroup |= WriteRes->getValueAsBit("BeginGroup"); + SCDesc.EndGroup |= WriteRes->getValueAsBit("EndGroup"); + + // Create an entry for each ProcResource listed in WriteRes. + RecVec PRVec = WriteRes->getValueAsListOfDefs("ProcResources"); + std::vector<int64_t> Cycles = + WriteRes->getValueAsListOfInts("ResourceCycles"); + for (unsigned PRIdx = 0, PREnd = PRVec.size(); + PRIdx != PREnd; ++PRIdx) { + MCWriteProcResEntry WPREntry; + WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]); + assert(WPREntry.ProcResourceIdx && "Bad ProcResourceIdx"); + if (Cycles.size() > PRIdx) + WPREntry.Cycles = Cycles[PRIdx]; + else + WPREntry.Cycles = 1; + WriteProcResources.push_back(WPREntry); + } + } + WriteLatencies.push_back(WLEntry); + } + // Create an entry for each operand Read in this SchedClass. + // Entries must be sorted first by UseIdx then by WriteResourceID. + for (unsigned UseIdx = 0, EndIdx = Reads.size(); + UseIdx != EndIdx; ++UseIdx) { + Record *ReadAdvance = + FindReadAdvance(SchedModels.getSchedRead(Reads[UseIdx]), ProcModel); + if (!ReadAdvance) + continue; + + // Mark the parent class as invalid for unsupported write types. + if (ReadAdvance->getValueAsBit("Unsupported")) { + SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps; + break; + } + RecVec ValidWrites = ReadAdvance->getValueAsListOfDefs("ValidWrites"); + IdxVec WriteIDs; + if (ValidWrites.empty()) + WriteIDs.push_back(0); + else { + for (RecIter VWI = ValidWrites.begin(), VWE = ValidWrites.end(); + VWI != VWE; ++VWI) { + WriteIDs.push_back(SchedModels.getSchedRWIdx(*VWI, /*IsRead=*/false)); + } + } + std::sort(WriteIDs.begin(), WriteIDs.end()); + for(IdxIter WI = WriteIDs.begin(), WE = WriteIDs.end(); WI != WE; ++WI) { + MCReadAdvanceEntry RAEntry; + RAEntry.UseIdx = UseIdx; + RAEntry.WriteResourceID = *WI; + RAEntry.Cycles = ReadAdvance->getValueAsInt("Cycles"); + ReadAdvanceEntries.push_back(RAEntry); + } + } + if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) { + WriteProcResources.clear(); + WriteLatencies.clear(); + ReadAdvanceEntries.clear(); + } + // Add the information for this SchedClass to the global tables using basic + // compression. + // + // WritePrecRes entries are sorted by ProcResIdx. + std::sort(WriteProcResources.begin(), WriteProcResources.end(), + LessWriteProcResources()); + + SCDesc.NumWriteProcResEntries = WriteProcResources.size(); + std::vector<MCWriteProcResEntry>::iterator WPRPos = + std::search(SchedTables.WriteProcResources.begin(), + SchedTables.WriteProcResources.end(), + WriteProcResources.begin(), WriteProcResources.end()); + if (WPRPos != SchedTables.WriteProcResources.end()) + SCDesc.WriteProcResIdx = WPRPos - SchedTables.WriteProcResources.begin(); + else { + SCDesc.WriteProcResIdx = SchedTables.WriteProcResources.size(); + SchedTables.WriteProcResources.insert(WPRPos, WriteProcResources.begin(), + WriteProcResources.end()); + } + // Latency entries must remain in operand order. + SCDesc.NumWriteLatencyEntries = WriteLatencies.size(); + std::vector<MCWriteLatencyEntry>::iterator WLPos = + std::search(SchedTables.WriteLatencies.begin(), + SchedTables.WriteLatencies.end(), + WriteLatencies.begin(), WriteLatencies.end()); + if (WLPos != SchedTables.WriteLatencies.end()) { + unsigned idx = WLPos - SchedTables.WriteLatencies.begin(); + SCDesc.WriteLatencyIdx = idx; + for (unsigned i = 0, e = WriteLatencies.size(); i < e; ++i) + if (SchedTables.WriterNames[idx + i].find(WriterNames[i]) == + std::string::npos) { + SchedTables.WriterNames[idx + i] += std::string("_") + WriterNames[i]; + } + } + else { + SCDesc.WriteLatencyIdx = SchedTables.WriteLatencies.size(); + SchedTables.WriteLatencies.insert(SchedTables.WriteLatencies.end(), + WriteLatencies.begin(), + WriteLatencies.end()); + SchedTables.WriterNames.insert(SchedTables.WriterNames.end(), + WriterNames.begin(), WriterNames.end()); + } + // ReadAdvanceEntries must remain in operand order. + SCDesc.NumReadAdvanceEntries = ReadAdvanceEntries.size(); + std::vector<MCReadAdvanceEntry>::iterator RAPos = + std::search(SchedTables.ReadAdvanceEntries.begin(), + SchedTables.ReadAdvanceEntries.end(), + ReadAdvanceEntries.begin(), ReadAdvanceEntries.end()); + if (RAPos != SchedTables.ReadAdvanceEntries.end()) + SCDesc.ReadAdvanceIdx = RAPos - SchedTables.ReadAdvanceEntries.begin(); + else { + SCDesc.ReadAdvanceIdx = SchedTables.ReadAdvanceEntries.size(); + SchedTables.ReadAdvanceEntries.insert(RAPos, ReadAdvanceEntries.begin(), + ReadAdvanceEntries.end()); + } + } +} + +// Emit SchedClass tables for all processors and associated global tables. +void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables, + raw_ostream &OS) { + // Emit global WriteProcResTable. + OS << "\n// {ProcResourceIdx, Cycles}\n" + << "extern const llvm::MCWriteProcResEntry " + << Target << "WriteProcResTable[] = {\n" + << " { 0, 0}, // Invalid\n"; + for (unsigned WPRIdx = 1, WPREnd = SchedTables.WriteProcResources.size(); + WPRIdx != WPREnd; ++WPRIdx) { + MCWriteProcResEntry &WPREntry = SchedTables.WriteProcResources[WPRIdx]; + OS << " {" << format("%2d", WPREntry.ProcResourceIdx) << ", " + << format("%2d", WPREntry.Cycles) << "}"; + if (WPRIdx + 1 < WPREnd) + OS << ','; + OS << " // #" << WPRIdx << '\n'; + } + OS << "}; // " << Target << "WriteProcResTable\n"; + + // Emit global WriteLatencyTable. + OS << "\n// {Cycles, WriteResourceID}\n" + << "extern const llvm::MCWriteLatencyEntry " + << Target << "WriteLatencyTable[] = {\n" + << " { 0, 0}, // Invalid\n"; + for (unsigned WLIdx = 1, WLEnd = SchedTables.WriteLatencies.size(); + WLIdx != WLEnd; ++WLIdx) { + MCWriteLatencyEntry &WLEntry = SchedTables.WriteLatencies[WLIdx]; + OS << " {" << format("%2d", WLEntry.Cycles) << ", " + << format("%2d", WLEntry.WriteResourceID) << "}"; + if (WLIdx + 1 < WLEnd) + OS << ','; + OS << " // #" << WLIdx << " " << SchedTables.WriterNames[WLIdx] << '\n'; + } + OS << "}; // " << Target << "WriteLatencyTable\n"; + + // Emit global ReadAdvanceTable. + OS << "\n// {UseIdx, WriteResourceID, Cycles}\n" + << "extern const llvm::MCReadAdvanceEntry " + << Target << "ReadAdvanceTable[] = {\n" + << " {0, 0, 0}, // Invalid\n"; + for (unsigned RAIdx = 1, RAEnd = SchedTables.ReadAdvanceEntries.size(); + RAIdx != RAEnd; ++RAIdx) { + MCReadAdvanceEntry &RAEntry = SchedTables.ReadAdvanceEntries[RAIdx]; + OS << " {" << RAEntry.UseIdx << ", " + << format("%2d", RAEntry.WriteResourceID) << ", " + << format("%2d", RAEntry.Cycles) << "}"; + if (RAIdx + 1 < RAEnd) + OS << ','; + OS << " // #" << RAIdx << '\n'; + } + OS << "}; // " << Target << "ReadAdvanceTable\n"; + + // Emit a SchedClass table for each processor. + for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), + PE = SchedModels.procModelEnd(); PI != PE; ++PI) { + if (!PI->hasInstrSchedModel()) + continue; + + std::vector<MCSchedClassDesc> &SCTab = + SchedTables.ProcSchedClasses[1 + (PI - SchedModels.procModelBegin())]; + + OS << "\n// {Name, NumMicroOps, BeginGroup, EndGroup," + << " WriteProcResIdx,#, WriteLatencyIdx,#, ReadAdvanceIdx,#}\n"; + OS << "static const llvm::MCSchedClassDesc " + << PI->ModelName << "SchedClasses[] = {\n"; + + // The first class is always invalid. We no way to distinguish it except by + // name and position. + assert(SchedModels.getSchedClass(0).Name == "NoItinerary" + && "invalid class not first"); + OS << " {DBGFIELD(\"InvalidSchedClass\") " + << MCSchedClassDesc::InvalidNumMicroOps + << ", 0, 0, 0, 0, 0, 0, 0, 0},\n"; + + for (unsigned SCIdx = 1, SCEnd = SCTab.size(); SCIdx != SCEnd; ++SCIdx) { + MCSchedClassDesc &MCDesc = SCTab[SCIdx]; + const CodeGenSchedClass &SchedClass = SchedModels.getSchedClass(SCIdx); + OS << " {DBGFIELD(\"" << SchedClass.Name << "\") "; + if (SchedClass.Name.size() < 18) + OS.indent(18 - SchedClass.Name.size()); + OS << MCDesc.NumMicroOps + << ", " << MCDesc.BeginGroup << ", " << MCDesc.EndGroup + << ", " << format("%2d", MCDesc.WriteProcResIdx) + << ", " << MCDesc.NumWriteProcResEntries + << ", " << format("%2d", MCDesc.WriteLatencyIdx) + << ", " << MCDesc.NumWriteLatencyEntries + << ", " << format("%2d", MCDesc.ReadAdvanceIdx) + << ", " << MCDesc.NumReadAdvanceEntries << "}"; + if (SCIdx + 1 < SCEnd) + OS << ','; + OS << " // #" << SCIdx << '\n'; + } + OS << "}; // " << PI->ModelName << "SchedClasses\n"; + } +} + void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { // For each processor model. for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), PE = SchedModels.procModelEnd(); PI != PE; ++PI) { - // Skip default + // Emit processor resource table. + if (PI->hasInstrSchedModel()) + EmitProcessorResources(*PI, OS); + else if(!PI->ProcResourceDefs.empty()) + PrintFatalError(PI->ModelDef->getLoc(), "SchedMachineModel defines " + "ProcResources without defining WriteRes SchedWriteRes"); + // Begin processor itinerary properties OS << "\n"; OS << "static const llvm::MCSchedModel " << PI->ModelName << "(\n"; @@ -591,11 +1109,19 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { EmitProcessorProp(OS, PI->ModelDef, "LoadLatency", ','); EmitProcessorProp(OS, PI->ModelDef, "HighLatency", ','); EmitProcessorProp(OS, PI->ModelDef, "MispredictPenalty", ','); + OS << " " << PI->Index << ", // Processor ID\n"; + if (PI->hasInstrSchedModel()) + OS << " " << PI->ModelName << "ProcResources" << ",\n" + << " " << PI->ModelName << "SchedClasses" << ",\n" + << " " << PI->ProcResourceDefs.size()+1 << ",\n" + << " " << (SchedModels.schedClassEnd() + - SchedModels.schedClassBegin()) << ",\n"; + else + OS << " 0, 0, 0, 0, // No instruction-level machine model.\n"; if (SchedModels.hasItineraryClasses()) - OS << " " << PI->ItinsDef->getName(); + OS << " " << PI->ItinsDef->getName() << ");\n"; else - OS << " 0"; - OS << ");\n"; + OS << " 0); // No Itinerary\n"; } } @@ -621,14 +1147,10 @@ void SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) { const std::string &Name = Processor->getValueAsString("Name"); const std::string &ProcModelName = - SchedModels.getProcModel(Processor).ModelName; + SchedModels.getModelForProc(Processor).ModelName; // Emit as { "cpu", procinit }, - OS << " { " - << "\"" << Name << "\", " - << "(void *)&" << ProcModelName; - - OS << " }"; + OS << " { \"" << Name << "\", (const void *)&" << ProcModelName << " }"; // Depending on ''if more in the list'' emit comma if (++i < N) OS << ","; @@ -644,16 +1166,116 @@ void SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) { // EmitSchedModel - Emits all scheduling model tables, folding common patterns. // void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) { + OS << "#ifdef DBGFIELD\n" + << "#error \"<target>GenSubtargetInfo.inc requires a DBGFIELD macro\"\n" + << "#endif\n" + << "#ifndef NDEBUG\n" + << "#define DBGFIELD(x) x,\n" + << "#else\n" + << "#define DBGFIELD(x)\n" + << "#endif\n"; + if (SchedModels.hasItineraryClasses()) { std::vector<std::vector<InstrItinerary> > ProcItinLists; // Emit the stage data EmitStageAndOperandCycleData(OS, ProcItinLists); EmitItineraries(OS, ProcItinLists); } + OS << "\n// ===============================================================\n" + << "// Data tables for the new per-operand machine model.\n"; + + SchedClassTables SchedTables; + for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(), + PE = SchedModels.procModelEnd(); PI != PE; ++PI) { + GenSchedClassTables(*PI, SchedTables); + } + EmitSchedClassTables(SchedTables, OS); + // Emit the processor machine model EmitProcessorModels(OS); // Emit the processor lookup data EmitProcessorLookup(OS); + + OS << "#undef DBGFIELD"; +} + +void SubtargetEmitter::EmitSchedModelHelpers(std::string ClassName, + raw_ostream &OS) { + OS << "unsigned " << ClassName + << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI," + << " const TargetSchedModel *SchedModel) const {\n"; + + std::vector<Record*> Prologs = Records.getAllDerivedDefinitions("PredicateProlog"); + std::sort(Prologs.begin(), Prologs.end(), LessRecord()); + for (std::vector<Record*>::const_iterator + PI = Prologs.begin(), PE = Prologs.end(); PI != PE; ++PI) { + OS << (*PI)->getValueAsString("Code") << '\n'; + } + IdxVec VariantClasses; + for (CodeGenSchedModels::SchedClassIter SCI = SchedModels.schedClassBegin(), + SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) { + if (SCI->Transitions.empty()) + continue; + VariantClasses.push_back(SCI - SchedModels.schedClassBegin()); + } + if (!VariantClasses.empty()) { + OS << " switch (SchedClass) {\n"; + for (IdxIter VCI = VariantClasses.begin(), VCE = VariantClasses.end(); + VCI != VCE; ++VCI) { + const CodeGenSchedClass &SC = SchedModels.getSchedClass(*VCI); + OS << " case " << *VCI << ": // " << SC.Name << '\n'; + IdxVec ProcIndices; + for (std::vector<CodeGenSchedTransition>::const_iterator + TI = SC.Transitions.begin(), TE = SC.Transitions.end(); + TI != TE; ++TI) { + IdxVec PI; + std::set_union(TI->ProcIndices.begin(), TI->ProcIndices.end(), + ProcIndices.begin(), ProcIndices.end(), + std::back_inserter(PI)); + ProcIndices.swap(PI); + } + for (IdxIter PI = ProcIndices.begin(), PE = ProcIndices.end(); + PI != PE; ++PI) { + OS << " "; + if (*PI != 0) + OS << "if (SchedModel->getProcessorID() == " << *PI << ") "; + OS << "{ // " << (SchedModels.procModelBegin() + *PI)->ModelName + << '\n'; + for (std::vector<CodeGenSchedTransition>::const_iterator + TI = SC.Transitions.begin(), TE = SC.Transitions.end(); + TI != TE; ++TI) { + OS << " if ("; + if (*PI != 0 && !std::count(TI->ProcIndices.begin(), + TI->ProcIndices.end(), *PI)) { + continue; + } + for (RecIter RI = TI->PredTerm.begin(), RE = TI->PredTerm.end(); + RI != RE; ++RI) { + if (RI != TI->PredTerm.begin()) + OS << "\n && "; + OS << "(" << (*RI)->getValueAsString("Predicate") << ")"; + } + OS << ")\n" + << " return " << TI->ToClassIdx << "; // " + << SchedModels.getSchedClass(TI->ToClassIdx).Name << '\n'; + } + OS << " }\n"; + if (*PI == 0) + break; + } + unsigned SCIdx = 0; + if (SC.ItinClassDef) + SCIdx = SchedModels.getSchedClassIdxForItin(SC.ItinClassDef); + else + SCIdx = SchedModels.findSchedClassIdx(SC.Writes, SC.Reads); + if (SCIdx != *VCI) + OS << " return " << SCIdx << ";\n"; + OS << " break;\n"; + } + OS << " };\n"; + } + OS << " report_fatal_error(\"Expected a variant SchedClass\");\n" + << "} // " << ClassName << "::resolveSchedClass\n"; } // @@ -680,7 +1302,8 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS, return; } - OS << " uint64_t Bits = ReInitMCSubtargetInfo(CPU, FS);\n"; + OS << " InitMCProcessorInfo(CPU, FS);\n" + << " uint64_t Bits = getFeatureBits();\n"; for (unsigned i = 0; i < Features.size(); i++) { // Next record @@ -747,13 +1370,18 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << Target << "SubTypeKV, "; else OS << "0, "; + OS << '\n'; OS.indent(22); + OS << Target << "ProcSchedKV, " + << Target << "WriteProcResTable, " + << Target << "WriteLatencyTable, " + << Target << "ReadAdvanceTable, "; if (SchedModels.hasItineraryClasses()) { - OS << Target << "ProcSchedKV, " - << Target << "Stages, " + OS << '\n'; OS.indent(22); + OS << Target << "Stages, " << Target << "OperandCycles, " << Target << "ForwardingPaths, "; } else - OS << "0, 0, 0, 0, "; + OS << "0, 0, 0, "; OS << NumFeatures << ", " << NumProcs << ");\n}\n\n"; OS << "} // End llvm namespace \n"; @@ -780,6 +1408,8 @@ void SubtargetEmitter::run(raw_ostream &OS) { << " explicit " << ClassName << "(StringRef TT, StringRef CPU, " << "StringRef FS);\n" << "public:\n" + << " unsigned resolveSchedClass(unsigned SchedClass, const MachineInstr *DefMI," + << " const TargetSchedModel *SchedModel) const;\n" << " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)" << " const;\n" << "};\n"; @@ -790,11 +1420,19 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n"; OS << "#undef GET_SUBTARGETINFO_CTOR\n"; + OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n"; OS << "namespace llvm {\n"; OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n"; OS << "extern const llvm::SubtargetFeatureKV " << Target << "SubTypeKV[];\n"; + OS << "extern const llvm::SubtargetInfoKV " << Target << "ProcSchedKV[];\n"; + OS << "extern const llvm::MCWriteProcResEntry " + << Target << "WriteProcResTable[];\n"; + OS << "extern const llvm::MCWriteLatencyEntry " + << Target << "WriteLatencyTable[];\n"; + OS << "extern const llvm::MCReadAdvanceEntry " + << Target << "ReadAdvanceTable[];\n"; + if (SchedModels.hasItineraryClasses()) { - OS << "extern const llvm::SubtargetInfoKV " << Target << "ProcSchedKV[];\n"; OS << "extern const llvm::InstrStage " << Target << "Stages[];\n"; OS << "extern const unsigned " << Target << "OperandCycles[];\n"; OS << "extern const unsigned " << Target << "ForwardingPaths[];\n"; @@ -812,14 +1450,22 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << Target << "SubTypeKV, "; else OS << "0, "; + OS << '\n'; OS.indent(22); + OS << Target << "ProcSchedKV, " + << Target << "WriteProcResTable, " + << Target << "WriteLatencyTable, " + << Target << "ReadAdvanceTable, "; + OS << '\n'; OS.indent(22); if (SchedModels.hasItineraryClasses()) { - OS << Target << "ProcSchedKV, " - << Target << "Stages, " + OS << Target << "Stages, " << Target << "OperandCycles, " << Target << "ForwardingPaths, "; } else - OS << "0, 0, 0, 0, "; + OS << "0, 0, 0, "; OS << NumFeatures << ", " << NumProcs << ");\n}\n\n"; + + EmitSchedModelHelpers(ClassName, OS); + OS << "} // End llvm namespace \n"; OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n"; diff --git a/contrib/llvm/utils/TableGen/TGValueTypes.cpp b/contrib/llvm/utils/TableGen/TGValueTypes.cpp index af0d9f4..3ac71a4 100644 --- a/contrib/llvm/utils/TableGen/TGValueTypes.cpp +++ b/contrib/llvm/utils/TableGen/TGValueTypes.cpp @@ -15,13 +15,25 @@ //===----------------------------------------------------------------------===// #include "llvm/CodeGen/ValueTypes.h" +#include "llvm/Support/Casting.h" #include <map> using namespace llvm; namespace llvm { class Type { +protected: + enum TypeKind { + TK_ExtendedIntegerType, + TK_ExtendedVectorType + }; +private: + TypeKind Kind; public: + TypeKind getKind() const { + return Kind; + } + Type(TypeKind K) : Kind(K) {} virtual unsigned getSizeInBits() const = 0; virtual ~Type() {} }; @@ -32,7 +44,10 @@ class ExtendedIntegerType : public Type { unsigned BitWidth; public: explicit ExtendedIntegerType(unsigned bits) - : BitWidth(bits) {} + : Type(TK_ExtendedIntegerType), BitWidth(bits) {} + static bool classof(const Type *T) { + return T->getKind() == TK_ExtendedIntegerType; + } unsigned getSizeInBits() const { return getBitWidth(); } @@ -46,7 +61,10 @@ class ExtendedVectorType : public Type { unsigned NumElements; public: ExtendedVectorType(EVT elty, unsigned num) - : ElementType(elty), NumElements(num) {} + : Type(TK_ExtendedVectorType), ElementType(elty), NumElements(num) {} + static bool classof(const Type *T) { + return T->getKind() == TK_ExtendedVectorType; + } unsigned getSizeInBits() const { return getNumElements() * getElementType().getSizeInBits(); } @@ -71,12 +89,12 @@ bool EVT::isExtendedFloatingPoint() const { bool EVT::isExtendedInteger() const { assert(isExtended() && "Type is not extended!"); - return dynamic_cast<const ExtendedIntegerType *>(LLVMTy) != 0; + return isa<ExtendedIntegerType>(LLVMTy); } bool EVT::isExtendedVector() const { assert(isExtended() && "Type is not extended!"); - return dynamic_cast<const ExtendedVectorType *>(LLVMTy) != 0; + return isa<ExtendedVectorType>(LLVMTy); } bool EVT::isExtended64BitVector() const { diff --git a/contrib/llvm/utils/TableGen/TableGen.cpp b/contrib/llvm/utils/TableGen/TableGen.cpp index 9695b4a..49efe7e 100644 --- a/contrib/llvm/utils/TableGen/TableGen.cpp +++ b/contrib/llvm/utils/TableGen/TableGen.cpp @@ -20,7 +20,6 @@ #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Main.h" #include "llvm/TableGen/Record.h" -#include "llvm/TableGen/TableGenAction.h" using namespace llvm; @@ -90,86 +89,83 @@ namespace { 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: - EmitCodeEmitter(Records, OS); - break; - case GenRegisterInfo: - EmitRegisterInfo(Records, OS); - break; - case GenInstrInfo: - EmitInstrInfo(Records, OS); - break; - case GenCallingConv: - EmitCallingConv(Records, OS); - break; - case GenAsmWriter: - EmitAsmWriter(Records, OS); - break; - case GenAsmMatcher: - EmitAsmMatcher(Records, OS); - break; - case GenDisassembler: - EmitDisassembler(Records, OS); - break; - case GenPseudoLowering: - EmitPseudoLowering(Records, OS); - break; - case GenDAGISel: - EmitDAGISel(Records, OS); - break; - case GenDFAPacketizer: - EmitDFAPacketizer(Records, OS); - break; - case GenFastISel: - EmitFastISel(Records, OS); - break; - case GenSubtarget: - EmitSubtarget(Records, OS); - break; - case GenIntrinsic: - EmitIntrinsics(Records, OS); - break; - case GenTgtIntrinsic: - EmitIntrinsics(Records, OS, true); - break; - case GenEDInfo: - EmitEnhancedDisassemblerInfo(Records, 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"; - } - break; - } - } - - return false; +bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) { + switch (Action) { + case PrintRecords: + OS << Records; // No argument, dump all contents + break; + case GenEmitter: + EmitCodeEmitter(Records, OS); + break; + case GenRegisterInfo: + EmitRegisterInfo(Records, OS); + break; + case GenInstrInfo: + EmitInstrInfo(Records, OS); + break; + case GenCallingConv: + EmitCallingConv(Records, OS); + break; + case GenAsmWriter: + EmitAsmWriter(Records, OS); + break; + case GenAsmMatcher: + EmitAsmMatcher(Records, OS); + break; + case GenDisassembler: + EmitDisassembler(Records, OS); + break; + case GenPseudoLowering: + EmitPseudoLowering(Records, OS); + break; + case GenDAGISel: + EmitDAGISel(Records, OS); + break; + case GenDFAPacketizer: + EmitDFAPacketizer(Records, OS); + break; + case GenFastISel: + EmitFastISel(Records, OS); + break; + case GenSubtarget: + EmitSubtarget(Records, OS); + break; + case GenIntrinsic: + EmitIntrinsics(Records, OS); + break; + case GenTgtIntrinsic: + EmitIntrinsics(Records, OS, true); + break; + case GenEDInfo: + EmitEnhancedDisassemblerInfo(Records, 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"; } - }; + break; + } + } + + return false; +} } int main(int argc, char **argv) { @@ -177,6 +173,5 @@ int main(int argc, char **argv) { PrettyStackTraceProgram X(argc, argv); cl::ParseCommandLineOptions(argc, argv); - LLVMTableGenAction Action; - return TableGenMain(argv[0], Action); + return TableGenMain(argv[0], &LLVMTableGenMain); } diff --git a/contrib/llvm/utils/TableGen/TableGenBackends.h b/contrib/llvm/utils/TableGen/TableGenBackends.h index 2c00c40..f0d25d8 100644 --- a/contrib/llvm/utils/TableGen/TableGenBackends.h +++ b/contrib/llvm/utils/TableGen/TableGenBackends.h @@ -74,5 +74,6 @@ void EmitInstrInfo(RecordKeeper &RK, raw_ostream &OS); void EmitPseudoLowering(RecordKeeper &RK, raw_ostream &OS); void EmitRegisterInfo(RecordKeeper &RK, raw_ostream &OS); void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS); +void EmitMapTable(RecordKeeper &RK, raw_ostream &OS); } // End llvm namespace diff --git a/contrib/llvm/utils/TableGen/X86DisassemblerTables.cpp b/contrib/llvm/utils/TableGen/X86DisassemblerTables.cpp index f3bd373..468a1f8 100644 --- a/contrib/llvm/utils/TableGen/X86DisassemblerTables.cpp +++ b/contrib/llvm/utils/TableGen/X86DisassemblerTables.cpp @@ -209,6 +209,7 @@ static ModRMDecisionType getDecisionType(ModRMDecision &decision) { bool satisfiesOneEntry = true; bool satisfiesSplitRM = true; bool satisfiesSplitReg = true; + bool satisfiesSplitMisc = true; for (unsigned index = 0; index < 256; ++index) { if (decision.instructionIDs[index] != decision.instructionIDs[0]) @@ -228,7 +229,7 @@ static ModRMDecisionType getDecisionType(ModRMDecision &decision) { if (((index & 0xc0) != 0xc0) && (decision.instructionIDs[index] != decision.instructionIDs[index&0x38])) - satisfiesSplitReg = false; + satisfiesSplitMisc = false; } if (satisfiesOneEntry) @@ -237,9 +238,12 @@ static ModRMDecisionType getDecisionType(ModRMDecision &decision) { if (satisfiesSplitRM) return MODRM_SPLITRM; - if (satisfiesSplitReg) + if (satisfiesSplitReg && satisfiesSplitMisc) return MODRM_SPLITREG; + if (satisfiesSplitMisc) + return MODRM_SPLITMISC; + return MODRM_FULL; } @@ -332,6 +336,12 @@ void DisassemblerTables::emitModRMDecision(raw_ostream &o1, raw_ostream &o2, for (unsigned index = 0xc0; index < 256; index += 8) emitOneID(o1, i1, decision.instructionIDs[index], true); break; + case MODRM_SPLITMISC: + for (unsigned index = 0; index < 64; index += 8) + emitOneID(o1, i1, decision.instructionIDs[index], true); + for (unsigned index = 0xc0; index < 256; ++index) + emitOneID(o1, i1, decision.instructionIDs[index], true); + break; case MODRM_FULL: for (unsigned index = 0; index < 256; ++index) emitOneID(o1, i1, decision.instructionIDs[index], true); @@ -361,11 +371,18 @@ void DisassemblerTables::emitModRMDecision(raw_ostream &o1, raw_ostream &o2, case MODRM_SPLITREG: sEntryNumber += 16; break; + case MODRM_SPLITMISC: + sEntryNumber += 8 + 64; + break; case MODRM_FULL: sEntryNumber += 256; break; } + // We assume that the index can fit into uint16_t. + assert(sEntryNumber < 65536U && + "Index into ModRMDecision is too large for uint16_t!"); + ++sTableNumber; } diff --git a/contrib/llvm/utils/TableGen/X86ModRMFilters.h b/contrib/llvm/utils/TableGen/X86ModRMFilters.h index 19fecbc..2cbaf79 100644 --- a/contrib/llvm/utils/TableGen/X86ModRMFilters.h +++ b/contrib/llvm/utils/TableGen/X86ModRMFilters.h @@ -70,7 +70,7 @@ class ModFilter : public ModRMFilter { public: /// Constructor /// - /// @r - True if the mod bits of the ModR/M byte must be 11; false + /// \param r True if the mod bits of the ModR/M byte must be 11; false /// otherwise. The name r derives from the fact that the mod /// bits indicate whether the R/M bits [bits 2-0] signify a /// register or a memory operand. @@ -98,11 +98,12 @@ class EscapeFilter : public ModRMFilter { public: /// Constructor /// - /// @c0_ff - True if the ModR/M byte must fall between 0xc0 and 0xff; - /// false otherwise. - /// @nnn_or_modRM - If c0_ff is true, the required value of the entire ModR/M - /// byte. If c0_ff is false, the required value of the nnn - /// field. + /// \param c0_ff True if the ModR/M byte must fall between 0xc0 and 0xff; + /// false otherwise. + /// + /// \param nnn_or_modRM If c0_ff is true, the required value of the entire + /// ModR/M byte. If c0_ff is false, the required value + /// of the nnn field. EscapeFilter(bool c0_ff, uint8_t nnn_or_modRM) : ModRMFilter(), C0_FF(c0_ff), @@ -128,8 +129,8 @@ class AddRegEscapeFilter : public ModRMFilter { public: /// Constructor /// - /// @modRM - The value of the ModR/M byte when the register operand - /// refers to the first register in the register set. + /// \param modRM The value of the ModR/M byte when the register operand + /// refers to the first register in the register set. AddRegEscapeFilter(uint8_t modRM) : ModRM(modRM) { } @@ -150,9 +151,9 @@ class ExtendedFilter : public ModRMFilter { public: /// Constructor /// - /// @r - True if the mod field must be set to 11; false otherwise. - /// The name is explained at ModFilter. - /// @nnn - The required value of the nnn field. + /// \param r True if the mod field must be set to 11; false otherwise. + /// The name is explained at ModFilter. + /// \param nnn The required value of the nnn field. ExtendedFilter(bool r, uint8_t nnn) : ModRMFilter(), R(r), @@ -177,7 +178,7 @@ class ExactFilter : public ModRMFilter { public: /// Constructor /// - /// @modRM - The required value of the full ModR/M byte. + /// \param modRM The required value of the full ModR/M byte. ExactFilter(uint8_t modRM) : ModRMFilter(), ModRM(modRM) { diff --git a/contrib/llvm/utils/TableGen/X86RecognizableInstr.cpp b/contrib/llvm/utils/TableGen/X86RecognizableInstr.cpp index 7ac2336..d6ed2fe 100644 --- a/contrib/llvm/utils/TableGen/X86RecognizableInstr.cpp +++ b/contrib/llvm/utils/TableGen/X86RecognizableInstr.cpp @@ -38,14 +38,15 @@ using namespace llvm; MAP(D0, 45) \ 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) + MAP(D5, 48) \ + MAP(D8, 49) \ + MAP(D9, 50) \ + MAP(DA, 51) \ + MAP(DB, 52) \ + MAP(DC, 53) \ + MAP(DD, 54) \ + MAP(DE, 55) \ + MAP(DF, 56) // A clone of X86 since we can't depend on something that is generated. namespace X86Local { @@ -244,7 +245,7 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables, IsSSE = (HasOpSizePrefix && (Name.find("16") == Name.npos)) || (Name.find("CRC32") != Name.npos); HasFROperands = hasFROperands(); - HasVEX_LPrefix = has256BitOperands() || Rec->getValueAsBit("hasVEX_L"); + HasVEX_LPrefix = Rec->getValueAsBit("hasVEX_L"); // Check for 64-bit inst which does not require REX Is32Bit = false; @@ -479,20 +480,6 @@ bool RecognizableInstr::hasFROperands() const { return false; } -bool RecognizableInstr::has256BitOperands() const { - const std::vector<CGIOperandList::OperandInfo> &OperandList = *Operands; - unsigned numOperands = OperandList.size(); - - for (unsigned operandIndex = 0; operandIndex < numOperands; ++operandIndex) { - const std::string &recName = OperandList[operandIndex].Rec->getName(); - - if (!recName.compare("VR256")) { - return true; - } - } - return false; -} - void RecognizableInstr::handleOperand(bool optional, unsigned &operandIndex, unsigned &physicalOperandIndex, unsigned &numPhysicalOperands, @@ -1145,6 +1132,8 @@ OperandEncoding RecognizableInstr::immediateEncodingFromString // register IDs in 8-bit immediates nowadays. ENCODING("VR256", ENCODING_IB) ENCODING("VR128", ENCODING_IB) + ENCODING("FR32", ENCODING_IB) + ENCODING("FR64", ENCODING_IB) errs() << "Unhandled immediate encoding " << s << "\n"; llvm_unreachable("Unhandled immediate encoding"); } diff --git a/contrib/llvm/utils/TableGen/X86RecognizableInstr.h b/contrib/llvm/utils/TableGen/X86RecognizableInstr.h index 542e510..9feb3c3 100644 --- a/contrib/llvm/utils/TableGen/X86RecognizableInstr.h +++ b/contrib/llvm/utils/TableGen/X86RecognizableInstr.h @@ -127,10 +127,7 @@ private: /// hasFROperands - Returns true if any operand is a FR operand. bool hasFROperands() const; - - /// has256BitOperands - Returns true if any operand is a 256-bit SSE operand. - bool has256BitOperands() const; - + /// typeFromString - Translates an operand type from the string provided in /// the LLVM tables to an OperandType for use in the operand specifier. /// @@ -143,7 +140,7 @@ private: /// @param hasREX_WPrefix - Indicates whether the instruction has a REX.W /// prefix. If it does, 32-bit register operands stay /// 32-bit regardless of the operand size. - /// @param hasOpSizePrefix- Indicates whether the instruction has an OpSize + /// @param hasOpSizePrefix Indicates whether the instruction has an OpSize /// prefix. If it does not, then 16-bit register /// operands stay 16-bit. /// @return - The operand's type. @@ -225,23 +222,23 @@ private: /// emitInstructionSpecifier - Loads the instruction specifier for the current /// instruction into a DisassemblerTables. /// - /// @arg tables - The DisassemblerTables to populate with the specifier for + /// \param tables The DisassemblerTables to populate with the specifier for /// the current instruction. void emitInstructionSpecifier(DisassemblerTables &tables); /// emitDecodePath - Populates the proper fields in the decode tables /// corresponding to the decode paths for this instruction. /// - /// @arg tables - The DisassemblerTables to populate with the decode + /// \param tables The DisassemblerTables to populate with the decode /// decode information for the current instruction. void emitDecodePath(DisassemblerTables &tables) const; /// Constructor - Initializes a RecognizableInstr with the appropriate fields /// from a CodeGenInstruction. /// - /// @arg tables - The DisassemblerTables that the specifier will be added to. - /// @arg insn - The CodeGenInstruction to extract information from. - /// @arg uid - The unique ID of the current instruction. + /// \param tables The DisassemblerTables that the specifier will be added to. + /// \param insn The CodeGenInstruction to extract information from. + /// \param uid The unique ID of the current instruction. RecognizableInstr(DisassemblerTables &tables, const CodeGenInstruction &insn, InstrUID uid); @@ -249,11 +246,11 @@ public: /// processInstr - Accepts a CodeGenInstruction and loads decode information /// for it into a DisassemblerTables if appropriate. /// - /// @arg tables - The DiassemblerTables to be populated with decode + /// \param tables The DiassemblerTables to be populated with decode /// information. - /// @arg insn - The CodeGenInstruction to be used as a source for this + /// \param insn The CodeGenInstruction to be used as a source for this /// information. - /// @uid - The unique ID of the instruction. + /// \param uid The unique ID of the instruction. static void processInstr(DisassemblerTables &tables, const CodeGenInstruction &insn, InstrUID uid); |