diff options
Diffstat (limited to 'utils/TableGen')
46 files changed, 20087 insertions, 0 deletions
diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp new file mode 100644 index 0000000000000..c615abad5068e --- /dev/null +++ b/utils/TableGen/AsmWriterEmitter.cpp @@ -0,0 +1,741 @@ +//===- AsmWriterEmitter.cpp - Generate an assembly writer -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend is emits an assembly printer for the current target. +// Note that this is currently fairly skeletal, but will grow over time. +// +//===----------------------------------------------------------------------===// + +#include "AsmWriterEmitter.h" +#include "CodeGenTarget.h" +#include "Record.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/MathExtras.h" +#include <algorithm> +using namespace llvm; + +static bool isIdentChar(char C) { + return (C >= 'a' && C <= 'z') || + (C >= 'A' && C <= 'Z') || + (C >= '0' && C <= '9') || + C == '_'; +} + +// This should be an anon namespace, this works around a GCC warning. +namespace llvm { + struct AsmWriterOperand { + enum { isLiteralTextOperand, isMachineInstrOperand } OperandType; + + /// Str - For isLiteralTextOperand, this IS the literal text. For + /// isMachineInstrOperand, this is the PrinterMethodName for the operand. + std::string Str; + + /// MiOpNo - For isMachineInstrOperand, this is the operand number of the + /// machine instruction. + unsigned MIOpNo; + + /// MiModifier - For isMachineInstrOperand, this is the modifier string for + /// an operand, specified with syntax like ${opname:modifier}. + std::string MiModifier; + + // To make VS STL happy + AsmWriterOperand():OperandType(isLiteralTextOperand) {} + + explicit AsmWriterOperand(const std::string &LitStr) + : OperandType(isLiteralTextOperand), Str(LitStr) {} + + AsmWriterOperand(const std::string &Printer, unsigned OpNo, + const std::string &Modifier) + : OperandType(isMachineInstrOperand), Str(Printer), MIOpNo(OpNo), + MiModifier(Modifier) {} + + bool operator!=(const AsmWriterOperand &Other) const { + if (OperandType != Other.OperandType || Str != Other.Str) return true; + if (OperandType == isMachineInstrOperand) + return MIOpNo != Other.MIOpNo || MiModifier != Other.MiModifier; + return false; + } + bool operator==(const AsmWriterOperand &Other) const { + return !operator!=(Other); + } + + /// getCode - Return the code that prints this operand. + std::string getCode() const; + }; +} + +namespace llvm { + class AsmWriterInst { + public: + std::vector<AsmWriterOperand> Operands; + const CodeGenInstruction *CGI; + + AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant); + + /// MatchesAllButOneOp - If this instruction is exactly identical to the + /// specified instruction except for one differing operand, return the + /// differing operand number. Otherwise return ~0. + unsigned MatchesAllButOneOp(const AsmWriterInst &Other) const; + + private: + void AddLiteralString(const std::string &Str) { + // If the last operand was already a literal text string, append this to + // it, otherwise add a new operand. + if (!Operands.empty() && + Operands.back().OperandType == AsmWriterOperand::isLiteralTextOperand) + Operands.back().Str.append(Str); + else + Operands.push_back(AsmWriterOperand(Str)); + } + }; +} + + +std::string AsmWriterOperand::getCode() const { + if (OperandType == isLiteralTextOperand) + return "O << \"" + Str + "\"; "; + + std::string Result = Str + "(MI"; + if (MIOpNo != ~0U) + Result += ", " + utostr(MIOpNo); + if (!MiModifier.empty()) + Result += ", \"" + MiModifier + '"'; + return Result + "); "; +} + + +/// ParseAsmString - Parse the specified Instruction's AsmString into this +/// AsmWriterInst. +/// +AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) { + this->CGI = &CGI; + unsigned CurVariant = ~0U; // ~0 if we are outside a {.|.|.} region, other #. + + // NOTE: Any extensions to this code need to be mirrored in the + // AsmPrinter::printInlineAsm code that executes as compile time (assuming + // that inline asm strings should also get the new feature)! + const std::string &AsmString = CGI.AsmString; + std::string::size_type LastEmitted = 0; + while (LastEmitted != AsmString.size()) { + std::string::size_type DollarPos = + AsmString.find_first_of("${|}\\", LastEmitted); + if (DollarPos == std::string::npos) DollarPos = AsmString.size(); + + // Emit a constant string fragment. + if (DollarPos != LastEmitted) { + if (CurVariant == Variant || CurVariant == ~0U) { + for (; LastEmitted != DollarPos; ++LastEmitted) + switch (AsmString[LastEmitted]) { + case '\n': AddLiteralString("\\n"); break; + case '\t': AddLiteralString("\\t"); break; + case '"': AddLiteralString("\\\""); break; + case '\\': AddLiteralString("\\\\"); break; + default: + AddLiteralString(std::string(1, AsmString[LastEmitted])); + break; + } + } else { + LastEmitted = DollarPos; + } + } else if (AsmString[DollarPos] == '\\') { + if (DollarPos+1 != AsmString.size() && + (CurVariant == Variant || CurVariant == ~0U)) { + if (AsmString[DollarPos+1] == 'n') { + AddLiteralString("\\n"); + } else if (AsmString[DollarPos+1] == 't') { + AddLiteralString("\\t"); + } else if (std::string("${|}\\").find(AsmString[DollarPos+1]) + != std::string::npos) { + AddLiteralString(std::string(1, AsmString[DollarPos+1])); + } else { + throw "Non-supported escaped character found in instruction '" + + CGI.TheDef->getName() + "'!"; + } + LastEmitted = DollarPos+2; + continue; + } + } else if (AsmString[DollarPos] == '{') { + if (CurVariant != ~0U) + throw "Nested variants found for instruction '" + + CGI.TheDef->getName() + "'!"; + LastEmitted = DollarPos+1; + CurVariant = 0; // We are now inside of the variant! + } else if (AsmString[DollarPos] == '|') { + if (CurVariant == ~0U) + throw "'|' character found outside of a variant in instruction '" + + CGI.TheDef->getName() + "'!"; + ++CurVariant; + ++LastEmitted; + } else if (AsmString[DollarPos] == '}') { + if (CurVariant == ~0U) + throw "'}' character found outside of a variant in instruction '" + + CGI.TheDef->getName() + "'!"; + ++LastEmitted; + CurVariant = ~0U; + } else if (DollarPos+1 != AsmString.size() && + AsmString[DollarPos+1] == '$') { + if (CurVariant == Variant || CurVariant == ~0U) + AddLiteralString("$"); // "$$" -> $ + LastEmitted = DollarPos+2; + } else { + // Get the name of the variable. + std::string::size_type VarEnd = DollarPos+1; + + // handle ${foo}bar as $foo by detecting whether the character following + // the dollar sign is a curly brace. If so, advance VarEnd and DollarPos + // so the variable name does not contain the leading curly brace. + bool hasCurlyBraces = false; + if (VarEnd < AsmString.size() && '{' == AsmString[VarEnd]) { + hasCurlyBraces = true; + ++DollarPos; + ++VarEnd; + } + + while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) + ++VarEnd; + std::string VarName(AsmString.begin()+DollarPos+1, + AsmString.begin()+VarEnd); + + // Modifier - Support ${foo:modifier} syntax, where "modifier" is passed + // into printOperand. Also support ${:feature}, which is passed into + // PrintSpecial. + std::string Modifier; + + // In order to avoid starting the next string at the terminating curly + // brace, advance the end position past it if we found an opening curly + // brace. + if (hasCurlyBraces) { + if (VarEnd >= AsmString.size()) + throw "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() + "'"; + + unsigned ModifierStart = VarEnd; + while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) + ++VarEnd; + Modifier = std::string(AsmString.begin()+ModifierStart, + AsmString.begin()+VarEnd); + if (Modifier.empty()) + throw "Bad operand modifier name in '"+ CGI.TheDef->getName() + "'"; + } + + if (AsmString[VarEnd] != '}') + throw "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 $$?"; + + if (VarName.empty()) { + // Just a modifier, pass this into PrintSpecial. + Operands.push_back(AsmWriterOperand("PrintSpecial", ~0U, Modifier)); + } else { + // Otherwise, normal operand. + unsigned OpNo = CGI.getOperandNamed(VarName); + CodeGenInstruction::OperandInfo OpInfo = CGI.OperandList[OpNo]; + + if (CurVariant == Variant || CurVariant == ~0U) { + unsigned MIOp = OpInfo.MIOperandNo; + Operands.push_back(AsmWriterOperand(OpInfo.PrinterMethodName, MIOp, + Modifier)); + } + } + LastEmitted = VarEnd; + } + } + + AddLiteralString("\\n"); +} + +/// MatchesAllButOneOp - If this instruction is exactly identical to the +/// specified instruction except for one differing operand, return the differing +/// operand number. If more than one operand mismatches, return ~1, otherwise +/// if the instructions are identical return ~0. +unsigned AsmWriterInst::MatchesAllButOneOp(const AsmWriterInst &Other)const{ + if (Operands.size() != Other.Operands.size()) return ~1; + + unsigned MismatchOperand = ~0U; + for (unsigned i = 0, e = Operands.size(); i != e; ++i) { + if (Operands[i] != Other.Operands[i]) { + if (MismatchOperand != ~0U) // Already have one mismatch? + return ~1U; + else + MismatchOperand = i; + } + } + return MismatchOperand; +} + +static void PrintCases(std::vector<std::pair<std::string, + AsmWriterOperand> > &OpsToPrint, std::ostream &O) { + O << " case " << OpsToPrint.back().first << ": "; + AsmWriterOperand TheOp = OpsToPrint.back().second; + OpsToPrint.pop_back(); + + // Check to see if any other operands are identical in this list, and if so, + // emit a case label for them. + for (unsigned i = OpsToPrint.size(); i != 0; --i) + if (OpsToPrint[i-1].second == TheOp) { + O << "\n case " << OpsToPrint[i-1].first << ": "; + OpsToPrint.erase(OpsToPrint.begin()+i-1); + } + + // Finally, emit the code. + O << TheOp.getCode(); + O << "break;\n"; +} + + +/// EmitInstructions - Emit the last instruction in the vector and any other +/// instructions that are suitably similar to it. +static void EmitInstructions(std::vector<AsmWriterInst> &Insts, + std::ostream &O) { + AsmWriterInst FirstInst = Insts.back(); + Insts.pop_back(); + + std::vector<AsmWriterInst> SimilarInsts; + unsigned DifferingOperand = ~0; + for (unsigned i = Insts.size(); i != 0; --i) { + unsigned DiffOp = Insts[i-1].MatchesAllButOneOp(FirstInst); + if (DiffOp != ~1U) { + if (DifferingOperand == ~0U) // First match! + DifferingOperand = DiffOp; + + // If this differs in the same operand as the rest of the instructions in + // this class, move it to the SimilarInsts list. + if (DifferingOperand == DiffOp || DiffOp == ~0U) { + SimilarInsts.push_back(Insts[i-1]); + Insts.erase(Insts.begin()+i-1); + } + } + } + + O << " case " << FirstInst.CGI->Namespace << "::" + << FirstInst.CGI->TheDef->getName() << ":\n"; + for (unsigned i = 0, e = SimilarInsts.size(); i != e; ++i) + O << " case " << SimilarInsts[i].CGI->Namespace << "::" + << SimilarInsts[i].CGI->TheDef->getName() << ":\n"; + for (unsigned i = 0, e = FirstInst.Operands.size(); i != e; ++i) { + if (i != DifferingOperand) { + // If the operand is the same for all instructions, just print it. + O << " " << FirstInst.Operands[i].getCode(); + } else { + // If this is the operand that varies between all of the instructions, + // emit a switch for just this operand now. + O << " switch (MI->getOpcode()) {\n"; + std::vector<std::pair<std::string, AsmWriterOperand> > OpsToPrint; + OpsToPrint.push_back(std::make_pair(FirstInst.CGI->Namespace + "::" + + FirstInst.CGI->TheDef->getName(), + FirstInst.Operands[i])); + + for (unsigned si = 0, e = SimilarInsts.size(); si != e; ++si) { + AsmWriterInst &AWI = SimilarInsts[si]; + OpsToPrint.push_back(std::make_pair(AWI.CGI->Namespace+"::"+ + AWI.CGI->TheDef->getName(), + AWI.Operands[i])); + } + std::reverse(OpsToPrint.begin(), OpsToPrint.end()); + while (!OpsToPrint.empty()) + PrintCases(OpsToPrint, O); + O << " }"; + } + O << "\n"; + } + + O << " break;\n"; +} + +void AsmWriterEmitter:: +FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands, + std::vector<unsigned> &InstIdxs, + std::vector<unsigned> &InstOpsUsed) const { + InstIdxs.assign(NumberedInstructions.size(), ~0U); + + // This vector parallels UniqueOperandCommands, keeping track of which + // instructions each case are used for. It is a comma separated string of + // enums. + std::vector<std::string> InstrsForCase; + InstrsForCase.resize(UniqueOperandCommands.size()); + InstOpsUsed.assign(UniqueOperandCommands.size(), 0); + + for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { + const AsmWriterInst *Inst = getAsmWriterInstByID(i); + if (Inst == 0) continue; // PHI, INLINEASM, DBG_LABEL, etc. + + std::string Command; + if (Inst->Operands.empty()) + continue; // Instruction already done. + + Command = " " + Inst->Operands[0].getCode() + "\n"; + + // If this is the last operand, emit a return. + if (Inst->Operands.size() == 1) + Command += " return true;\n"; + + // Check to see if we already have 'Command' in UniqueOperandCommands. + // If not, add it. + bool FoundIt = false; + for (unsigned idx = 0, e = UniqueOperandCommands.size(); idx != e; ++idx) + if (UniqueOperandCommands[idx] == Command) { + InstIdxs[i] = idx; + InstrsForCase[idx] += ", "; + InstrsForCase[idx] += Inst->CGI->TheDef->getName(); + FoundIt = true; + break; + } + if (!FoundIt) { + InstIdxs[i] = UniqueOperandCommands.size(); + UniqueOperandCommands.push_back(Command); + InstrsForCase.push_back(Inst->CGI->TheDef->getName()); + + // This command matches one operand so far. + InstOpsUsed.push_back(1); + } + } + + // For each entry of UniqueOperandCommands, there is a set of instructions + // that uses it. If the next command of all instructions in the set are + // identical, fold it into the command. + for (unsigned CommandIdx = 0, e = UniqueOperandCommands.size(); + CommandIdx != e; ++CommandIdx) { + + for (unsigned Op = 1; ; ++Op) { + // Scan for the first instruction in the set. + std::vector<unsigned>::iterator NIT = + std::find(InstIdxs.begin(), InstIdxs.end(), CommandIdx); + if (NIT == InstIdxs.end()) break; // No commonality. + + // If this instruction has no more operands, we isn't anything to merge + // into this command. + const AsmWriterInst *FirstInst = + getAsmWriterInstByID(NIT-InstIdxs.begin()); + if (!FirstInst || FirstInst->Operands.size() == Op) + break; + + // Otherwise, scan to see if all of the other instructions in this command + // set share the operand. + bool AllSame = true; + + for (NIT = std::find(NIT+1, InstIdxs.end(), CommandIdx); + NIT != InstIdxs.end(); + NIT = std::find(NIT+1, InstIdxs.end(), CommandIdx)) { + // Okay, found another instruction in this command set. If the operand + // matches, we're ok, otherwise bail out. + const AsmWriterInst *OtherInst = + getAsmWriterInstByID(NIT-InstIdxs.begin()); + if (!OtherInst || OtherInst->Operands.size() == Op || + OtherInst->Operands[Op] != FirstInst->Operands[Op]) { + AllSame = false; + break; + } + } + if (!AllSame) break; + + // Okay, everything in this command set has the same next operand. Add it + // to UniqueOperandCommands and remember that it was consumed. + std::string Command = " " + FirstInst->Operands[Op].getCode() + "\n"; + + // If this is the last operand, emit a return after the code. + if (FirstInst->Operands.size() == Op+1) + Command += " return true;\n"; + + UniqueOperandCommands[CommandIdx] += Command; + InstOpsUsed[CommandIdx]++; + } + } + + // Prepend some of the instructions each case is used for onto the case val. + for (unsigned i = 0, e = InstrsForCase.size(); i != e; ++i) { + std::string Instrs = InstrsForCase[i]; + if (Instrs.size() > 70) { + Instrs.erase(Instrs.begin()+70, Instrs.end()); + Instrs += "..."; + } + + if (!Instrs.empty()) + UniqueOperandCommands[i] = " // " + Instrs + "\n" + + UniqueOperandCommands[i]; + } +} + + + +void AsmWriterEmitter::run(std::ostream &O) { + EmitSourceFileHeader("Assembly Writer Source Fragment", O); + + CodeGenTarget Target; + Record *AsmWriter = Target.getAsmWriter(); + std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); + unsigned Variant = AsmWriter->getValueAsInt("Variant"); + + O << + "/// printInstruction - This method is automatically generated by tablegen\n" + "/// from the instruction set description. This method returns true if the\n" + "/// machine instruction was sufficiently described to print it, otherwise\n" + "/// it returns false.\n" + "bool " << Target.getName() << ClassName + << "::printInstruction(const MachineInstr *MI) {\n"; + + std::vector<AsmWriterInst> Instructions; + + for (CodeGenTarget::inst_iterator I = Target.inst_begin(), + E = Target.inst_end(); I != E; ++I) + if (!I->second.AsmString.empty()) + Instructions.push_back(AsmWriterInst(I->second, Variant)); + + // Get the instruction numbering. + Target.getInstructionsByEnumValue(NumberedInstructions); + + // Compute the CodeGenInstruction -> AsmWriterInst mapping. Note that not + // all machine instructions are necessarily being printed, so there may be + // target instructions not in this map. + for (unsigned i = 0, e = Instructions.size(); i != e; ++i) + CGIAWIMap.insert(std::make_pair(Instructions[i].CGI, &Instructions[i])); + + // Build an aggregate string, and build a table of offsets into it. + std::map<std::string, unsigned> StringOffset; + std::string AggregateString; + AggregateString.push_back(0); // "\0" + AggregateString.push_back(0); // "\0" + + /// 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; + + unsigned MaxStringIdx = 0; + for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { + AsmWriterInst *AWI = CGIAWIMap[NumberedInstructions[i]]; + unsigned Idx; + if (AWI == 0) { + // Something not handled by the asmwriter printer. + Idx = 0; + } else if (AWI->Operands[0].OperandType != + AsmWriterOperand::isLiteralTextOperand || + AWI->Operands[0].Str.empty()) { + // Something handled by the asmwriter printer, but with no leading string. + Idx = 1; + } else { + unsigned &Entry = StringOffset[AWI->Operands[0].Str]; + if (Entry == 0) { + // Add the string to the aggregate if this is the first time found. + MaxStringIdx = Entry = AggregateString.size(); + std::string Str = AWI->Operands[0].Str; + UnescapeString(Str); + AggregateString += Str; + AggregateString += '\0'; + } + Idx = Entry; + + // Nuke the string from the operand list. It is now handled! + AWI->Operands.erase(AWI->Operands.begin()); + } + OpcodeInfo.push_back(Idx); + } + + // Figure out how many bits we used for the string index. + unsigned AsmStrBits = Log2_32_Ceil(MaxStringIdx+1); + + // To reduce code size, we compactify common instructions into a few bits + // in the opcode-indexed table. + unsigned BitsLeft = 32-AsmStrBits; + + std::vector<std::vector<std::string> > TableDrivenOperandPrinters; + + bool isFirst = true; + while (1) { + std::vector<std::string> UniqueOperandCommands; + + // For the first operand check, add a default value for instructions with + // just opcode strings to use. + if (isFirst) { + UniqueOperandCommands.push_back(" return true;\n"); + isFirst = false; + } + + std::vector<unsigned> InstIdxs; + std::vector<unsigned> NumInstOpsHandled; + FindUniqueOperandCommands(UniqueOperandCommands, InstIdxs, + NumInstOpsHandled); + + // If we ran out of operands to print, we're done. + if (UniqueOperandCommands.empty()) break; + + // Compute the number of bits we need to represent these cases, this is + // ceil(log2(numentries)). + unsigned NumBits = Log2_32_Ceil(UniqueOperandCommands.size()); + + // If we don't have enough bits for this operand, don't include it. + if (NumBits > BitsLeft) { + DOUT << "Not enough bits to densely encode " << NumBits + << " more bits\n"; + break; + } + + // 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); + + // Remove the info about this operand. + for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { + if (AsmWriterInst *Inst = getAsmWriterInstByID(i)) + if (!Inst->Operands.empty()) { + unsigned NumOps = NumInstOpsHandled[InstIdxs[i]]; + assert(NumOps <= Inst->Operands.size() && + "Can't remove this many ops!"); + Inst->Operands.erase(Inst->Operands.begin(), + Inst->Operands.begin()+NumOps); + } + } + + // Remember the handlers for this set of operands. + TableDrivenOperandPrinters.push_back(UniqueOperandCommands); + } + + + + O<<" static const unsigned OpInfo[] = {\n"; + for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { + O << " " << OpcodeInfo[i] << "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 \""; + unsigned CharsPrinted = 0; + EscapeString(AggregateString); + for (unsigned i = 0, e = AggregateString.size(); i != e; ++i) { + if (CharsPrinted > 70) { + O << "\"\n \""; + CharsPrinted = 0; + } + O << AggregateString[i]; + ++CharsPrinted; + + // Print escape sequences all together. + if (AggregateString[i] == '\\') { + assert(i+1 < AggregateString.size() && "Incomplete escape sequence!"); + if (isdigit(AggregateString[i+1])) { + assert(isdigit(AggregateString[i+2]) && isdigit(AggregateString[i+3]) && + "Expected 3 digit octal escape!"); + O << AggregateString[++i]; + O << AggregateString[++i]; + O << AggregateString[++i]; + CharsPrinted += 3; + } else { + O << AggregateString[++i]; + ++CharsPrinted; + } + } + } + O << "\";\n\n"; + + O << " processDebugLoc(MI->getDebugLoc());\n\n"; + + O << " if (MI->getOpcode() == TargetInstrInfo::INLINEASM) {\n" + << " O << \"\\t\";\n" + << " printInlineAsm(MI);\n" + << " return true;\n" + << " } else if (MI->isLabel()) {\n" + << " printLabel(MI);\n" + << " return true;\n" + << " } else if (MI->getOpcode() == TargetInstrInfo::DECLARE) {\n" + << " printDeclare(MI);\n" + << " return true;\n" + << " } else if (MI->getOpcode() == TargetInstrInfo::IMPLICIT_DEF) {\n" + << " printImplicitDef(MI);\n" + << " return true;\n" + << " }\n\n"; + + O << " O << \"\\t\";\n\n"; + + O << " // Emit the opcode for the instruction.\n" + << " unsigned Bits = OpInfo[MI->getOpcode()];\n" + << " if (Bits == 0) return false;\n" + << " O << AsmStrs+(Bits & " << (1 << AsmStrBits)-1 << ");\n\n"; + + // Output the table driven operand information. + BitsLeft = 32-AsmStrBits; + for (unsigned i = 0, e = TableDrivenOperandPrinters.size(); i != e; ++i) { + std::vector<std::string> &Commands = TableDrivenOperandPrinters[i]; + + // Compute the number of bits we need to represent these cases, this is + // ceil(log2(numentries)). + unsigned NumBits = Log2_32_Ceil(Commands.size()); + 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) << ") & " + << ((1 << NumBits)-1) << ") {\n" + << Commands[1] + << " } else {\n" + << Commands[0] + << " }\n\n"; + } else { + O << " switch ((Bits >> " << (BitsLeft+AsmStrBits) << ") & " + << ((1 << NumBits)-1) << ") {\n" + << " default: // unreachable.\n"; + + // Print out all the cases. + for (unsigned i = 0, e = Commands.size(); i != e; ++i) { + O << " case " << i << ":\n"; + O << Commands[i]; + O << " break;\n"; + } + O << " }\n\n"; + } + } + + // Okay, delete instructions with no operand info left. + for (unsigned i = 0, e = Instructions.size(); i != e; ++i) { + // Entire instruction has been emitted? + AsmWriterInst &Inst = Instructions[i]; + if (Inst.Operands.empty()) { + Instructions.erase(Instructions.begin()+i); + --i; --e; + } + } + + + // Because this is a vector, we want to emit from the end. Reverse all of the + // elements in the vector. + std::reverse(Instructions.begin(), Instructions.end()); + + if (!Instructions.empty()) { + // Find the opcode # of inline asm. + O << " switch (MI->getOpcode()) {\n"; + while (!Instructions.empty()) + EmitInstructions(Instructions, O); + + O << " }\n"; + O << " return true;\n"; + } + + O << "}\n"; +} diff --git a/utils/TableGen/AsmWriterEmitter.h b/utils/TableGen/AsmWriterEmitter.h new file mode 100644 index 0000000000000..302722d6df06f --- /dev/null +++ b/utils/TableGen/AsmWriterEmitter.h @@ -0,0 +1,50 @@ +//===- AsmWriterEmitter.h - Generate an assembly writer ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend is responsible for emitting an assembly printer for the +// code generator. +// +//===----------------------------------------------------------------------===// + +#ifndef ASMWRITER_EMITTER_H +#define ASMWRITER_EMITTER_H + +#include "TableGenBackend.h" +#include <map> +#include <vector> +#include <cassert> + +namespace llvm { + class AsmWriterInst; + class CodeGenInstruction; + + class AsmWriterEmitter : public TableGenBackend { + RecordKeeper &Records; + std::map<const CodeGenInstruction*, AsmWriterInst*> CGIAWIMap; + std::vector<const CodeGenInstruction*> NumberedInstructions; + public: + AsmWriterEmitter(RecordKeeper &R) : Records(R) {} + + // run - Output the asmwriter, returning true on failure. + void run(std::ostream &o); + +private: + AsmWriterInst *getAsmWriterInstByID(unsigned ID) const { + assert(ID < NumberedInstructions.size()); + std::map<const CodeGenInstruction*, AsmWriterInst*>::const_iterator I = + CGIAWIMap.find(NumberedInstructions[ID]); + assert(I != CGIAWIMap.end() && "Didn't find inst!"); + return I->second; + } + void FindUniqueOperandCommands(std::vector<std::string> &UOC, + std::vector<unsigned> &InstIdxs, + std::vector<unsigned> &InstOpsUsed) const; + }; +} +#endif diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt new file mode 100644 index 0000000000000..3f982e0c77aeb --- /dev/null +++ b/utils/TableGen/CMakeLists.txt @@ -0,0 +1,32 @@ +add_executable(tblgen + AsmWriterEmitter.cpp + CallingConvEmitter.cpp + ClangDiagnosticsEmitter.cpp + CodeEmitterGen.cpp + CodeGenDAGPatterns.cpp + CodeGenInstruction.cpp + CodeGenTarget.cpp + DAGISelEmitter.cpp + FastISelEmitter.cpp + InstrEnumEmitter.cpp + InstrInfoEmitter.cpp + IntrinsicEmitter.cpp + LLVMCConfigurationEmitter.cpp + Record.cpp + RegisterInfoEmitter.cpp + SubtargetEmitter.cpp + TGLexer.cpp + TGParser.cpp + TGSourceMgr.cpp + TGValueTypes.cpp + TableGen.cpp + TableGenBackend.cpp + ) + +target_link_libraries(tblgen LLVMSupport LLVMSystem) +if( MINGW ) + target_link_libraries(tblgen imagehlp psapi) +endif( MINGW ) +if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD ) + target_link_libraries(tblgen pthread) +endif() diff --git a/utils/TableGen/CallingConvEmitter.cpp b/utils/TableGen/CallingConvEmitter.cpp new file mode 100644 index 0000000000000..c1f87014335f7 --- /dev/null +++ b/utils/TableGen/CallingConvEmitter.cpp @@ -0,0 +1,206 @@ +//===- CallingConvEmitter.cpp - Generate calling conventions --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend is responsible for emitting descriptions of the calling +// conventions supported by this target. +// +//===----------------------------------------------------------------------===// + +#include "CallingConvEmitter.h" +#include "Record.h" +#include "CodeGenTarget.h" +using namespace llvm; + +void CallingConvEmitter::run(std::ostream &O) { + EmitSourceFileHeader("Calling Convention Implementation Fragment", O); + + std::vector<Record*> CCs = Records.getAllDerivedDefinitions("CallingConv"); + + // Emit prototypes for all of the CC's so that they can forward ref each + // other. + for (unsigned i = 0, e = CCs.size(); i != e; ++i) { + O << "static bool " << CCs[i]->getName() + << "(unsigned ValNo, MVT ValVT,\n" + << std::string(CCs[i]->getName().size()+13, ' ') + << "MVT LocVT, CCValAssign::LocInfo LocInfo,\n" + << std::string(CCs[i]->getName().size()+13, ' ') + << "ISD::ArgFlagsTy ArgFlags, CCState &State);\n"; + } + + // Emit each calling convention description in full. + for (unsigned i = 0, e = CCs.size(); i != e; ++i) + EmitCallingConv(CCs[i], O); +} + + +void CallingConvEmitter::EmitCallingConv(Record *CC, std::ostream &O) { + ListInit *CCActions = CC->getValueAsListInit("Actions"); + Counter = 0; + + O << "\n\nstatic bool " << CC->getName() + << "(unsigned ValNo, MVT ValVT,\n" + << std::string(CC->getName().size()+13, ' ') + << "MVT LocVT, CCValAssign::LocInfo LocInfo,\n" + << std::string(CC->getName().size()+13, ' ') + << "ISD::ArgFlagsTy ArgFlags, CCState &State) {\n"; + // Emit all of the actions, in order. + for (unsigned i = 0, e = CCActions->getSize(); i != e; ++i) { + O << "\n"; + EmitAction(CCActions->getElementAsRecord(i), 2, O); + } + + O << "\n return true; // CC didn't match.\n"; + O << "}\n"; +} + +void CallingConvEmitter::EmitAction(Record *Action, + unsigned Indent, std::ostream &O) { + std::string IndentStr = std::string(Indent, ' '); + + if (Action->isSubClassOf("CCPredicateAction")) { + O << IndentStr << "if ("; + + if (Action->isSubClassOf("CCIfType")) { + ListInit *VTs = Action->getValueAsListInit("VTs"); + for (unsigned i = 0, e = VTs->getSize(); i != e; ++i) { + Record *VT = VTs->getElementAsRecord(i); + if (i != 0) O << " ||\n " << IndentStr; + O << "LocVT == " << getEnumName(getValueType(VT)); + } + + } else if (Action->isSubClassOf("CCIf")) { + O << Action->getValueAsString("Predicate"); + } else { + Action->dump(); + throw "Unknown CCPredicateAction!"; + } + + O << ") {\n"; + EmitAction(Action->getValueAsDef("SubAction"), Indent+2, O); + O << IndentStr << "}\n"; + } else { + if (Action->isSubClassOf("CCDelegateTo")) { + Record *CC = Action->getValueAsDef("CC"); + O << IndentStr << "if (!" << CC->getName() + << "(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State))\n" + << IndentStr << " return false;\n"; + } else if (Action->isSubClassOf("CCAssignToReg")) { + ListInit *RegList = Action->getValueAsListInit("RegList"); + if (RegList->getSize() == 1) { + O << IndentStr << "if (unsigned Reg = State.AllocateReg("; + O << getQualifiedName(RegList->getElementAsRecord(0)) << ")) {\n"; + } else { + O << IndentStr << "static const unsigned RegList" << ++Counter + << "[] = {\n"; + O << IndentStr << " "; + for (unsigned i = 0, e = RegList->getSize(); i != e; ++i) { + if (i != 0) O << ", "; + O << getQualifiedName(RegList->getElementAsRecord(i)); + } + O << "\n" << IndentStr << "};\n"; + O << IndentStr << "if (unsigned Reg = State.AllocateReg(RegList" + << Counter << ", " << RegList->getSize() << ")) {\n"; + } + O << IndentStr << " State.addLoc(CCValAssign::getReg(ValNo, ValVT, " + << "Reg, LocVT, LocInfo));\n"; + O << IndentStr << " return false;\n"; + O << IndentStr << "}\n"; + } else if (Action->isSubClassOf("CCAssignToRegWithShadow")) { + ListInit *RegList = Action->getValueAsListInit("RegList"); + ListInit *ShadowRegList = Action->getValueAsListInit("ShadowRegList"); + if (ShadowRegList->getSize() >0 && + ShadowRegList->getSize() != RegList->getSize()) + throw "Invalid length of list of shadowed registers"; + + if (RegList->getSize() == 1) { + O << IndentStr << "if (unsigned Reg = State.AllocateReg("; + O << getQualifiedName(RegList->getElementAsRecord(0)); + O << ", " << getQualifiedName(ShadowRegList->getElementAsRecord(0)); + O << ")) {\n"; + } else { + unsigned RegListNumber = ++Counter; + unsigned ShadowRegListNumber = ++Counter; + + O << IndentStr << "static const unsigned RegList" << RegListNumber + << "[] = {\n"; + O << IndentStr << " "; + for (unsigned i = 0, e = RegList->getSize(); i != e; ++i) { + if (i != 0) O << ", "; + O << getQualifiedName(RegList->getElementAsRecord(i)); + } + O << "\n" << IndentStr << "};\n"; + + O << IndentStr << "static const unsigned RegList" + << ShadowRegListNumber << "[] = {\n"; + O << IndentStr << " "; + for (unsigned i = 0, e = ShadowRegList->getSize(); i != e; ++i) { + if (i != 0) O << ", "; + O << getQualifiedName(ShadowRegList->getElementAsRecord(i)); + } + O << "\n" << IndentStr << "};\n"; + + O << IndentStr << "if (unsigned Reg = State.AllocateReg(RegList" + << RegListNumber << ", " << "RegList" << ShadowRegListNumber + << ", " << RegList->getSize() << ")) {\n"; + } + O << IndentStr << " State.addLoc(CCValAssign::getReg(ValNo, ValVT, " + << "Reg, LocVT, LocInfo));\n"; + O << IndentStr << " return false;\n"; + O << IndentStr << "}\n"; + } else if (Action->isSubClassOf("CCAssignToStack")) { + int Size = Action->getValueAsInt("Size"); + int Align = Action->getValueAsInt("Align"); + + O << IndentStr << "unsigned Offset" << ++Counter + << " = State.AllocateStack("; + if (Size) + O << Size << ", "; + else + O << "\n" << IndentStr << " State.getTarget().getTargetData()" + "->getTypeAllocSize(LocVT.getTypeForMVT()), "; + if (Align) + O << Align; + else + O << "\n" << IndentStr << " State.getTarget().getTargetData()" + "->getABITypeAlignment(LocVT.getTypeForMVT())"; + O << ");\n" << IndentStr + << "State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset" + << Counter << ", LocVT, LocInfo));\n"; + O << IndentStr << "return false;\n"; + } else if (Action->isSubClassOf("CCPromoteToType")) { + Record *DestTy = Action->getValueAsDef("DestTy"); + O << IndentStr << "LocVT = " << getEnumName(getValueType(DestTy)) <<";\n"; + O << IndentStr << "if (ArgFlags.isSExt())\n" + << IndentStr << IndentStr << "LocInfo = CCValAssign::SExt;\n" + << IndentStr << "else if (ArgFlags.isZExt())\n" + << IndentStr << IndentStr << "LocInfo = CCValAssign::ZExt;\n" + << IndentStr << "else\n" + << IndentStr << IndentStr << "LocInfo = CCValAssign::AExt;\n"; + } else if (Action->isSubClassOf("CCBitConvertToType")) { + Record *DestTy = Action->getValueAsDef("DestTy"); + O << IndentStr << "LocVT = " << getEnumName(getValueType(DestTy)) <<";\n"; + O << IndentStr << "LocInfo = CCValAssign::BCvt;\n"; + } else if (Action->isSubClassOf("CCPassByVal")) { + int Size = Action->getValueAsInt("Size"); + int Align = Action->getValueAsInt("Align"); + O << IndentStr + << "State.HandleByVal(ValNo, ValVT, LocVT, LocInfo, " + << Size << ", " << Align << ", ArgFlags);\n"; + O << IndentStr << "return false;\n"; + } else if (Action->isSubClassOf("CCCustom")) { + O << IndentStr + << "if (" << Action->getValueAsString("FuncName") << "(ValNo, ValVT, " + << "LocVT, LocInfo, ArgFlags, State))\n"; + O << IndentStr << IndentStr << "return false;\n"; + } else { + Action->dump(); + throw "Unknown CCAction!"; + } + } +} diff --git a/utils/TableGen/CallingConvEmitter.h b/utils/TableGen/CallingConvEmitter.h new file mode 100644 index 0000000000000..ffd6a48c7ad65 --- /dev/null +++ b/utils/TableGen/CallingConvEmitter.h @@ -0,0 +1,38 @@ +//===- CallingConvEmitter.h - Generate calling conventions ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend is responsible for emitting descriptions of the calling +// conventions supported by this target. +// +//===----------------------------------------------------------------------===// + +#ifndef CALLINGCONV_EMITTER_H +#define CALLINGCONV_EMITTER_H + +#include "TableGenBackend.h" +#include <map> +#include <vector> +#include <cassert> + +namespace llvm { + class CallingConvEmitter : public TableGenBackend { + RecordKeeper &Records; + public: + explicit CallingConvEmitter(RecordKeeper &R) : Records(R) {} + + // run - Output the asmwriter, returning true on failure. + void run(std::ostream &o); + + private: + void EmitCallingConv(Record *CC, std::ostream &O); + void EmitAction(Record *Action, unsigned Indent, std::ostream &O); + unsigned Counter; + }; +} +#endif diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp new file mode 100644 index 0000000000000..919ae9befed32 --- /dev/null +++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp @@ -0,0 +1,169 @@ +//=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*- +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// These tablegen backends emit Clang diagnostics tables. +// +//===----------------------------------------------------------------------===// + +#include "ClangDiagnosticsEmitter.h" +#include "Record.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Streams.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/VectorExtras.h" +#include <set> +#include <map> +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Warning Tables (.inc file) generation. +//===----------------------------------------------------------------------===// + +void ClangDiagsDefsEmitter::run(std::ostream &OS) { + // Write the #if guard + if (!Component.empty()) { + std::string ComponentName = UppercaseString(Component); + OS << "#ifdef " << ComponentName << "START\n"; + OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName + << ",\n"; + OS << "#undef " << ComponentName << "START\n"; + OS << "#endif\n"; + } + + const std::vector<Record*> &Diags = + Records.getAllDerivedDefinitions("Diagnostic"); + + for (unsigned i = 0, e = Diags.size(); i != e; ++i) { + const Record &R = *Diags[i]; + // Filter by component. + if (!Component.empty() && Component != R.getValueAsString("Component")) + continue; + + OS << "DIAG(" << R.getName() << ", "; + OS << R.getValueAsDef("Class")->getName(); + OS << ", diag::" << R.getValueAsDef("DefaultMapping")->getName(); + + // Description string. + OS << ", \""; + std::string S = R.getValueAsString("Text"); + EscapeString(S); + OS << S << "\""; + + // Warning associated with the diagnostic. + if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) { + S = DI->getDef()->getValueAsString("GroupName"); + EscapeString(S); + OS << ", \"" << S << "\""; + } else { + OS << ", 0"; + } + OS << ")\n"; + } +} + +//===----------------------------------------------------------------------===// +// Warning Group Tables generation +//===----------------------------------------------------------------------===// + +struct GroupInfo { + std::vector<const Record*> DiagsInGroup; + std::vector<std::string> SubGroups; + unsigned IDNo; +}; + +void ClangDiagGroupsEmitter::run(std::ostream &OS) { + // Invert the 1-[0/1] mapping of diags to group into a one to many mapping of + // groups to diags in the group. + std::map<std::string, GroupInfo> DiagsInGroup; + + std::vector<Record*> Diags = + Records.getAllDerivedDefinitions("Diagnostic"); + for (unsigned i = 0, e = Diags.size(); i != e; ++i) { + const Record *R = Diags[i]; + DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group")); + if (DI == 0) continue; + std::string GroupName = DI->getDef()->getValueAsString("GroupName"); + DiagsInGroup[GroupName].DiagsInGroup.push_back(R); + } + + // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty + // groups (these are warnings that GCC supports that clang never produces). + Diags = Records.getAllDerivedDefinitions("DiagGroup"); + for (unsigned i = 0, e = Diags.size(); i != e; ++i) { + Record *Group = Diags[i]; + GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")]; + + std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups"); + for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) + GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName")); + } + + // Assign unique ID numbers to the groups. + unsigned IDNo = 0; + for (std::map<std::string, GroupInfo>::iterator + I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo) + I->second.IDNo = IDNo; + + // Walk through the groups emitting an array for each diagnostic of the diags + // that are mapped to. + OS << "\n#ifdef GET_DIAG_ARRAYS\n"; + unsigned MaxLen = 0; + for (std::map<std::string, GroupInfo>::iterator + I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { + MaxLen = std::max(MaxLen, (unsigned)I->first.size()); + + std::vector<const Record*> &V = I->second.DiagsInGroup; + if (!V.empty()) { + OS << "static const short DiagArray" << I->second.IDNo << "[] = { "; + for (unsigned i = 0, e = V.size(); i != e; ++i) + OS << "diag::" << V[i]->getName() << ", "; + OS << "-1 };\n"; + } + + const std::vector<std::string> &SubGroups = I->second.SubGroups; + if (!SubGroups.empty()) { + OS << "static const char DiagSubGroup" << I->second.IDNo << "[] = { "; + for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) { + std::map<std::string, GroupInfo>::iterator RI = + DiagsInGroup.find(SubGroups[i]); + assert(RI != DiagsInGroup.end() && "Referenced without existing?"); + OS << RI->second.IDNo << ", "; + } + OS << "-1 };\n"; + } + } + OS << "#endif // GET_DIAG_ARRAYS\n\n"; + + // Emit the table now. + OS << "\n#ifdef GET_DIAG_TABLE\n"; + for (std::map<std::string, GroupInfo>::iterator + I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { + std::string S = I->first; + EscapeString(S); + // Group option string. + OS << " { \"" << S << "\"," + << std::string(MaxLen-I->first.size()+1, ' '); + + // Diagnostics in the group. + if (I->second.DiagsInGroup.empty()) + OS << "0, "; + else + OS << "DiagArray" << I->second.IDNo << ", "; + + // Subgroups. + if (I->second.SubGroups.empty()) + OS << 0; + else + OS << "DiagSubGroup" << I->second.IDNo; + OS << " },\n"; + } + OS << "#endif // GET_DIAG_TABLE\n\n"; +} diff --git a/utils/TableGen/ClangDiagnosticsEmitter.h b/utils/TableGen/ClangDiagnosticsEmitter.h new file mode 100644 index 0000000000000..58ea524d96477 --- /dev/null +++ b/utils/TableGen/ClangDiagnosticsEmitter.h @@ -0,0 +1,46 @@ +//===- ClangDiagnosticsEmitter.h - Generate Clang diagnostics tables -*- C++ -*- +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// These tablegen backends emit Clang diagnostics tables. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANGDIAGS_EMITTER_H +#define CLANGDIAGS_EMITTER_H + +#include "TableGenBackend.h" + +namespace llvm { + +/// ClangDiagsDefsEmitter - The top-level class emits .def files containing +/// declarations of Clang diagnostics. +/// +class ClangDiagsDefsEmitter : public TableGenBackend { + RecordKeeper &Records; + const std::string& Component; +public: + explicit ClangDiagsDefsEmitter(RecordKeeper &R, const std::string& component) + : Records(R), Component(component) {} + + // run - Output the .def file contents + void run(std::ostream &OS); +}; + +class ClangDiagGroupsEmitter : public TableGenBackend { + RecordKeeper &Records; +public: + explicit ClangDiagGroupsEmitter(RecordKeeper &R) : Records(R) {} + + void run(std::ostream &OS); +}; + + +} // End llvm namespace + +#endif diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp new file mode 100644 index 0000000000000..7b0a335b26be1 --- /dev/null +++ b/utils/TableGen/CodeEmitterGen.cpp @@ -0,0 +1,251 @@ +//===- CodeEmitterGen.cpp - Code Emitter Generator ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// CodeEmitterGen uses the descriptions of instructions and their fields to +// construct an automated code emitter: a function that, given a MachineInstr, +// returns the (currently, 32-bit unsigned) value of the instruction. +// +//===----------------------------------------------------------------------===// + +#include "CodeEmitterGen.h" +#include "CodeGenTarget.h" +#include "Record.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Debug.h" +using namespace llvm; + +void CodeEmitterGen::reverseBits(std::vector<Record*> &Insts) { + for (std::vector<Record*>::iterator I = Insts.begin(), E = Insts.end(); + I != E; ++I) { + Record *R = *I; + if (R->getName() == "PHI" || + R->getName() == "INLINEASM" || + R->getName() == "DBG_LABEL" || + R->getName() == "EH_LABEL" || + R->getName() == "GC_LABEL" || + R->getName() == "DECLARE" || + R->getName() == "EXTRACT_SUBREG" || + R->getName() == "INSERT_SUBREG" || + R->getName() == "IMPLICIT_DEF" || + R->getName() == "SUBREG_TO_REG" || + R->getName() == "COPY_TO_REGCLASS") continue; + + BitsInit *BI = R->getValueAsBitsInit("Inst"); + + unsigned numBits = BI->getNumBits(); + BitsInit *NewBI = new BitsInit(numBits); + for (unsigned bit = 0, end = numBits / 2; bit != end; ++bit) { + unsigned bitSwapIdx = numBits - bit - 1; + Init *OrigBit = BI->getBit(bit); + Init *BitSwap = BI->getBit(bitSwapIdx); + NewBI->setBit(bit, BitSwap); + NewBI->setBit(bitSwapIdx, OrigBit); + } + if (numBits % 2) { + unsigned middle = (numBits + 1) / 2; + NewBI->setBit(middle, BI->getBit(middle)); + } + + // Update the bits in reversed order so that emitInstrOpBits will get the + // correct endianness. + R->getValue("Inst")->setValue(NewBI); + } +} + + +// If the VarBitInit at position 'bit' matches the specified variable then +// 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))) { + TypedInit *TI = VBI->getVariable(); + + if (VarInit *VI = dynamic_cast<VarInit*>(TI)) { + if (VI->getName() == VarName) return VBI->getBitNum(); + } + } + + return -1; +} + + +void CodeEmitterGen::run(std::ostream &o) { + CodeGenTarget Target; + std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction"); + + // For little-endian instruction bit encodings, reverse the bit order + if (Target.isLittleEndianEncoding()) reverseBits(Insts); + + EmitSourceFileHeader("Machine Code Emitter", o); + std::string Namespace = Insts[0]->getValueAsString("Namespace") + "::"; + + std::vector<const CodeGenInstruction*> NumberedInstructions; + Target.getInstructionsByEnumValue(NumberedInstructions); + + // Emit function declaration + o << "unsigned " << Target.getName() << "CodeEmitter::" + << "getBinaryCodeForInstr(const MachineInstr &MI) {\n"; + + // Emit instruction base values + o << " static const unsigned InstBits[] = {\n"; + for (std::vector<const CodeGenInstruction*>::iterator + IN = NumberedInstructions.begin(), + EN = NumberedInstructions.end(); + IN != EN; ++IN) { + const CodeGenInstruction *CGI = *IN; + Record *R = CGI->TheDef; + + if (R->getName() == "PHI" || + R->getName() == "INLINEASM" || + R->getName() == "DBG_LABEL" || + R->getName() == "EH_LABEL" || + R->getName() == "GC_LABEL" || + R->getName() == "DECLARE" || + R->getName() == "EXTRACT_SUBREG" || + R->getName() == "INSERT_SUBREG" || + R->getName() == "IMPLICIT_DEF" || + R->getName() == "SUBREG_TO_REG" || + R->getName() == "COPY_TO_REGCLASS") { + o << " 0U,\n"; + continue; + } + + BitsInit *BI = R->getValueAsBitsInit("Inst"); + + // Start by filling in fixed values... + unsigned Value = 0; + for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i) { + if (BitInit *B = dynamic_cast<BitInit*>(BI->getBit(e-i-1))) { + Value |= B->getValue() << (e-i-1); + } + } + o << " " << Value << "U," << '\t' << "// " << R->getName() << "\n"; + } + o << " 0U\n };\n"; + + // Map to accumulate all the cases. + std::map<std::string, std::vector<std::string> > CaseMap; + + // Construct all cases statement for each opcode + for (std::vector<Record*>::iterator IC = Insts.begin(), EC = Insts.end(); + IC != EC; ++IC) { + Record *R = *IC; + const std::string &InstName = R->getName(); + std::string Case(""); + + if (InstName == "PHI" || + InstName == "INLINEASM" || + InstName == "DBG_LABEL"|| + InstName == "EH_LABEL"|| + InstName == "GC_LABEL"|| + InstName == "DECLARE"|| + InstName == "EXTRACT_SUBREG" || + InstName == "INSERT_SUBREG" || + InstName == "IMPLICIT_DEF" || + InstName == "SUBREG_TO_REG" || + InstName == "COPY_TO_REGCLASS") continue; + + BitsInit *BI = R->getValueAsBitsInit("Inst"); + const std::vector<RecordVal> &Vals = R->getValues(); + CodeGenInstruction &CGI = Target.getInstruction(InstName); + + // Loop over all of the fields in the instruction, determining which are the + // operands to the instruction. + unsigned op = 0; + for (unsigned i = 0, e = Vals.size(); i != e; ++i) { + if (!Vals[i].getPrefix() && !Vals[i].getValue()->isComplete()) { + // Is the operand continuous? If so, we can just mask and OR it in + // instead of doing it bit-by-bit, saving a lot in runtime cost. + const std::string &VarName = Vals[i].getName(); + bool gotOp = false; + + for (int bit = BI->getNumBits()-1; bit >= 0; ) { + int varBit = getVariableBit(VarName, BI, bit); + + if (varBit == -1) { + --bit; + } else { + int beginInstBit = bit; + int beginVarBit = varBit; + int N = 1; + + for (--bit; bit >= 0;) { + varBit = getVariableBit(VarName, BI, bit); + if (varBit == -1 || varBit != (beginVarBit - N)) break; + ++N; + --bit; + } + + if (!gotOp) { + /// If this operand is not supposed to be emitted by the generated + /// emitter, skip it. + while (CGI.isFlatOperandNotEmitted(op)) + ++op; + + Case += " // op: " + VarName + "\n" + + " op = getMachineOpValue(MI, MI.getOperand(" + + utostr(op++) + "));\n"; + gotOp = true; + } + + unsigned opMask = ~0U >> (32-N); + int opShift = beginVarBit - N + 1; + opMask <<= opShift; + opShift = beginInstBit - beginVarBit; + + if (opShift > 0) { + Case += " Value |= (op & " + utostr(opMask) + "U) << " + + itostr(opShift) + ";\n"; + } else if (opShift < 0) { + Case += " Value |= (op & " + utostr(opMask) + "U) >> " + + itostr(-opShift) + ";\n"; + } else { + Case += " Value |= op & " + utostr(opMask) + "U;\n"; + } + } + } + } + } + + std::vector<std::string> &InstList = CaseMap[Case]; + InstList.push_back(InstName); + } + + + // Emit initial function code + o << " const unsigned opcode = MI.getOpcode();\n" + << " unsigned Value = InstBits[opcode];\n" + << " unsigned op = 0;\n" + << " op = op; // suppress warning\n" + << " switch (opcode) {\n"; + + // Emit each case statement + std::map<std::string, std::vector<std::string> >::iterator IE, EE; + for (IE = CaseMap.begin(), EE = CaseMap.end(); IE != EE; ++IE) { + const std::string &Case = IE->first; + std::vector<std::string> &InstList = IE->second; + + for (int i = 0, N = InstList.size(); i < N; i++) { + if (i) o << "\n"; + o << " case " << Namespace << InstList[i] << ":"; + } + o << " {\n"; + o << Case; + o << " break;\n" + << " }\n"; + } + + // Default case: unhandled opcode + o << " default:\n" + << " cerr << \"Not supported instr: \" << MI << \"\\n\";\n" + << " abort();\n" + << " }\n" + << " return Value;\n" + << "}\n\n"; +} diff --git a/utils/TableGen/CodeEmitterGen.h b/utils/TableGen/CodeEmitterGen.h new file mode 100644 index 0000000000000..cb272bd56d25e --- /dev/null +++ b/utils/TableGen/CodeEmitterGen.h @@ -0,0 +1,43 @@ +//===- CodeEmitterGen.h - Code Emitter Generator ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// FIXME: document +// +//===----------------------------------------------------------------------===// + +#ifndef CODEMITTERGEN_H +#define CODEMITTERGEN_H + +#include "TableGenBackend.h" +#include <map> +#include <vector> +#include <string> + +namespace llvm { + +class RecordVal; +class BitsInit; + +class CodeEmitterGen : public TableGenBackend { + RecordKeeper &Records; +public: + CodeEmitterGen(RecordKeeper &R) : Records(R) {} + + // run - Output the code emitter + void run(std::ostream &o); +private: + void emitMachineOpEmitter(std::ostream &o, const std::string &Namespace); + void emitGetValueBit(std::ostream &o, const std::string &Namespace); + void reverseBits(std::vector<Record*> &Insts); + int getVariableBit(const std::string &VarName, BitsInit *BI, int bit); +}; + +} // End llvm namespace + +#endif diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp new file mode 100644 index 0000000000000..db76dabb53758 --- /dev/null +++ b/utils/TableGen/CodeGenDAGPatterns.cpp @@ -0,0 +1,2395 @@ +//===- CodeGenDAGPatterns.cpp - Read DAG patterns from .td file -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the CodeGenDAGPatterns class, which is used to read and +// represent the patterns present in a .td file for instructions. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenDAGPatterns.h" +#include "Record.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Streams.h" +#include <set> +#include <algorithm> +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Helpers for working with extended types. + +/// FilterVTs - Filter a list of VT's according to a predicate. +/// +template<typename T> +static std::vector<MVT::SimpleValueType> +FilterVTs(const std::vector<MVT::SimpleValueType> &InVTs, T Filter) { + std::vector<MVT::SimpleValueType> Result; + for (unsigned i = 0, e = InVTs.size(); i != e; ++i) + if (Filter(InVTs[i])) + Result.push_back(InVTs[i]); + return Result; +} + +template<typename T> +static std::vector<unsigned char> +FilterEVTs(const std::vector<unsigned char> &InVTs, T Filter) { + std::vector<unsigned char> Result; + for (unsigned i = 0, e = InVTs.size(); i != e; ++i) + if (Filter((MVT::SimpleValueType)InVTs[i])) + Result.push_back(InVTs[i]); + return Result; +} + +static std::vector<unsigned char> +ConvertVTs(const std::vector<MVT::SimpleValueType> &InVTs) { + std::vector<unsigned char> Result; + for (unsigned i = 0, e = InVTs.size(); i != e; ++i) + Result.push_back(InVTs[i]); + return Result; +} + +static inline bool isInteger(MVT::SimpleValueType VT) { + return MVT(VT).isInteger(); +} + +static inline bool isFloatingPoint(MVT::SimpleValueType VT) { + return MVT(VT).isFloatingPoint(); +} + +static inline bool isVector(MVT::SimpleValueType VT) { + return MVT(VT).isVector(); +} + +static bool LHSIsSubsetOfRHS(const std::vector<unsigned char> &LHS, + const std::vector<unsigned char> &RHS) { + if (LHS.size() > RHS.size()) return false; + for (unsigned i = 0, e = LHS.size(); i != e; ++i) + if (std::find(RHS.begin(), RHS.end(), LHS[i]) == RHS.end()) + return false; + return true; +} + +namespace llvm { +namespace EMVT { +/// isExtIntegerInVTs - Return true if the specified extended value type vector +/// contains isInt or an integer value type. +bool isExtIntegerInVTs(const std::vector<unsigned char> &EVTs) { + assert(!EVTs.empty() && "Cannot check for integer in empty ExtVT list!"); + return EVTs[0] == isInt || !(FilterEVTs(EVTs, isInteger).empty()); +} + +/// isExtFloatingPointInVTs - Return true if the specified extended value type +/// vector contains isFP or a FP value type. +bool isExtFloatingPointInVTs(const std::vector<unsigned char> &EVTs) { + assert(!EVTs.empty() && "Cannot check for integer in empty ExtVT list!"); + return EVTs[0] == isFP || !(FilterEVTs(EVTs, isFloatingPoint).empty()); +} +} // end namespace EMVT. +} // end namespace llvm. + + +/// Dependent variable map for CodeGenDAGPattern variant generation +typedef std::map<std::string, int> DepVarMap; + +/// Const iterator shorthand for DepVarMap +typedef DepVarMap::const_iterator DepVarMap_citer; + +namespace { +void FindDepVarsOf(TreePatternNode *N, DepVarMap &DepMap) { + if (N->isLeaf()) { + if (dynamic_cast<DefInit*>(N->getLeafValue()) != NULL) { + DepMap[N->getName()]++; + } + } else { + for (size_t i = 0, e = N->getNumChildren(); i != e; ++i) + FindDepVarsOf(N->getChild(i), DepMap); + } +} + +//! Find dependent variables within child patterns +/*! + */ +void FindDepVars(TreePatternNode *N, MultipleUseVarSet &DepVars) { + DepVarMap depcounts; + FindDepVarsOf(N, depcounts); + for (DepVarMap_citer i = depcounts.begin(); i != depcounts.end(); ++i) { + if (i->second > 1) { // std::pair<std::string, int> + DepVars.insert(i->first); + } + } +} + +//! Dump the dependent variable set: +void DumpDepVars(MultipleUseVarSet &DepVars) { + if (DepVars.empty()) { + DOUT << "<empty set>"; + } else { + DOUT << "[ "; + for (MultipleUseVarSet::const_iterator i = DepVars.begin(), e = DepVars.end(); + i != e; ++i) { + DOUT << (*i) << " "; + } + DOUT << "]"; + } +} +} + +//===----------------------------------------------------------------------===// +// PatternToMatch implementation +// + +/// getPredicateCheck - Return a single string containing all of this +/// pattern's predicates concatenated with "&&" operators. +/// +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))) { + Record *Def = Pred->getDef(); + if (!Def->isSubClassOf("Predicate")) { +#ifndef NDEBUG + Def->dump(); +#endif + assert(0 && "Unknown predicate type!"); + } + if (!PredicateCheck.empty()) + PredicateCheck += " && "; + PredicateCheck += "(" + Def->getValueAsString("CondString") + ")"; + } + } + + return PredicateCheck; +} + +//===----------------------------------------------------------------------===// +// SDTypeConstraint implementation +// + +SDTypeConstraint::SDTypeConstraint(Record *R) { + OperandNo = R->getValueAsInt("OperandNum"); + + if (R->isSubClassOf("SDTCisVT")) { + ConstraintType = SDTCisVT; + x.SDTCisVT_Info.VT = getValueType(R->getValueAsDef("VT")); + } else if (R->isSubClassOf("SDTCisPtrTy")) { + ConstraintType = SDTCisPtrTy; + } else if (R->isSubClassOf("SDTCisInt")) { + ConstraintType = SDTCisInt; + } else if (R->isSubClassOf("SDTCisFP")) { + ConstraintType = SDTCisFP; + } else if (R->isSubClassOf("SDTCisSameAs")) { + ConstraintType = SDTCisSameAs; + x.SDTCisSameAs_Info.OtherOperandNum = R->getValueAsInt("OtherOperandNum"); + } else if (R->isSubClassOf("SDTCisVTSmallerThanOp")) { + ConstraintType = SDTCisVTSmallerThanOp; + x.SDTCisVTSmallerThanOp_Info.OtherOperandNum = + R->getValueAsInt("OtherOperandNum"); + } else if (R->isSubClassOf("SDTCisOpSmallerThanOp")) { + ConstraintType = SDTCisOpSmallerThanOp; + x.SDTCisOpSmallerThanOp_Info.BigOperandNum = + R->getValueAsInt("BigOperandNum"); + } else if (R->isSubClassOf("SDTCisEltOfVec")) { + ConstraintType = SDTCisEltOfVec; + x.SDTCisEltOfVec_Info.OtherOperandNum = + R->getValueAsInt("OtherOpNum"); + } else { + cerr << "Unrecognized SDTypeConstraint '" << R->getName() << "'!\n"; + exit(1); + } +} + +/// getOperandNum - Return the node corresponding to operand #OpNo in tree +/// N, which has NumResults results. +TreePatternNode *SDTypeConstraint::getOperandNum(unsigned OpNo, + TreePatternNode *N, + unsigned NumResults) const { + assert(NumResults <= 1 && + "We only work with nodes with zero or one result so far!"); + + if (OpNo >= (NumResults + N->getNumChildren())) { + cerr << "Invalid operand number " << OpNo << " "; + N->dump(); + cerr << '\n'; + exit(1); + } + + if (OpNo < NumResults) + return N; // FIXME: need value # + else + return N->getChild(OpNo-NumResults); +} + +/// 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. +bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N, + const SDNodeInfo &NodeInfo, + TreePattern &TP) const { + unsigned NumResults = NodeInfo.getNumResults(); + assert(NumResults <= 1 && + "We only work with nodes with zero or one result so far!"); + + // Check that the number of operands is sane. Negative operands -> varargs. + if (NodeInfo.getNumOperands() >= 0) { + if (N->getNumChildren() != (unsigned)NodeInfo.getNumOperands()) + TP.error(N->getOperator()->getName() + " node requires exactly " + + itostr(NodeInfo.getNumOperands()) + " operands!"); + } + + const CodeGenTarget &CGT = TP.getDAGPatterns().getTargetInfo(); + + TreePatternNode *NodeToApply = getOperandNum(OperandNo, N, NumResults); + + switch (ConstraintType) { + default: assert(0 && "Unknown constraint type!"); + case SDTCisVT: + // Operand must be a particular type. + return NodeToApply->UpdateNodeType(x.SDTCisVT_Info.VT, TP); + case SDTCisPtrTy: { + // Operand must be same as target pointer type. + return NodeToApply->UpdateNodeType(MVT::iPTR, TP); + } + case SDTCisInt: { + // If there is only one integer type supported, this must be it. + std::vector<MVT::SimpleValueType> IntVTs = + FilterVTs(CGT.getLegalValueTypes(), isInteger); + + // If we found exactly one supported integer type, apply it. + if (IntVTs.size() == 1) + return NodeToApply->UpdateNodeType(IntVTs[0], TP); + return NodeToApply->UpdateNodeType(EMVT::isInt, TP); + } + case SDTCisFP: { + // If there is only one FP type supported, this must be it. + std::vector<MVT::SimpleValueType> FPVTs = + FilterVTs(CGT.getLegalValueTypes(), isFloatingPoint); + + // If we found exactly one supported FP type, apply it. + if (FPVTs.size() == 1) + return NodeToApply->UpdateNodeType(FPVTs[0], TP); + return NodeToApply->UpdateNodeType(EMVT::isFP, TP); + } + case SDTCisSameAs: { + TreePatternNode *OtherNode = + getOperandNum(x.SDTCisSameAs_Info.OtherOperandNum, N, NumResults); + return NodeToApply->UpdateNodeType(OtherNode->getExtTypes(), TP) | + OtherNode->UpdateNodeType(NodeToApply->getExtTypes(), TP); + } + case SDTCisVTSmallerThanOp: { + // 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()) || + !static_cast<DefInit*>(NodeToApply->getLeafValue())->getDef() + ->isSubClassOf("ValueType")) + TP.error(N->getOperator()->getName() + " expects a VT operand!"); + MVT::SimpleValueType VT = + getValueType(static_cast<DefInit*>(NodeToApply->getLeafValue())->getDef()); + if (!isInteger(VT)) + TP.error(N->getOperator()->getName() + " VT operand must be integer!"); + + TreePatternNode *OtherNode = + getOperandNum(x.SDTCisVTSmallerThanOp_Info.OtherOperandNum, N,NumResults); + + // It must be integer. + bool MadeChange = false; + MadeChange |= OtherNode->UpdateNodeType(EMVT::isInt, TP); + + // This code only handles nodes that have one type set. Assert here so + // that we can change this if we ever need to deal with multiple value + // types at this point. + assert(OtherNode->getExtTypes().size() == 1 && "Node has too many types!"); + if (OtherNode->hasTypeSet() && OtherNode->getTypeNum(0) <= VT) + OtherNode->UpdateNodeType(MVT::Other, TP); // Throw an error. + return false; + } + case SDTCisOpSmallerThanOp: { + TreePatternNode *BigOperand = + getOperandNum(x.SDTCisOpSmallerThanOp_Info.BigOperandNum, N, NumResults); + + // Both operands must be integer or FP, but we don't care which. + bool MadeChange = false; + + // This code does not currently handle nodes which have multiple types, + // where some types are integer, and some are fp. Assert that this is not + // the case. + assert(!(EMVT::isExtIntegerInVTs(NodeToApply->getExtTypes()) && + EMVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes())) && + !(EMVT::isExtIntegerInVTs(BigOperand->getExtTypes()) && + EMVT::isExtFloatingPointInVTs(BigOperand->getExtTypes())) && + "SDTCisOpSmallerThanOp does not handle mixed int/fp types!"); + if (EMVT::isExtIntegerInVTs(NodeToApply->getExtTypes())) + MadeChange |= BigOperand->UpdateNodeType(EMVT::isInt, TP); + else if (EMVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes())) + MadeChange |= BigOperand->UpdateNodeType(EMVT::isFP, TP); + if (EMVT::isExtIntegerInVTs(BigOperand->getExtTypes())) + MadeChange |= NodeToApply->UpdateNodeType(EMVT::isInt, TP); + else if (EMVT::isExtFloatingPointInVTs(BigOperand->getExtTypes())) + MadeChange |= NodeToApply->UpdateNodeType(EMVT::isFP, TP); + + std::vector<MVT::SimpleValueType> VTs = CGT.getLegalValueTypes(); + + if (EMVT::isExtIntegerInVTs(NodeToApply->getExtTypes())) { + VTs = FilterVTs(VTs, isInteger); + } else if (EMVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes())) { + VTs = FilterVTs(VTs, isFloatingPoint); + } else { + VTs.clear(); + } + + switch (VTs.size()) { + default: // Too many VT's to pick from. + case 0: break; // No info yet. + case 1: + // Only one VT of this flavor. Cannot ever satisfy the constraints. + return NodeToApply->UpdateNodeType(MVT::Other, TP); // throw + case 2: + // If we have exactly two possible types, the little operand must be the + // small one, the big operand should be the big one. Common with + // float/double for example. + assert(VTs[0] < VTs[1] && "Should be sorted!"); + MadeChange |= NodeToApply->UpdateNodeType(VTs[0], TP); + MadeChange |= BigOperand->UpdateNodeType(VTs[1], TP); + break; + } + return MadeChange; + } + case SDTCisEltOfVec: { + TreePatternNode *OtherOperand = + getOperandNum(x.SDTCisEltOfVec_Info.OtherOperandNum, + N, NumResults); + if (OtherOperand->hasTypeSet()) { + if (!isVector(OtherOperand->getTypeNum(0))) + TP.error(N->getOperator()->getName() + " VT operand must be a vector!"); + MVT IVT = OtherOperand->getTypeNum(0); + IVT = IVT.getVectorElementType(); + return NodeToApply->UpdateNodeType(IVT.getSimpleVT(), TP); + } + return false; + } + } + return false; +} + +//===----------------------------------------------------------------------===// +// SDNodeInfo implementation +// +SDNodeInfo::SDNodeInfo(Record *R) : Def(R) { + EnumName = R->getValueAsString("Opcode"); + SDClassName = R->getValueAsString("SDClass"); + Record *TypeProfile = R->getValueAsDef("TypeProfile"); + NumResults = TypeProfile->getValueAsInt("NumResults"); + NumOperands = TypeProfile->getValueAsInt("NumOperands"); + + // Parse the properties. + Properties = 0; + std::vector<Record*> PropList = R->getValueAsListOfDefs("Properties"); + for (unsigned i = 0, e = PropList.size(); i != e; ++i) { + if (PropList[i]->getName() == "SDNPCommutative") { + Properties |= 1 << SDNPCommutative; + } else if (PropList[i]->getName() == "SDNPAssociative") { + Properties |= 1 << SDNPAssociative; + } else if (PropList[i]->getName() == "SDNPHasChain") { + Properties |= 1 << SDNPHasChain; + } else if (PropList[i]->getName() == "SDNPOutFlag") { + Properties |= 1 << SDNPOutFlag; + } else if (PropList[i]->getName() == "SDNPInFlag") { + Properties |= 1 << SDNPInFlag; + } else if (PropList[i]->getName() == "SDNPOptInFlag") { + Properties |= 1 << SDNPOptInFlag; + } else if (PropList[i]->getName() == "SDNPMayStore") { + Properties |= 1 << SDNPMayStore; + } else if (PropList[i]->getName() == "SDNPMayLoad") { + Properties |= 1 << SDNPMayLoad; + } else if (PropList[i]->getName() == "SDNPSideEffect") { + Properties |= 1 << SDNPSideEffect; + } else if (PropList[i]->getName() == "SDNPMemOperand") { + Properties |= 1 << SDNPMemOperand; + } else { + cerr << "Unknown SD Node property '" << PropList[i]->getName() + << "' on node '" << R->getName() << "'!\n"; + exit(1); + } + } + + + // Parse the type constraints. + std::vector<Record*> ConstraintList = + TypeProfile->getValueAsListOfDefs("Constraints"); + TypeConstraints.assign(ConstraintList.begin(), ConstraintList.end()); +} + +//===----------------------------------------------------------------------===// +// TreePatternNode implementation +// + +TreePatternNode::~TreePatternNode() { +#if 0 // FIXME: implement refcounted tree nodes! + for (unsigned i = 0, e = getNumChildren(); i != e; ++i) + delete getChild(i); +#endif +} + +/// UpdateNodeType - Set the node type of N to VT if VT contains +/// information. If N already contains a conflicting type, then throw an +/// exception. This returns true if any information was updated. +/// +bool TreePatternNode::UpdateNodeType(const std::vector<unsigned char> &ExtVTs, + TreePattern &TP) { + assert(!ExtVTs.empty() && "Cannot update node type with empty type vector!"); + + if (ExtVTs[0] == EMVT::isUnknown || LHSIsSubsetOfRHS(getExtTypes(), ExtVTs)) + return false; + if (isTypeCompletelyUnknown() || LHSIsSubsetOfRHS(ExtVTs, getExtTypes())) { + setTypes(ExtVTs); + return true; + } + + if (getExtTypeNum(0) == MVT::iPTR || getExtTypeNum(0) == MVT::iPTRAny) { + if (ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::iPTRAny || + ExtVTs[0] == EMVT::isInt) + return false; + if (EMVT::isExtIntegerInVTs(ExtVTs)) { + std::vector<unsigned char> FVTs = FilterEVTs(ExtVTs, isInteger); + if (FVTs.size()) { + setTypes(ExtVTs); + return true; + } + } + } + + if ((ExtVTs[0] == EMVT::isInt || ExtVTs[0] == MVT::iAny) && + EMVT::isExtIntegerInVTs(getExtTypes())) { + assert(hasTypeSet() && "should be handled above!"); + std::vector<unsigned char> FVTs = FilterEVTs(getExtTypes(), isInteger); + if (getExtTypes() == FVTs) + return false; + setTypes(FVTs); + return true; + } + if ((ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::iPTRAny) && + EMVT::isExtIntegerInVTs(getExtTypes())) { + //assert(hasTypeSet() && "should be handled above!"); + std::vector<unsigned char> FVTs = FilterEVTs(getExtTypes(), isInteger); + if (getExtTypes() == FVTs) + return false; + if (FVTs.size()) { + setTypes(FVTs); + return true; + } + } + if ((ExtVTs[0] == EMVT::isFP || ExtVTs[0] == MVT::fAny) && + EMVT::isExtFloatingPointInVTs(getExtTypes())) { + assert(hasTypeSet() && "should be handled above!"); + std::vector<unsigned char> FVTs = + FilterEVTs(getExtTypes(), isFloatingPoint); + if (getExtTypes() == FVTs) + return false; + setTypes(FVTs); + return true; + } + + // If we know this is an int or fp type, and we are told it is a specific one, + // take the advice. + // + // Similarly, we should probably set the type here to the intersection of + // {isInt|isFP} and ExtVTs + if (((getExtTypeNum(0) == EMVT::isInt || getExtTypeNum(0) == MVT::iAny) && + EMVT::isExtIntegerInVTs(ExtVTs)) || + ((getExtTypeNum(0) == EMVT::isFP || getExtTypeNum(0) == MVT::fAny) && + EMVT::isExtFloatingPointInVTs(ExtVTs))) { + setTypes(ExtVTs); + return true; + } + if (getExtTypeNum(0) == EMVT::isInt && + (ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::iPTRAny)) { + setTypes(ExtVTs); + return true; + } + + if (isLeaf()) { + dump(); + cerr << " "; + TP.error("Type inference contradiction found in node!"); + } else { + TP.error("Type inference contradiction found in node " + + getOperator()->getName() + "!"); + } + return true; // unreachable +} + + +void TreePatternNode::print(std::ostream &OS) const { + if (isLeaf()) { + OS << *getLeafValue(); + } else { + OS << "(" << getOperator()->getName(); + } + + // FIXME: At some point we should handle printing all the value types for + // nodes that are multiply typed. + switch (getExtTypeNum(0)) { + case MVT::Other: OS << ":Other"; break; + case EMVT::isInt: OS << ":isInt"; break; + case EMVT::isFP : OS << ":isFP"; break; + case EMVT::isUnknown: ; /*OS << ":?";*/ break; + case MVT::iPTR: OS << ":iPTR"; break; + case MVT::iPTRAny: OS << ":iPTRAny"; break; + default: { + std::string VTName = llvm::getName(getTypeNum(0)); + // Strip off MVT:: prefix if present. + if (VTName.substr(0,5) == "MVT::") + VTName = VTName.substr(5); + OS << ":" << VTName; + break; + } + } + + if (!isLeaf()) { + if (getNumChildren() != 0) { + OS << " "; + getChild(0)->print(OS); + for (unsigned i = 1, e = getNumChildren(); i != e; ++i) { + OS << ", "; + getChild(i)->print(OS); + } + } + OS << ")"; + } + + for (unsigned i = 0, e = PredicateFns.size(); i != e; ++i) + OS << "<<P:" << PredicateFns[i] << ">>"; + if (TransformFn) + OS << "<<X:" << TransformFn->getName() << ">>"; + if (!getName().empty()) + OS << ":$" << getName(); + +} +void TreePatternNode::dump() const { + print(*cerr.stream()); +} + +/// isIsomorphicTo - Return true if this node is recursively +/// isomorphic to the specified node. For this comparison, the node's +/// entire state is considered. The assigned name is ignored, since +/// nodes with differing names are considered isomorphic. However, if +/// the assigned name is present in the dependent variable set, then +/// the assigned name is considered significant and the node is +/// isomorphic if the names match. +bool TreePatternNode::isIsomorphicTo(const TreePatternNode *N, + const MultipleUseVarSet &DepVars) const { + if (N == this) return true; + if (N->isLeaf() != isLeaf() || getExtTypes() != N->getExtTypes() || + getPredicateFns() != N->getPredicateFns() || + getTransformFn() != N->getTransformFn()) + return false; + + if (isLeaf()) { + if (DefInit *DI = dynamic_cast<DefInit*>(getLeafValue())) { + if (DefInit *NDI = dynamic_cast<DefInit*>(N->getLeafValue())) { + return ((DI->getDef() == NDI->getDef()) + && (DepVars.find(getName()) == DepVars.end() + || getName() == N->getName())); + } + } + return getLeafValue() == N->getLeafValue(); + } + + if (N->getOperator() != getOperator() || + N->getNumChildren() != getNumChildren()) return false; + for (unsigned i = 0, e = getNumChildren(); i != e; ++i) + if (!getChild(i)->isIsomorphicTo(N->getChild(i), DepVars)) + return false; + return true; +} + +/// clone - Make a copy of this tree and all of its children. +/// +TreePatternNode *TreePatternNode::clone() const { + TreePatternNode *New; + if (isLeaf()) { + New = new TreePatternNode(getLeafValue()); + } else { + std::vector<TreePatternNode*> CChildren; + CChildren.reserve(Children.size()); + for (unsigned i = 0, e = getNumChildren(); i != e; ++i) + CChildren.push_back(getChild(i)->clone()); + New = new TreePatternNode(getOperator(), CChildren); + } + New->setName(getName()); + New->setTypes(getExtTypes()); + New->setPredicateFns(getPredicateFns()); + New->setTransformFn(getTransformFn()); + return New; +} + +/// SubstituteFormalArguments - Replace the formal arguments in this tree +/// with actual values specified by ArgMap. +void TreePatternNode:: +SubstituteFormalArguments(std::map<std::string, TreePatternNode*> &ArgMap) { + if (isLeaf()) return; + + for (unsigned i = 0, e = getNumChildren(); i != e; ++i) { + TreePatternNode *Child = getChild(i); + if (Child->isLeaf()) { + Init *Val = Child->getLeafValue(); + if (dynamic_cast<DefInit*>(Val) && + static_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!"); + assert((Child->getPredicateFns().empty() || + NewChild->getPredicateFns() == Child->getPredicateFns()) && + "Non-empty child predicate clobbered!"); + setChild(i, NewChild); + } + } else { + getChild(i)->SubstituteFormalArguments(ArgMap); + } + } +} + + +/// InlinePatternFragments - If this pattern refers to any pattern +/// 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. + Record *Op = getOperator(); + + if (!Op->isSubClassOf("PatFrag")) { + // Just recursively inline children nodes. + for (unsigned i = 0, e = getNumChildren(); i != e; ++i) { + TreePatternNode *Child = getChild(i); + TreePatternNode *NewChild = Child->InlinePatternFragments(TP); + + assert((Child->getPredicateFns().empty() || + NewChild->getPredicateFns() == Child->getPredicateFns()) && + "Non-empty child predicate clobbered!"); + + setChild(i, NewChild); + } + return this; + } + + // Otherwise, we found a reference to a fragment. First, look up its + // TreePattern record. + TreePattern *Frag = TP.getDAGPatterns().getPatternFragment(Op); + + // Verify that we are passing the right number of operands. + if (Frag->getNumArgs() != Children.size()) + TP.error("'" + Op->getName() + "' fragment requires " + + utostr(Frag->getNumArgs()) + " operands!"); + + TreePatternNode *FragTree = Frag->getOnlyTree()->clone(); + + std::string Code = Op->getValueAsCode("Predicate"); + if (!Code.empty()) + FragTree->addPredicateFn("Predicate_"+Op->getName()); + + // Resolve formal arguments to their actual value. + if (Frag->getNumArgs()) { + // Compute the map of formal to actual arguments. + std::map<std::string, TreePatternNode*> ArgMap; + for (unsigned i = 0, e = Frag->getNumArgs(); i != e; ++i) + ArgMap[Frag->getArgName(i)] = getChild(i)->InlinePatternFragments(TP); + + FragTree->SubstituteFormalArguments(ArgMap); + } + + FragTree->setName(getName()); + FragTree->UpdateNodeType(getExtTypes(), TP); + + // Transfer in the old predicates. + for (unsigned i = 0, e = getPredicateFns().size(); i != e; ++i) + FragTree->addPredicateFn(getPredicateFns()[i]); + + // Get a new copy of this fragment to stitch into here. + //delete this; // FIXME: implement refcounting! + + // The fragment we inlined could have recursive inlining that is needed. See + // if there are any pattern fragments in it and inline them as needed. + return FragTree->InlinePatternFragments(TP); +} + +/// getImplicitType - Check to see if the specified record has an implicit +/// type which should be applied to it. This infer the type of register +/// references from the register file information, for example. +/// +static std::vector<unsigned char> getImplicitType(Record *R, bool NotRegisters, + TreePattern &TP) { + // Some common return values + std::vector<unsigned char> Unknown(1, EMVT::isUnknown); + std::vector<unsigned char> Other(1, MVT::Other); + + // Check to see if this is a register or a register class... + if (R->isSubClassOf("RegisterClass")) { + if (NotRegisters) + return Unknown; + const CodeGenRegisterClass &RC = + TP.getDAGPatterns().getTargetInfo().getRegisterClass(R); + return ConvertVTs(RC.getValueTypes()); + } else if (R->isSubClassOf("PatFrag")) { + // Pattern fragment types will be resolved when they are inlined. + return Unknown; + } else if (R->isSubClassOf("Register")) { + if (NotRegisters) + return Unknown; + const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo(); + return T.getRegisterVTs(R); + } else if (R->isSubClassOf("ValueType") || R->isSubClassOf("CondCode")) { + // Using a VTSDNode or CondCodeSDNode. + return Other; + } else if (R->isSubClassOf("ComplexPattern")) { + if (NotRegisters) + return Unknown; + std::vector<unsigned char> + ComplexPat(1, TP.getDAGPatterns().getComplexPattern(R).getValueType()); + return ComplexPat; + } else if (R->getName() == "ptr_rc") { + Other[0] = MVT::iPTR; + return Other; + } else if (R->getName() == "node" || R->getName() == "srcvalue" || + R->getName() == "zero_reg") { + // Placeholder. + return Unknown; + } + + TP.error("Unknown node flavor used in pattern: " + R->getName()); + return Other; +} + + +/// getIntrinsicInfo - If this node corresponds to an intrinsic, return the +/// CodeGenIntrinsic information for it, otherwise return a null pointer. +const CodeGenIntrinsic *TreePatternNode:: +getIntrinsicInfo(const CodeGenDAGPatterns &CDP) const { + if (getOperator() != CDP.get_intrinsic_void_sdnode() && + getOperator() != CDP.get_intrinsic_w_chain_sdnode() && + getOperator() != CDP.get_intrinsic_wo_chain_sdnode()) + return 0; + + unsigned IID = + dynamic_cast<IntInit*>(getChild(0)->getLeafValue())->getValue(); + return &CDP.getIntrinsicInfo(IID); +} + +/// isCommutativeIntrinsic - Return true if the node corresponds to a +/// commutative intrinsic. +bool +TreePatternNode::isCommutativeIntrinsic(const CodeGenDAGPatterns &CDP) const { + if (const CodeGenIntrinsic *Int = getIntrinsicInfo(CDP)) + return Int->isCommutative; + return false; +} + + +/// 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. +bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { + CodeGenDAGPatterns &CDP = TP.getDAGPatterns(); + if (isLeaf()) { + if (DefInit *DI = dynamic_cast<DefInit*>(getLeafValue())) { + // If it's a regclass or something else known, include the type. + return UpdateNodeType(getImplicitType(DI->getDef(), NotRegisters, TP),TP); + } else if (IntInit *II = dynamic_cast<IntInit*>(getLeafValue())) { + // Int inits are always integers. :) + bool MadeChange = UpdateNodeType(EMVT::isInt, TP); + + if (hasTypeSet()) { + // At some point, it may make sense for this tree pattern to have + // multiple types. Assert here that it does not, so we revisit this + // code when appropriate. + assert(getExtTypes().size() >= 1 && "TreePattern doesn't have a type!"); + MVT::SimpleValueType VT = getTypeNum(0); + for (unsigned i = 1, e = getExtTypes().size(); i != e; ++i) + assert(getTypeNum(i) == VT && "TreePattern has too many types!"); + + VT = getTypeNum(0); + if (VT != MVT::iPTR && VT != MVT::iPTRAny) { + unsigned Size = MVT(VT).getSizeInBits(); + // Make sure that the value is representable for this type. + if (Size < 32) { + int Val = (II->getValue() << (32-Size)) >> (32-Size); + if (Val != II->getValue()) { + // If sign-extended doesn't fit, does it fit as unsigned? + unsigned ValueMask; + unsigned UnsignedVal; + ValueMask = unsigned(~uint32_t(0UL) >> (32-Size)); + UnsignedVal = unsigned(II->getValue()); + + if ((ValueMask & UnsignedVal) != UnsignedVal) { + TP.error("Integer value '" + itostr(II->getValue())+ + "' is out of range for type '" + + getEnumName(getTypeNum(0)) + "'!"); + } + } + } + } + } + + return MadeChange; + } + return false; + } + + // special handling for set, which isn't really an SDNode. + if (getOperator()->getName() == "set") { + assert (getNumChildren() >= 2 && "Missing RHS of a set?"); + unsigned NC = getNumChildren(); + bool MadeChange = false; + for (unsigned i = 0; i < NC-1; ++i) { + MadeChange = getChild(i)->ApplyTypeConstraints(TP, NotRegisters); + MadeChange |= getChild(NC-1)->ApplyTypeConstraints(TP, NotRegisters); + + // Types of operands must match. + MadeChange |= getChild(i)->UpdateNodeType(getChild(NC-1)->getExtTypes(), + TP); + MadeChange |= getChild(NC-1)->UpdateNodeType(getChild(i)->getExtTypes(), + TP); + MadeChange |= UpdateNodeType(MVT::isVoid, TP); + } + return MadeChange; + } else if (getOperator()->getName() == "implicit" || + getOperator()->getName() == "parallel") { + bool MadeChange = false; + for (unsigned i = 0; i < getNumChildren(); ++i) + MadeChange = getChild(i)->ApplyTypeConstraints(TP, NotRegisters); + MadeChange |= UpdateNodeType(MVT::isVoid, TP); + return MadeChange; + } else if (getOperator()->getName() == "COPY_TO_REGCLASS") { + bool MadeChange = false; + MadeChange |= getChild(0)->ApplyTypeConstraints(TP, NotRegisters); + MadeChange |= getChild(1)->ApplyTypeConstraints(TP, NotRegisters); + MadeChange |= UpdateNodeType(getChild(1)->getTypeNum(0), TP); + return MadeChange; + } else if (const CodeGenIntrinsic *Int = getIntrinsicInfo(CDP)) { + bool MadeChange = false; + + // Apply the result type to the node. + unsigned NumRetVTs = Int->IS.RetVTs.size(); + unsigned NumParamVTs = Int->IS.ParamVTs.size(); + + for (unsigned i = 0, e = NumRetVTs; i != e; ++i) + MadeChange |= UpdateNodeType(Int->IS.RetVTs[i], TP); + + if (getNumChildren() != NumParamVTs + NumRetVTs) + TP.error("Intrinsic '" + Int->Name + "' expects " + + utostr(NumParamVTs + NumRetVTs - 1) + " operands, not " + + utostr(getNumChildren() - 1) + " operands!"); + + // Apply type info to the intrinsic ID. + MadeChange |= getChild(0)->UpdateNodeType(MVT::iPTR, TP); + + for (unsigned i = NumRetVTs, e = getNumChildren(); i != e; ++i) { + MVT::SimpleValueType OpVT = Int->IS.ParamVTs[i - NumRetVTs]; + MadeChange |= getChild(i)->UpdateNodeType(OpVT, TP); + MadeChange |= getChild(i)->ApplyTypeConstraints(TP, NotRegisters); + } + return MadeChange; + } else if (getOperator()->isSubClassOf("SDNode")) { + const SDNodeInfo &NI = CDP.getSDNodeInfo(getOperator()); + + bool MadeChange = NI.ApplyTypeConstraints(this, TP); + for (unsigned i = 0, e = getNumChildren(); i != e; ++i) + MadeChange |= getChild(i)->ApplyTypeConstraints(TP, NotRegisters); + // Branch, etc. do not produce results and top-level forms in instr pattern + // must have void types. + if (NI.getNumResults() == 0) + MadeChange |= UpdateNodeType(MVT::isVoid, TP); + + return MadeChange; + } else if (getOperator()->isSubClassOf("Instruction")) { + const DAGInstruction &Inst = CDP.getInstruction(getOperator()); + bool MadeChange = false; + unsigned NumResults = Inst.getNumResults(); + + assert(NumResults <= 1 && + "Only supports zero or one result instrs!"); + + CodeGenInstruction &InstInfo = + CDP.getTargetInfo().getInstruction(getOperator()->getName()); + // Apply the result type to the node + if (NumResults == 0 || InstInfo.NumDefs == 0) { + MadeChange = UpdateNodeType(MVT::isVoid, TP); + } else { + Record *ResultNode = Inst.getResult(0); + + if (ResultNode->getName() == "ptr_rc") { + std::vector<unsigned char> VT; + VT.push_back(MVT::iPTR); + MadeChange = UpdateNodeType(VT, TP); + } else if (ResultNode->getName() == "unknown") { + std::vector<unsigned char> VT; + VT.push_back(EMVT::isUnknown); + MadeChange = UpdateNodeType(VT, TP); + } else { + assert(ResultNode->isSubClassOf("RegisterClass") && + "Operands should be register classes!"); + + const CodeGenRegisterClass &RC = + CDP.getTargetInfo().getRegisterClass(ResultNode); + MadeChange = UpdateNodeType(ConvertVTs(RC.getValueTypes()), TP); + } + } + + unsigned ChildNo = 0; + for (unsigned i = 0, e = Inst.getNumOperands(); i != e; ++i) { + Record *OperandNode = Inst.getOperand(i); + + // 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")) && + !CDP.getDefaultOperand(OperandNode).DefaultOps.empty()) + continue; + + // Verify that we didn't run out of provided operands. + if (ChildNo >= getNumChildren()) + TP.error("Instruction '" + getOperator()->getName() + + "' expects more operands than were provided."); + + MVT::SimpleValueType VT; + TreePatternNode *Child = getChild(ChildNo++); + if (OperandNode->isSubClassOf("RegisterClass")) { + const CodeGenRegisterClass &RC = + CDP.getTargetInfo().getRegisterClass(OperandNode); + MadeChange |= Child->UpdateNodeType(ConvertVTs(RC.getValueTypes()), TP); + } else if (OperandNode->isSubClassOf("Operand")) { + VT = getValueType(OperandNode->getValueAsDef("Type")); + MadeChange |= Child->UpdateNodeType(VT, TP); + } else if (OperandNode->getName() == "ptr_rc") { + MadeChange |= Child->UpdateNodeType(MVT::iPTR, TP); + } else if (OperandNode->getName() == "unknown") { + MadeChange |= Child->UpdateNodeType(EMVT::isUnknown, TP); + } else { + assert(0 && "Unknown operand type!"); + abort(); + } + MadeChange |= Child->ApplyTypeConstraints(TP, NotRegisters); + } + + if (ChildNo != getNumChildren()) + TP.error("Instruction '" + getOperator()->getName() + + "' was provided too many operands!"); + + return MadeChange; + } else { + assert(getOperator()->isSubClassOf("SDNodeXForm") && "Unknown node type!"); + + // Node transforms always take one operand. + if (getNumChildren() != 1) + TP.error("Node transform '" + getOperator()->getName() + + "' requires one operand!"); + + // If either the output or input of the xform does not have exact + // type info. We assume they must be the same. Otherwise, it is perfectly + // legal to transform from one type to a completely different type. + if (!hasTypeSet() || !getChild(0)->hasTypeSet()) { + bool MadeChange = UpdateNodeType(getChild(0)->getExtTypes(), TP); + MadeChange |= getChild(0)->UpdateNodeType(getExtTypes(), TP); + return MadeChange; + } + return false; + } +} + +/// OnlyOnRHSOfCommutative - Return true if this value is only allowed on the +/// RHS of a commutative operation, not the on LHS. +static bool OnlyOnRHSOfCommutative(TreePatternNode *N) { + if (!N->isLeaf() && N->getOperator()->getName() == "imm") + return true; + if (N->isLeaf() && dynamic_cast<IntInit*>(N->getLeafValue())) + return true; + return false; +} + + +/// canPatternMatch - If it is impossible for this pattern to match on this +/// target, fill in Reason and return false. Otherwise, return true. This is +/// used as a sanity check for .td files (to prevent people from writing stuff +/// that can never possibly work), and to prevent the pattern permuter from +/// generating stuff that is useless. +bool TreePatternNode::canPatternMatch(std::string &Reason, + const CodeGenDAGPatterns &CDP) { + if (isLeaf()) return true; + + for (unsigned i = 0, e = getNumChildren(); i != e; ++i) + if (!getChild(i)->canPatternMatch(Reason, CDP)) + return false; + + // If this is an intrinsic, handle cases that would make it not match. For + // example, if an operand is required to be an immediate. + if (getOperator()->isSubClassOf("Intrinsic")) { + // TODO: + return true; + } + + // If this node is a commutative operator, check that the LHS isn't an + // immediate. + const SDNodeInfo &NodeInfo = CDP.getSDNodeInfo(getOperator()); + bool isCommIntrinsic = isCommutativeIntrinsic(CDP); + if (NodeInfo.hasProperty(SDNPCommutative) || isCommIntrinsic) { + // Scan all of the operands of the node and make sure that only the last one + // is a constant node, unless the RHS also is. + if (!OnlyOnRHSOfCommutative(getChild(getNumChildren()-1))) { + bool Skip = isCommIntrinsic ? 1 : 0; // First operand is intrinsic id. + for (unsigned i = Skip, e = getNumChildren()-1; i != e; ++i) + if (OnlyOnRHSOfCommutative(getChild(i))) { + Reason="Immediate value must be on the RHS of commutative operators!"; + return false; + } + } + } + + return true; +} + +//===----------------------------------------------------------------------===// +// TreePattern implementation +// + +TreePattern::TreePattern(Record *TheRec, ListInit *RawPat, bool isInput, + CodeGenDAGPatterns &cdp) : TheRecord(TheRec), CDP(cdp){ + isInputPattern = isInput; + for (unsigned i = 0, e = RawPat->getSize(); i != e; ++i) + Trees.push_back(ParseTreePattern((DagInit*)RawPat->getElement(i))); +} + +TreePattern::TreePattern(Record *TheRec, DagInit *Pat, bool isInput, + CodeGenDAGPatterns &cdp) : TheRecord(TheRec), CDP(cdp){ + isInputPattern = isInput; + Trees.push_back(ParseTreePattern(Pat)); +} + +TreePattern::TreePattern(Record *TheRec, TreePatternNode *Pat, bool isInput, + CodeGenDAGPatterns &cdp) : TheRecord(TheRec), CDP(cdp){ + isInputPattern = isInput; + Trees.push_back(Pat); +} + + + +void TreePattern::error(const std::string &Msg) const { + dump(); + throw TGError(TheRecord->getLoc(), "In " + TheRecord->getName() + ": " + Msg); +} + +TreePatternNode *TreePattern::ParseTreePattern(DagInit *Dag) { + DefInit *OpDef = dynamic_cast<DefInit*>(Dag->getOperator()); + if (!OpDef) error("Pattern has unexpected operator type!"); + Record *Operator = OpDef->getDef(); + + if (Operator->isSubClassOf("ValueType")) { + // If the operator is a ValueType, then this must be "type cast" of a leaf + // node. + if (Dag->getNumArgs() != 1) + error("Type cast only takes one operand!"); + + Init *Arg = Dag->getArg(0); + TreePatternNode *New; + if (DefInit *DI = dynamic_cast<DefInit*>(Arg)) { + Record *R = DI->getDef(); + if (R->isSubClassOf("SDNode") || R->isSubClassOf("PatFrag")) { + Dag->setArg(0, new DagInit(DI, "", + std::vector<std::pair<Init*, std::string> >())); + return ParseTreePattern(Dag); + } + New = new TreePatternNode(DI); + } else if (DagInit *DI = dynamic_cast<DagInit*>(Arg)) { + New = ParseTreePattern(DI); + } else if (IntInit *II = dynamic_cast<IntInit*>(Arg)) { + New = new TreePatternNode(II); + if (!Dag->getArgName(0).empty()) + error("Constant int argument should not have a name!"); + } else if (BitsInit *BI = dynamic_cast<BitsInit*>(Arg)) { + // Turn this into an IntInit. + Init *II = BI->convertInitializerTo(new IntRecTy()); + if (II == 0 || !dynamic_cast<IntInit*>(II)) + error("Bits value must be constants!"); + + New = new TreePatternNode(dynamic_cast<IntInit*>(II)); + if (!Dag->getArgName(0).empty()) + error("Constant int argument should not have a name!"); + } else { + Arg->dump(); + error("Unknown leaf value for tree pattern!"); + return 0; + } + + // Apply the type cast. + New->UpdateNodeType(getValueType(Operator), *this); + if (New->getNumChildren() == 0) + New->setName(Dag->getArgName(0)); + return New; + } + + // Verify that this is something that makes sense for an operator. + if (!Operator->isSubClassOf("PatFrag") && + !Operator->isSubClassOf("SDNode") && + !Operator->isSubClassOf("Instruction") && + !Operator->isSubClassOf("SDNodeXForm") && + !Operator->isSubClassOf("Intrinsic") && + Operator->getName() != "set" && + Operator->getName() != "implicit" && + Operator->getName() != "parallel") + error("Unrecognized node '" + Operator->getName() + "'!"); + + // Check to see if this is something that is illegal in an input pattern. + if (isInputPattern && (Operator->isSubClassOf("Instruction") || + Operator->isSubClassOf("SDNodeXForm"))) + error("Cannot use '" + Operator->getName() + "' in an input pattern!"); + + std::vector<TreePatternNode*> Children; + + for (unsigned i = 0, e = Dag->getNumArgs(); i != e; ++i) { + Init *Arg = Dag->getArg(i); + if (DagInit *DI = dynamic_cast<DagInit*>(Arg)) { + Children.push_back(ParseTreePattern(DI)); + if (Children.back()->getName().empty()) + Children.back()->setName(Dag->getArgName(i)); + } else if (DefInit *DefI = dynamic_cast<DefInit*>(Arg)) { + Record *R = DefI->getDef(); + // Direct reference to a leaf DagNode or PatFrag? Turn it into a + // TreePatternNode if its own. + if (R->isSubClassOf("SDNode") || R->isSubClassOf("PatFrag")) { + Dag->setArg(i, new DagInit(DefI, "", + std::vector<std::pair<Init*, std::string> >())); + --i; // Revisit this node... + } else { + TreePatternNode *Node = new TreePatternNode(DefI); + Node->setName(Dag->getArgName(i)); + Children.push_back(Node); + + // Input argument? + if (R->getName() == "node") { + if (Dag->getArgName(i).empty()) + error("'node' argument requires a name to match with operand list"); + Args.push_back(Dag->getArgName(i)); + } + } + } else if (IntInit *II = dynamic_cast<IntInit*>(Arg)) { + TreePatternNode *Node = new TreePatternNode(II); + if (!Dag->getArgName(i).empty()) + error("Constant int argument should not have a name!"); + Children.push_back(Node); + } else if (BitsInit *BI = dynamic_cast<BitsInit*>(Arg)) { + // Turn this into an IntInit. + Init *II = BI->convertInitializerTo(new IntRecTy()); + if (II == 0 || !dynamic_cast<IntInit*>(II)) + error("Bits value must be constants!"); + + TreePatternNode *Node = new TreePatternNode(dynamic_cast<IntInit*>(II)); + if (!Dag->getArgName(i).empty()) + error("Constant int argument should not have a name!"); + Children.push_back(Node); + } else { + cerr << '"'; + Arg->dump(); + cerr << "\": "; + error("Unknown leaf value for tree pattern!"); + } + } + + // If the operator is an intrinsic, then this is just syntactic sugar for for + // (intrinsic_* <number>, ..children..). Pick the right intrinsic node, and + // convert the intrinsic name to a number. + if (Operator->isSubClassOf("Intrinsic")) { + const CodeGenIntrinsic &Int = getDAGPatterns().getIntrinsic(Operator); + unsigned IID = getDAGPatterns().getIntrinsicID(Operator)+1; + + // If this intrinsic returns void, it must have side-effects and thus a + // chain. + if (Int.IS.RetVTs[0] == MVT::isVoid) { + Operator = getDAGPatterns().get_intrinsic_void_sdnode(); + } else if (Int.ModRef != CodeGenIntrinsic::NoMem) { + // Has side-effects, requires chain. + Operator = getDAGPatterns().get_intrinsic_w_chain_sdnode(); + } else { + // Otherwise, no chain. + Operator = getDAGPatterns().get_intrinsic_wo_chain_sdnode(); + } + + TreePatternNode *IIDNode = new TreePatternNode(new IntInit(IID)); + Children.insert(Children.begin(), IIDNode); + } + + TreePatternNode *Result = new TreePatternNode(Operator, Children); + Result->setName(Dag->getName()); + return Result; +} + +/// InferAllTypes - Infer/propagate as many types throughout the expression +/// patterns as possible. Return true if all types are inferred, false +/// otherwise. Throw an exception if a type contradiction is found. +bool TreePattern::InferAllTypes() { + bool MadeChange = true; + while (MadeChange) { + MadeChange = false; + for (unsigned i = 0, e = Trees.size(); i != e; ++i) + MadeChange |= Trees[i]->ApplyTypeConstraints(*this, false); + } + + bool HasUnresolvedTypes = false; + for (unsigned i = 0, e = Trees.size(); i != e; ++i) + HasUnresolvedTypes |= Trees[i]->ContainsUnresolvedType(); + return !HasUnresolvedTypes; +} + +void TreePattern::print(std::ostream &OS) const { + OS << getRecord()->getName(); + if (!Args.empty()) { + OS << "(" << Args[0]; + for (unsigned i = 1, e = Args.size(); i != e; ++i) + OS << ", " << Args[i]; + OS << ")"; + } + OS << ": "; + + if (Trees.size() > 1) + OS << "[\n"; + for (unsigned i = 0, e = Trees.size(); i != e; ++i) { + OS << "\t"; + Trees[i]->print(OS); + OS << "\n"; + } + + if (Trees.size() > 1) + OS << "]\n"; +} + +void TreePattern::dump() const { print(*cerr.stream()); } + +//===----------------------------------------------------------------------===// +// CodeGenDAGPatterns implementation +// + +// FIXME: REMOVE OSTREAM ARGUMENT +CodeGenDAGPatterns::CodeGenDAGPatterns(RecordKeeper &R) : Records(R) { + Intrinsics = LoadIntrinsics(Records, false); + TgtIntrinsics = LoadIntrinsics(Records, true); + ParseNodeInfo(); + ParseNodeTransforms(); + ParseComplexPatterns(); + ParsePatternFragments(); + ParseDefaultOperands(); + ParseInstructions(); + ParsePatterns(); + + // Generate variants. For example, commutative patterns can match + // multiple ways. Add them to PatternsToMatch as well. + GenerateVariants(); + + // Infer instruction flags. For example, we can detect loads, + // stores, and side effects in many cases by examining an + // instruction's pattern. + InferInstructionFlags(); +} + +CodeGenDAGPatterns::~CodeGenDAGPatterns() { + for (std::map<Record*, TreePattern*>::iterator I = PatternFragments.begin(), + E = PatternFragments.end(); I != E; ++I) + delete I->second; +} + + +Record *CodeGenDAGPatterns::getSDNodeNamed(const std::string &Name) const { + Record *N = Records.getDef(Name); + if (!N || !N->isSubClassOf("SDNode")) { + cerr << "Error getting SDNode '" << Name << "'!\n"; + exit(1); + } + return N; +} + +// Parse all of the SDNode definitions for the target, populating SDNodes. +void CodeGenDAGPatterns::ParseNodeInfo() { + std::vector<Record*> Nodes = Records.getAllDerivedDefinitions("SDNode"); + while (!Nodes.empty()) { + SDNodes.insert(std::make_pair(Nodes.back(), Nodes.back())); + Nodes.pop_back(); + } + + // Get the builtin intrinsic nodes. + intrinsic_void_sdnode = getSDNodeNamed("intrinsic_void"); + intrinsic_w_chain_sdnode = getSDNodeNamed("intrinsic_w_chain"); + intrinsic_wo_chain_sdnode = getSDNodeNamed("intrinsic_wo_chain"); +} + +/// ParseNodeTransforms - Parse all SDNodeXForm instances into the SDNodeXForms +/// map, and emit them to the file as functions. +void CodeGenDAGPatterns::ParseNodeTransforms() { + std::vector<Record*> Xforms = Records.getAllDerivedDefinitions("SDNodeXForm"); + while (!Xforms.empty()) { + Record *XFormNode = Xforms.back(); + Record *SDNode = XFormNode->getValueAsDef("Opcode"); + std::string Code = XFormNode->getValueAsCode("XFormFunction"); + SDNodeXForms.insert(std::make_pair(XFormNode, NodeXForm(SDNode, Code))); + + Xforms.pop_back(); + } +} + +void CodeGenDAGPatterns::ParseComplexPatterns() { + std::vector<Record*> AMs = Records.getAllDerivedDefinitions("ComplexPattern"); + while (!AMs.empty()) { + ComplexPatterns.insert(std::make_pair(AMs.back(), AMs.back())); + AMs.pop_back(); + } +} + + +/// ParsePatternFragments - Parse all of the PatFrag definitions in the .td +/// file, building up the PatternFragments map. After we've collected them all, +/// inline fragments together as necessary, so that there are no references left +/// inside a pattern fragment to a pattern fragment. +/// +void CodeGenDAGPatterns::ParsePatternFragments() { + std::vector<Record*> Fragments = Records.getAllDerivedDefinitions("PatFrag"); + + // First step, parse all of the fragments. + for (unsigned i = 0, e = Fragments.size(); i != e; ++i) { + DagInit *Tree = Fragments[i]->getValueAsDag("Fragment"); + TreePattern *P = new TreePattern(Fragments[i], Tree, true, *this); + PatternFragments[Fragments[i]] = P; + + // Validate the argument list, converting it to set, to discard duplicates. + std::vector<std::string> &Args = P->getArgList(); + std::set<std::string> OperandsSet(Args.begin(), Args.end()); + + if (OperandsSet.count("")) + P->error("Cannot have unnamed 'node' values in pattern fragment!"); + + // Parse the operands list. + DagInit *OpsList = Fragments[i]->getValueAsDag("Operands"); + DefInit *OpsOp = dynamic_cast<DefInit*>(OpsList->getOperator()); + // Special cases: ops == outs == ins. Different names are used to + // improve readability. + if (!OpsOp || + (OpsOp->getDef()->getName() != "ops" && + OpsOp->getDef()->getName() != "outs" && + OpsOp->getDef()->getName() != "ins")) + P->error("Operands list should start with '(ops ... '!"); + + // 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") + P->error("Operands list should all be 'node' values."); + if (OpsList->getArgName(j).empty()) + P->error("Operands list should have names for each operand!"); + if (!OperandsSet.count(OpsList->getArgName(j))) + P->error("'" + OpsList->getArgName(j) + + "' does not occur in pattern or was multiply specified!"); + OperandsSet.erase(OpsList->getArgName(j)); + Args.push_back(OpsList->getArgName(j)); + } + + if (!OperandsSet.empty()) + P->error("Operands list does not contain an entry for operand '" + + *OperandsSet.begin() + "'!"); + + // If there is a code init for this fragment, keep track of the fact that + // this fragment uses it. + std::string Code = Fragments[i]->getValueAsCode("Predicate"); + if (!Code.empty()) + P->getOnlyTree()->addPredicateFn("Predicate_"+Fragments[i]->getName()); + + // If there is a node transformation corresponding to this, keep track of + // it. + Record *Transform = Fragments[i]->getValueAsDef("OperandTransform"); + if (!getSDNodeTransform(Transform).second.empty()) // not noop xform? + P->getOnlyTree()->setTransformFn(Transform); + } + + // Now that we've parsed all of the tree fragments, do a closure on them so + // that there are not references to PatFrags left inside of them. + for (unsigned i = 0, e = Fragments.size(); i != e; ++i) { + TreePattern *ThePat = PatternFragments[Fragments[i]]; + ThePat->InlinePatternFragments(); + + // 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. + } + + // If debugging, print out the pattern fragment result. + DEBUG(ThePat->dump()); + } +} + +void CodeGenDAGPatterns::ParseDefaultOperands() { + std::vector<Record*> DefaultOps[2]; + DefaultOps[0] = Records.getAllDerivedDefinitions("PredicateOperand"); + DefaultOps[1] = Records.getAllDerivedDefinitions("OptionalDefOperand"); + + // Find some SDNode. + assert(!SDNodes.empty() && "No SDNodes parsed?"); + Init *SomeSDNode = new DefInit(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 = new DagInit(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); + } + + // Insert it into the DefaultOperands map so we can find it later. + DefaultOperands[DefaultOps[iter][i]] = DefaultOpInfo; + } + } +} + +/// HandleUse - Given "Pat" a leaf in the pattern, check to see if it is an +/// instruction input. Return true if this is a real use. +static bool HandleUse(TreePattern *I, TreePatternNode *Pat, + std::map<std::string, TreePatternNode*> &InstInputs, + std::vector<Record*> &InstImpInputs) { + // No name -> not interesting. + if (Pat->getName().empty()) { + if (Pat->isLeaf()) { + DefInit *DI = dynamic_cast<DefInit*>(Pat->getLeafValue()); + if (DI && DI->getDef()->isSubClassOf("RegisterClass")) + I->error("Input " + DI->getDef()->getName() + " must be named!"); + else if (DI && DI->getDef()->isSubClassOf("Register")) + InstImpInputs.push_back(DI->getDef()); + } + return false; + } + + Record *Rec; + if (Pat->isLeaf()) { + DefInit *DI = dynamic_cast<DefInit*>(Pat->getLeafValue()); + if (!DI) I->error("Input $" + Pat->getName() + " must be an identifier!"); + Rec = DI->getDef(); + } else { + Rec = Pat->getOperator(); + } + + // SRCVALUE nodes are ignored. + if (Rec->getName() == "srcvalue") + return false; + + TreePatternNode *&Slot = InstInputs[Pat->getName()]; + if (!Slot) { + Slot = Pat; + } else { + Record *SlotRec; + if (Slot->isLeaf()) { + SlotRec = dynamic_cast<DefInit*>(Slot->getLeafValue())->getDef(); + } else { + assert(Slot->getNumChildren() == 0 && "can't be a use with children!"); + SlotRec = Slot->getOperator(); + } + + // Ensure that the inputs agree if we've already seen this input. + if (Rec != SlotRec) + I->error("All $" + Pat->getName() + " inputs must agree with each other"); + if (Slot->getExtTypes() != Pat->getExtTypes()) + I->error("All $" + Pat->getName() + " inputs must agree with each other"); + } + return true; +} + +/// FindPatternInputsAndOutputs - Scan the specified TreePatternNode (which is +/// part of "I", the instruction), computing the set of inputs and outputs of +/// the pattern. Report errors if we see anything naughty. +void CodeGenDAGPatterns:: +FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, + std::map<std::string, TreePatternNode*> &InstInputs, + std::map<std::string, TreePatternNode*>&InstResults, + std::vector<Record*> &InstImpInputs, + std::vector<Record*> &InstImpResults) { + if (Pat->isLeaf()) { + bool isUse = HandleUse(I, Pat, InstInputs, InstImpInputs); + if (!isUse && Pat->getTransformFn()) + I->error("Cannot specify a transform function for a non-input value!"); + return; + } else if (Pat->getOperator()->getName() == "implicit") { + for (unsigned i = 0, e = Pat->getNumChildren(); i != e; ++i) { + TreePatternNode *Dest = Pat->getChild(i); + if (!Dest->isLeaf()) + I->error("implicitly defined value should be a register!"); + + DefInit *Val = dynamic_cast<DefInit*>(Dest->getLeafValue()); + if (!Val || !Val->getDef()->isSubClassOf("Register")) + I->error("implicitly defined value should be a register!"); + InstImpResults.push_back(Val->getDef()); + } + return; + } else if (Pat->getOperator()->getName() != "set") { + // If this is not a set, verify that the children nodes are not void typed, + // and recurse. + for (unsigned i = 0, e = Pat->getNumChildren(); i != e; ++i) { + if (Pat->getChild(i)->getExtTypeNum(0) == MVT::isVoid) + I->error("Cannot have void nodes inside of patterns!"); + FindPatternInputsAndOutputs(I, Pat->getChild(i), InstInputs, InstResults, + InstImpInputs, InstImpResults); + } + + // If this is a non-leaf node with no children, treat it basically as if + // it were a leaf. This handles nodes like (imm). + bool isUse = HandleUse(I, Pat, InstInputs, InstImpInputs); + + if (!isUse && Pat->getTransformFn()) + I->error("Cannot specify a transform function for a non-input value!"); + return; + } + + // Otherwise, this is a set, validate and collect instruction results. + if (Pat->getNumChildren() == 0) + I->error("set requires operands!"); + + if (Pat->getTransformFn()) + I->error("Cannot specify a transform function on a set node!"); + + // Check the set destinations. + unsigned NumDests = Pat->getNumChildren()-1; + for (unsigned i = 0; i != NumDests; ++i) { + TreePatternNode *Dest = Pat->getChild(i); + if (!Dest->isLeaf()) + I->error("set destination should be a register!"); + + DefInit *Val = dynamic_cast<DefInit*>(Dest->getLeafValue()); + if (!Val) + I->error("set destination should be a register!"); + + if (Val->getDef()->isSubClassOf("RegisterClass") || + Val->getDef()->getName() == "ptr_rc") { + if (Dest->getName().empty()) + I->error("set destination must have a name!"); + if (InstResults.count(Dest->getName())) + I->error("cannot set '" + Dest->getName() +"' multiple times"); + InstResults[Dest->getName()] = Dest; + } else if (Val->getDef()->isSubClassOf("Register")) { + InstImpResults.push_back(Val->getDef()); + } else { + I->error("set destination should be a register!"); + } + } + + // Verify and collect info from the computation. + FindPatternInputsAndOutputs(I, Pat->getChild(NumDests), + InstInputs, InstResults, + InstImpInputs, InstImpResults); +} + +//===----------------------------------------------------------------------===// +// Instruction Analysis +//===----------------------------------------------------------------------===// + +class InstAnalyzer { + const CodeGenDAGPatterns &CDP; + bool &mayStore; + bool &mayLoad; + bool &HasSideEffects; +public: + InstAnalyzer(const CodeGenDAGPatterns &cdp, + bool &maystore, bool &mayload, bool &hse) + : CDP(cdp), mayStore(maystore), mayLoad(mayload), HasSideEffects(hse){ + } + + /// 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. + } + + // FIXME: Assume only the first tree is the pattern. The others are clobber + // nodes. + AnalyzeNode(Pattern->getTree(0)); + return true; + } + +private: + void AnalyzeNode(const TreePatternNode *N) { + if (N->isLeaf()) { + if (DefInit *DI = dynamic_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; + } + } + return; + } + + // Analyze children. + for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) + AnalyzeNode(N->getChild(i)); + + // Ignore set nodes, which are not SDNodes. + if (N->getOperator()->getName() == "set") + return; + + // Get information about the SDNode for the operator. + const SDNodeInfo &OpInfo = CDP.getSDNodeInfo(N->getOperator()); + + // Notice properties of the node. + if (OpInfo.hasProperty(SDNPMayStore)) mayStore = true; + if (OpInfo.hasProperty(SDNPMayLoad)) mayLoad = true; + if (OpInfo.hasProperty(SDNPSideEffect)) HasSideEffects = true; + + if (const CodeGenIntrinsic *IntInfo = N->getIntrinsicInfo(CDP)) { + // If this is an intrinsic, analyze it. + if (IntInfo->ModRef >= CodeGenIntrinsic::ReadArgMem) + mayLoad = true;// These may load memory. + + if (IntInfo->ModRef >= CodeGenIntrinsic::WriteArgMem) + mayStore = true;// Intrinsics that can write to memory are 'mayStore'. + + if (IntInfo->ModRef >= CodeGenIntrinsic::WriteMem) + // WriteMem intrinsics can have other strange effects. + HasSideEffects = true; + } + } + +}; + +static void InferFromPattern(const CodeGenInstruction &Inst, + bool &MayStore, bool &MayLoad, + bool &HasSideEffects, + const CodeGenDAGPatterns &CDP) { + MayStore = MayLoad = HasSideEffects = false; + + bool HadPattern = + InstAnalyzer(CDP, MayStore, MayLoad, HasSideEffects).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) + fprintf(stderr, + "Warning: mayStore flag explicitly set on instruction '%s'" + " but flag already inferred from pattern.\n", + Inst.TheDef->getName().c_str()); + MayStore = true; + } + + 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) + fprintf(stderr, + "Warning: mayLoad flag explicitly set on instruction '%s'" + " but flag already inferred from pattern.\n", + Inst.TheDef->getName().c_str()); + MayLoad = true; + } + + if (Inst.neverHasSideEffects) { + if (HadPattern) + fprintf(stderr, "Warning: neverHasSideEffects set on instruction '%s' " + "which already has a pattern\n", Inst.TheDef->getName().c_str()); + HasSideEffects = false; + } + + if (Inst.hasSideEffects) { + if (HasSideEffects) + fprintf(stderr, "Warning: hasSideEffects set on instruction '%s' " + "which already inferred this.\n", Inst.TheDef->getName().c_str()); + HasSideEffects = true; + } +} + +/// ParseInstructions - Parse all of the instructions, inlining and resolving +/// any fragments involved. This populates the Instructions list with fully +/// resolved instructions. +void CodeGenDAGPatterns::ParseInstructions() { + std::vector<Record*> Instrs = Records.getAllDerivedDefinitions("Instruction"); + + for (unsigned i = 0, e = Instrs.size(); i != e; ++i) { + ListInit *LI = 0; + + if (dynamic_cast<ListInit*>(Instrs[i]->getValueInit("Pattern"))) + LI = Instrs[i]->getValueAsListInit("Pattern"); + + // If there is no pattern, only collect minimal information about the + // instruction for its operand list. We have to assume that there is one + // result, as we have no detailed info. + if (!LI || LI->getSize() == 0) { + std::vector<Record*> Results; + std::vector<Record*> Operands; + + CodeGenInstruction &InstInfo =Target.getInstruction(Instrs[i]->getName()); + + if (InstInfo.OperandList.size() != 0) { + if (InstInfo.NumDefs == 0) { + // These produce no results + for (unsigned j = 0, e = InstInfo.OperandList.size(); j < e; ++j) + Operands.push_back(InstInfo.OperandList[j].Rec); + } else { + // Assume the first operand is the result. + Results.push_back(InstInfo.OperandList[0].Rec); + + // The rest are inputs. + for (unsigned j = 1, e = InstInfo.OperandList.size(); j < e; ++j) + Operands.push_back(InstInfo.OperandList[j].Rec); + } + } + + // Create and insert the instruction. + std::vector<Record*> ImpResults; + std::vector<Record*> ImpOperands; + Instructions.insert(std::make_pair(Instrs[i], + DAGInstruction(0, Results, Operands, ImpResults, + ImpOperands))); + continue; // no pattern. + } + + // Parse the instruction. + TreePattern *I = new TreePattern(Instrs[i], LI, true, *this); + // Inline pattern fragments into it. + I->InlinePatternFragments(); + + // Infer as many types as possible. If we cannot infer all of them, we can + // never do anything with this instruction pattern: report it to the user. + if (!I->InferAllTypes()) + I->error("Could not infer all types in pattern!"); + + // InstInputs - Keep track of all of the inputs of the instruction, along + // with the record they are declared as. + std::map<std::string, TreePatternNode*> InstInputs; + + // InstResults - Keep track of all the virtual registers that are 'set' + // in the instruction, including what reg class they are. + std::map<std::string, TreePatternNode*> InstResults; + + std::vector<Record*> InstImpInputs; + std::vector<Record*> InstImpResults; + + // Verify that the top-level forms in the instruction are of void type, and + // fill in the InstResults map. + for (unsigned j = 0, e = I->getNumTrees(); j != e; ++j) { + TreePatternNode *Pat = I->getTree(j); + if (Pat->getExtTypeNum(0) != MVT::isVoid) + I->error("Top-level forms in instruction pattern should have" + " void types"); + + // Find inputs and outputs, and verify the structure of the uses/defs. + FindPatternInputsAndOutputs(I, Pat, InstInputs, InstResults, + InstImpInputs, InstImpResults); + } + + // Now that we have inputs and outputs of the pattern, inspect the operands + // list for the instruction. This determines the order that operands are + // added to the machine instruction the node corresponds to. + unsigned NumResults = InstResults.size(); + + // Parse the operands list from the (ops) list, validating it. + assert(I->getArgList().empty() && "Args list should still be empty here!"); + CodeGenInstruction &CGI = Target.getInstruction(Instrs[i]->getName()); + + // Check that all of the results occur first in the list. + std::vector<Record*> Results; + TreePatternNode *Res0Node = NULL; + for (unsigned i = 0; i != NumResults; ++i) { + if (i == CGI.OperandList.size()) + I->error("'" + InstResults.begin()->first + + "' set but does not appear in operand list!"); + const std::string &OpName = CGI.OperandList[i].Name; + + // Check that it exists in InstResults. + TreePatternNode *RNode = InstResults[OpName]; + if (RNode == 0) + I->error("Operand $" + OpName + " does not exist in operand list!"); + + if (i == 0) + Res0Node = RNode; + Record *R = dynamic_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!"); + + if (CGI.OperandList[i].Rec != R) + I->error("Operand $" + OpName + " class mismatch!"); + + // Remember the return type. + Results.push_back(CGI.OperandList[i].Rec); + + // Okay, this one checks out. + InstResults.erase(OpName); + } + + // Loop over the inputs next. Make a copy of InstInputs so we can destroy + // the copy while we're checking the inputs. + std::map<std::string, TreePatternNode*> InstInputsCheck(InstInputs); + + std::vector<TreePatternNode*> ResultNodeOperands; + std::vector<Record*> Operands; + for (unsigned i = NumResults, e = CGI.OperandList.size(); i != e; ++i) { + CodeGenInstruction::OperandInfo &Op = CGI.OperandList[i]; + const std::string &OpName = Op.Name; + if (OpName.empty()) + 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")) { + // Does it have a non-empty DefaultOps field? If so, ignore this + // operand. + if (!getDefaultOperand(Op.Rec).DefaultOps.empty()) + continue; + } + I->error("Operand $" + OpName + + " does not appear in the instruction pattern"); + } + TreePatternNode *InVal = InstInputsCheck[OpName]; + InstInputsCheck.erase(OpName); // It occurred, remove from map. + + if (InVal->isLeaf() && + dynamic_cast<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" + " between the operand and pattern"); + } + Operands.push_back(Op.Rec); + + // Construct the result for the dest-pattern operand list. + TreePatternNode *OpNode = InVal->clone(); + + // No predicate is useful on the result. + OpNode->clearPredicateFns(); + + // Promote the xform function to be an explicit node if set. + if (Record *Xform = OpNode->getTransformFn()) { + OpNode->setTransformFn(0); + std::vector<TreePatternNode*> Children; + Children.push_back(OpNode); + OpNode = new TreePatternNode(Xform, Children); + } + + ResultNodeOperands.push_back(OpNode); + } + + if (!InstInputsCheck.empty()) + I->error("Input operand $" + InstInputsCheck.begin()->first + + " occurs in pattern but not in operands list!"); + + TreePatternNode *ResultPattern = + new TreePatternNode(I->getRecord(), ResultNodeOperands); + // Copy fully inferred output node type to instruction result pattern. + if (NumResults > 0) + ResultPattern->setTypes(Res0Node->getExtTypes()); + + // Create and insert the instruction. + // FIXME: InstImpResults and InstImpInputs should not be part of + // DAGInstruction. + DAGInstruction TheInst(I, Results, Operands, InstImpResults, InstImpInputs); + Instructions.insert(std::make_pair(I->getRecord(), TheInst)); + + // Use a temporary tree pattern to infer all types and make sure that the + // constructed result is correct. This depends on the instruction already + // being inserted into the Instructions map. + TreePattern Temp(I->getRecord(), ResultPattern, false, *this); + Temp.InferAllTypes(); + + DAGInstruction &TheInsertedInst = Instructions.find(I->getRecord())->second; + TheInsertedInst.setResultPattern(Temp.getOnlyTree()); + + DEBUG(I->dump()); + } + + // If we can, convert the instructions to be patterns that are matched! + for (std::map<Record*, DAGInstruction>::iterator II = Instructions.begin(), + E = Instructions.end(); II != E; ++II) { + DAGInstruction &TheInst = II->second; + const TreePattern *I = TheInst.getPattern(); + if (I == 0) continue; // No pattern. + + // FIXME: Assume only the first tree is the pattern. The others are clobber + // nodes. + TreePatternNode *Pattern = I->getTree(0); + TreePatternNode *SrcPattern; + if (Pattern->getOperator()->getName() == "set") { + SrcPattern = Pattern->getChild(Pattern->getNumChildren()-1)->clone(); + } else{ + // Not a set (store or something?) + SrcPattern = Pattern; + } + + std::string Reason; + if (!SrcPattern->canPatternMatch(Reason, *this)) + I->error("Instruction can never match: " + Reason); + + Record *Instr = II->first; + TreePatternNode *DstPattern = TheInst.getResultPattern(); + PatternsToMatch. + push_back(PatternToMatch(Instr->getValueAsListInit("Predicates"), + SrcPattern, DstPattern, TheInst.getImpResults(), + Instr->getValueAsInt("AddedComplexity"))); + } +} + + +void CodeGenDAGPatterns::InferInstructionFlags() { + std::map<std::string, CodeGenInstruction> &InstrDescs = + Target.getInstructions(); + for (std::map<std::string, CodeGenInstruction>::iterator + II = InstrDescs.begin(), E = InstrDescs.end(); II != E; ++II) { + CodeGenInstruction &InstInfo = II->second; + // Determine properties of the instruction from its pattern. + bool MayStore, MayLoad, HasSideEffects; + InferFromPattern(InstInfo, MayStore, MayLoad, HasSideEffects, *this); + InstInfo.mayStore = MayStore; + InstInfo.mayLoad = MayLoad; + InstInfo.hasSideEffects = HasSideEffects; + } +} + +void CodeGenDAGPatterns::ParsePatterns() { + std::vector<Record*> Patterns = Records.getAllDerivedDefinitions("Pattern"); + + for (unsigned i = 0, e = Patterns.size(); i != e; ++i) { + DagInit *Tree = Patterns[i]->getValueAsDag("PatternToMatch"); + DefInit *OpDef = dynamic_cast<DefInit*>(Tree->getOperator()); + Record *Operator = OpDef->getDef(); + TreePattern *Pattern; + if (Operator->getName() != "parallel") + Pattern = new TreePattern(Patterns[i], Tree, true, *this); + else { + std::vector<Init*> Values; + for (unsigned j = 0, ee = Tree->getNumArgs(); j != ee; ++j) + Values.push_back(Tree->getArg(j)); + ListInit *LI = new ListInit(Values); + Pattern = new TreePattern(Patterns[i], LI, true, *this); + } + + // Inline pattern fragments into it. + Pattern->InlinePatternFragments(); + + ListInit *LI = Patterns[i]->getValueAsListInit("ResultInstrs"); + if (LI->getSize() == 0) continue; // no pattern. + + // Parse the instruction. + TreePattern *Result = new TreePattern(Patterns[i], LI, false, *this); + + // Inline pattern fragments into it. + Result->InlinePatternFragments(); + + if (Result->getNumTrees() != 1) + Result->error("Cannot handle instructions producing instructions " + "with temporaries yet!"); + + bool IterateInference; + bool InferredAllPatternTypes, InferredAllResultTypes; + do { + // Infer as many types as possible. If we cannot infer all of them, we + // can never do anything with this pattern: report it to the user. + InferredAllPatternTypes = Pattern->InferAllTypes(); + + // Infer as many types as possible. If we cannot infer all of them, we + // can never do anything with this pattern: report it to the user. + InferredAllResultTypes = Result->InferAllTypes(); + + // Apply the type of the result to the source pattern. This helps us + // resolve cases where the input type is known to be a pointer type (which + // is considered resolved), but the result knows it needs to be 32- or + // 64-bits. Infer the other way for good measure. + IterateInference = Pattern->getTree(0)-> + UpdateNodeType(Result->getTree(0)->getExtTypes(), *Result); + IterateInference |= Result->getTree(0)-> + UpdateNodeType(Pattern->getTree(0)->getExtTypes(), *Result); + } while (IterateInference); + + // Verify that we inferred enough types that we can do something with the + // pattern and result. If these fire the user has to add type casts. + if (!InferredAllPatternTypes) + Pattern->error("Could not infer all types in pattern!"); + if (!InferredAllResultTypes) + Result->error("Could not infer all types in pattern result!"); + + // Validate that the input pattern is correct. + std::map<std::string, TreePatternNode*> InstInputs; + std::map<std::string, TreePatternNode*> InstResults; + std::vector<Record*> InstImpInputs; + std::vector<Record*> InstImpResults; + for (unsigned j = 0, ee = Pattern->getNumTrees(); j != ee; ++j) + FindPatternInputsAndOutputs(Pattern, Pattern->getTree(j), + InstInputs, InstResults, + InstImpInputs, InstImpResults); + + // Promote the xform function to be an explicit node if set. + TreePatternNode *DstPattern = Result->getOnlyTree(); + std::vector<TreePatternNode*> ResultNodeOperands; + for (unsigned ii = 0, ee = DstPattern->getNumChildren(); ii != ee; ++ii) { + TreePatternNode *OpNode = DstPattern->getChild(ii); + if (Record *Xform = OpNode->getTransformFn()) { + OpNode->setTransformFn(0); + std::vector<TreePatternNode*> Children; + Children.push_back(OpNode); + OpNode = new TreePatternNode(Xform, Children); + } + ResultNodeOperands.push_back(OpNode); + } + DstPattern = Result->getOnlyTree(); + if (!DstPattern->isLeaf()) + DstPattern = new TreePatternNode(DstPattern->getOperator(), + ResultNodeOperands); + DstPattern->setTypes(Result->getOnlyTree()->getExtTypes()); + TreePattern Temp(Result->getRecord(), DstPattern, false, *this); + Temp.InferAllTypes(); + + std::string Reason; + if (!Pattern->getTree(0)->canPatternMatch(Reason, *this)) + Pattern->error("Pattern can never match: " + Reason); + + PatternsToMatch. + push_back(PatternToMatch(Patterns[i]->getValueAsListInit("Predicates"), + Pattern->getTree(0), + Temp.getOnlyTree(), InstImpResults, + Patterns[i]->getValueAsInt("AddedComplexity"))); + } +} + +/// CombineChildVariants - Given a bunch of permutations of each child of the +/// 'operator' node, put them together in all possible ways. +static void CombineChildVariants(TreePatternNode *Orig, + const std::vector<std::vector<TreePatternNode*> > &ChildVariants, + std::vector<TreePatternNode*> &OutVariants, + CodeGenDAGPatterns &CDP, + const MultipleUseVarSet &DepVars) { + // Make sure that each operand has at least one variant to choose from. + for (unsigned i = 0, e = ChildVariants.size(); i != e; ++i) + if (ChildVariants[i].empty()) + return; + + // The end result is an all-pairs construction of the resultant pattern. + std::vector<unsigned> Idxs; + Idxs.resize(ChildVariants.size()); + bool NotDone; + do { +#ifndef NDEBUG + if (DebugFlag && !Idxs.empty()) { + cerr << Orig->getOperator()->getName() << ": Idxs = [ "; + for (unsigned i = 0; i < Idxs.size(); ++i) { + cerr << Idxs[i] << " "; + } + cerr << "]\n"; + } +#endif + // Create the variant and add it to the output list. + std::vector<TreePatternNode*> NewChildren; + for (unsigned i = 0, e = ChildVariants.size(); i != e; ++i) + NewChildren.push_back(ChildVariants[i][Idxs[i]]); + TreePatternNode *R = new TreePatternNode(Orig->getOperator(), NewChildren); + + // Copy over properties. + R->setName(Orig->getName()); + R->setPredicateFns(Orig->getPredicateFns()); + R->setTransformFn(Orig->getTransformFn()); + R->setTypes(Orig->getExtTypes()); + + // If this pattern cannot match, do not include it as a variant. + std::string ErrString; + if (!R->canPatternMatch(ErrString, CDP)) { + delete R; + } else { + bool AlreadyExists = false; + + // Scan to see if this pattern has already been emitted. We can get + // duplication due to things like commuting: + // (and GPRC:$a, GPRC:$b) -> (and GPRC:$b, GPRC:$a) + // which are the same pattern. Ignore the dups. + for (unsigned i = 0, e = OutVariants.size(); i != e; ++i) + if (R->isIsomorphicTo(OutVariants[i], DepVars)) { + AlreadyExists = true; + break; + } + + if (AlreadyExists) + delete R; + else + OutVariants.push_back(R); + } + + // Increment indices to the next permutation by incrementing the + // indicies from last index backward, e.g., generate the sequence + // [0, 0], [0, 1], [1, 0], [1, 1]. + int IdxsIdx; + for (IdxsIdx = Idxs.size() - 1; IdxsIdx >= 0; --IdxsIdx) { + if (++Idxs[IdxsIdx] == ChildVariants[IdxsIdx].size()) + Idxs[IdxsIdx] = 0; + else + break; + } + NotDone = (IdxsIdx >= 0); + } while (NotDone); +} + +/// CombineChildVariants - A helper function for binary operators. +/// +static void CombineChildVariants(TreePatternNode *Orig, + const std::vector<TreePatternNode*> &LHS, + const std::vector<TreePatternNode*> &RHS, + std::vector<TreePatternNode*> &OutVariants, + CodeGenDAGPatterns &CDP, + const MultipleUseVarSet &DepVars) { + std::vector<std::vector<TreePatternNode*> > ChildVariants; + ChildVariants.push_back(LHS); + ChildVariants.push_back(RHS); + CombineChildVariants(Orig, ChildVariants, OutVariants, CDP, DepVars); +} + + +static void GatherChildrenOfAssociativeOpcode(TreePatternNode *N, + std::vector<TreePatternNode *> &Children) { + assert(N->getNumChildren()==2 &&"Associative but doesn't have 2 children!"); + Record *Operator = N->getOperator(); + + // Only permit raw nodes. + if (!N->getName().empty() || !N->getPredicateFns().empty() || + N->getTransformFn()) { + Children.push_back(N); + return; + } + + if (N->getChild(0)->isLeaf() || N->getChild(0)->getOperator() != Operator) + Children.push_back(N->getChild(0)); + else + GatherChildrenOfAssociativeOpcode(N->getChild(0), Children); + + if (N->getChild(1)->isLeaf() || N->getChild(1)->getOperator() != Operator) + Children.push_back(N->getChild(1)); + else + GatherChildrenOfAssociativeOpcode(N->getChild(1), Children); +} + +/// GenerateVariantsOf - Given a pattern N, generate all permutations we can of +/// the (potentially recursive) pattern by using algebraic laws. +/// +static void GenerateVariantsOf(TreePatternNode *N, + std::vector<TreePatternNode*> &OutVariants, + CodeGenDAGPatterns &CDP, + const MultipleUseVarSet &DepVars) { + // We cannot permute leaves. + if (N->isLeaf()) { + OutVariants.push_back(N); + return; + } + + // Look up interesting info about the node. + const SDNodeInfo &NodeInfo = CDP.getSDNodeInfo(N->getOperator()); + + // If this node is associative, re-associate. + if (NodeInfo.hasProperty(SDNPAssociative)) { + // Re-associate by pulling together all of the linked operators + std::vector<TreePatternNode*> MaximalChildren; + GatherChildrenOfAssociativeOpcode(N, MaximalChildren); + + // Only handle child sizes of 3. Otherwise we'll end up trying too many + // permutations. + if (MaximalChildren.size() == 3) { + // Find the variants of all of our maximal children. + std::vector<TreePatternNode*> AVariants, BVariants, CVariants; + GenerateVariantsOf(MaximalChildren[0], AVariants, CDP, DepVars); + GenerateVariantsOf(MaximalChildren[1], BVariants, CDP, DepVars); + GenerateVariantsOf(MaximalChildren[2], CVariants, CDP, DepVars); + + // There are only two ways we can permute the tree: + // (A op B) op C and A op (B op C) + // Within these forms, we can also permute A/B/C. + + // Generate legal pair permutations of A/B/C. + std::vector<TreePatternNode*> ABVariants; + std::vector<TreePatternNode*> BAVariants; + std::vector<TreePatternNode*> ACVariants; + std::vector<TreePatternNode*> CAVariants; + std::vector<TreePatternNode*> BCVariants; + std::vector<TreePatternNode*> CBVariants; + CombineChildVariants(N, AVariants, BVariants, ABVariants, CDP, DepVars); + CombineChildVariants(N, BVariants, AVariants, BAVariants, CDP, DepVars); + CombineChildVariants(N, AVariants, CVariants, ACVariants, CDP, DepVars); + CombineChildVariants(N, CVariants, AVariants, CAVariants, CDP, DepVars); + CombineChildVariants(N, BVariants, CVariants, BCVariants, CDP, DepVars); + CombineChildVariants(N, CVariants, BVariants, CBVariants, CDP, DepVars); + + // Combine those into the result: (x op x) op x + CombineChildVariants(N, ABVariants, CVariants, OutVariants, CDP, DepVars); + CombineChildVariants(N, BAVariants, CVariants, OutVariants, CDP, DepVars); + CombineChildVariants(N, ACVariants, BVariants, OutVariants, CDP, DepVars); + CombineChildVariants(N, CAVariants, BVariants, OutVariants, CDP, DepVars); + CombineChildVariants(N, BCVariants, AVariants, OutVariants, CDP, DepVars); + CombineChildVariants(N, CBVariants, AVariants, OutVariants, CDP, DepVars); + + // Combine those into the result: x op (x op x) + CombineChildVariants(N, CVariants, ABVariants, OutVariants, CDP, DepVars); + CombineChildVariants(N, CVariants, BAVariants, OutVariants, CDP, DepVars); + CombineChildVariants(N, BVariants, ACVariants, OutVariants, CDP, DepVars); + CombineChildVariants(N, BVariants, CAVariants, OutVariants, CDP, DepVars); + CombineChildVariants(N, AVariants, BCVariants, OutVariants, CDP, DepVars); + CombineChildVariants(N, AVariants, CBVariants, OutVariants, CDP, DepVars); + return; + } + } + + // Compute permutations of all children. + std::vector<std::vector<TreePatternNode*> > ChildVariants; + ChildVariants.resize(N->getNumChildren()); + for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) + GenerateVariantsOf(N->getChild(i), ChildVariants[i], CDP, DepVars); + + // Build all permutations based on how the children were formed. + CombineChildVariants(N, ChildVariants, OutVariants, CDP, DepVars); + + // If this node is commutative, consider the commuted order. + bool isCommIntrinsic = N->isCommutativeIntrinsic(CDP); + if (NodeInfo.hasProperty(SDNPCommutative) || isCommIntrinsic) { + assert((N->getNumChildren()==2 || isCommIntrinsic) && + "Commutative but doesn't have 2 children!"); + // Don't count children which are actually register references. + unsigned NC = 0; + 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())) { + Record *RR = DI->getDef(); + if (RR->isSubClassOf("Register")) + continue; + } + NC++; + } + // Consider the commuted order. + if (isCommIntrinsic) { + // Commutative intrinsic. First operand is the intrinsic id, 2nd and 3rd + // operands are the commutative operands, and there might be more operands + // after those. + assert(NC >= 3 && + "Commutative intrinsic should have at least 3 childrean!"); + std::vector<std::vector<TreePatternNode*> > Variants; + Variants.push_back(ChildVariants[0]); // Intrinsic id. + Variants.push_back(ChildVariants[2]); + Variants.push_back(ChildVariants[1]); + for (unsigned i = 3; i != NC; ++i) + Variants.push_back(ChildVariants[i]); + CombineChildVariants(N, Variants, OutVariants, CDP, DepVars); + } else if (NC == 2) + CombineChildVariants(N, ChildVariants[1], ChildVariants[0], + OutVariants, CDP, DepVars); + } +} + + +// GenerateVariants - Generate variants. For example, commutative patterns can +// match multiple ways. Add them to PatternsToMatch as well. +void CodeGenDAGPatterns::GenerateVariants() { + DOUT << "Generating instruction variants.\n"; + + // Loop over all of the patterns we've collected, checking to see if we can + // generate variants of the instruction, through the exploitation of + // identities. This permits the target to provide aggressive matching without + // the .td file having to contain tons of variants of instructions. + // + // Note that this loop adds new patterns to the PatternsToMatch list, but we + // intentionally do not reconsider these. Any variants of added patterns have + // already been added. + // + for (unsigned i = 0, e = PatternsToMatch.size(); i != e; ++i) { + MultipleUseVarSet DepVars; + std::vector<TreePatternNode*> Variants; + FindDepVars(PatternsToMatch[i].getSrcPattern(), DepVars); + DOUT << "Dependent/multiply used variables: "; + DEBUG(DumpDepVars(DepVars)); + DOUT << "\n"; + GenerateVariantsOf(PatternsToMatch[i].getSrcPattern(), Variants, *this, DepVars); + + assert(!Variants.empty() && "Must create at least original variant!"); + Variants.erase(Variants.begin()); // Remove the original pattern. + + if (Variants.empty()) // No variants for this pattern. + continue; + + DOUT << "FOUND VARIANTS OF: "; + DEBUG(PatternsToMatch[i].getSrcPattern()->dump()); + DOUT << "\n"; + + for (unsigned v = 0, e = Variants.size(); v != e; ++v) { + TreePatternNode *Variant = Variants[v]; + + DOUT << " VAR#" << v << ": "; + DEBUG(Variant->dump()); + DOUT << "\n"; + + // Scan to see if an instruction or explicit pattern already matches this. + bool AlreadyExists = false; + for (unsigned p = 0, e = PatternsToMatch.size(); p != e; ++p) { + // Check to see if this variant already exists. + if (Variant->isIsomorphicTo(PatternsToMatch[p].getSrcPattern(), DepVars)) { + DOUT << " *** ALREADY EXISTS, ignoring variant.\n"; + AlreadyExists = true; + break; + } + } + // If we already have it, ignore the variant. + if (AlreadyExists) continue; + + // Otherwise, add it to the list of patterns we have. + PatternsToMatch. + push_back(PatternToMatch(PatternsToMatch[i].getPredicates(), + Variant, PatternsToMatch[i].getDstPattern(), + PatternsToMatch[i].getDstRegs(), + PatternsToMatch[i].getAddedComplexity())); + } + + DOUT << "\n"; + } +} + diff --git a/utils/TableGen/CodeGenDAGPatterns.h b/utils/TableGen/CodeGenDAGPatterns.h new file mode 100644 index 0000000000000..9ce14dcc7b360 --- /dev/null +++ b/utils/TableGen/CodeGenDAGPatterns.h @@ -0,0 +1,597 @@ +//===- CodeGenDAGPatterns.h - Read DAG patterns from .td file ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the CodeGenDAGPatterns class, which is used to read and +// represent the patterns present in a .td file for instructions. +// +//===----------------------------------------------------------------------===// + +#ifndef CODEGEN_DAGPATTERNS_H +#define CODEGEN_DAGPATTERNS_H + +#include <set> +#include <algorithm> +#include <vector> + +#include "CodeGenTarget.h" +#include "CodeGenIntrinsics.h" + +namespace llvm { + class Record; + struct Init; + class ListInit; + class DagInit; + class SDNodeInfo; + class TreePattern; + class TreePatternNode; + class CodeGenDAGPatterns; + class ComplexPattern; + +/// EMVT::DAGISelGenValueType - These are some extended forms of +/// MVT::SimpleValueType that we use as lattice values during type inference. +namespace EMVT { + enum DAGISelGenValueType { + isFP = MVT::LAST_VALUETYPE, + isInt, + isUnknown + }; + + /// isExtIntegerVT - Return true if the specified extended value type vector + /// contains isInt or an integer value type. + bool isExtIntegerInVTs(const std::vector<unsigned char> &EVTs); + + /// isExtFloatingPointVT - Return true if the specified extended value type + /// vector contains isFP or a FP value type. + bool isExtFloatingPointInVTs(const std::vector<unsigned char> &EVTs); +} + +/// Set type used to track multiply used variables in patterns +typedef std::set<std::string> MultipleUseVarSet; + +/// SDTypeConstraint - This is a discriminated union of constraints, +/// corresponding to the SDTypeConstraint tablegen class in Target.td. +struct SDTypeConstraint { + SDTypeConstraint(Record *R); + + unsigned OperandNo; // The operand # this constraint applies to. + enum { + SDTCisVT, SDTCisPtrTy, SDTCisInt, SDTCisFP, SDTCisSameAs, + SDTCisVTSmallerThanOp, SDTCisOpSmallerThanOp, SDTCisEltOfVec + } ConstraintType; + + union { // The discriminated union. + struct { + unsigned char VT; + } SDTCisVT_Info; + struct { + unsigned OtherOperandNum; + } SDTCisSameAs_Info; + struct { + unsigned OtherOperandNum; + } SDTCisVTSmallerThanOp_Info; + struct { + unsigned BigOperandNum; + } SDTCisOpSmallerThanOp_Info; + struct { + unsigned OtherOperandNum; + } SDTCisEltOfVec_Info; + } x; + + /// 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. + bool ApplyTypeConstraint(TreePatternNode *N, const SDNodeInfo &NodeInfo, + TreePattern &TP) const; + + /// getOperandNum - Return the node corresponding to operand #OpNo in tree + /// N, which has NumResults results. + TreePatternNode *getOperandNum(unsigned OpNo, TreePatternNode *N, + unsigned NumResults) const; +}; + +/// SDNodeInfo - One of these records is created for each SDNode instance in +/// the target .td file. This represents the various dag nodes we will be +/// processing. +class SDNodeInfo { + Record *Def; + std::string EnumName; + std::string SDClassName; + unsigned Properties; + unsigned NumResults; + int NumOperands; + std::vector<SDTypeConstraint> TypeConstraints; +public: + SDNodeInfo(Record *R); // Parse the specified record. + + unsigned getNumResults() const { return NumResults; } + int getNumOperands() const { return NumOperands; } + Record *getRecord() const { return Def; } + const std::string &getEnumName() const { return EnumName; } + const std::string &getSDClassName() const { return SDClassName; } + + const std::vector<SDTypeConstraint> &getTypeConstraints() const { + return TypeConstraints; + } + + /// hasProperty - Return true if this node has the specified property. + /// + bool hasProperty(enum SDNP Prop) const { return Properties & (1 << Prop); } + + /// 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. + bool ApplyTypeConstraints(TreePatternNode *N, TreePattern &TP) const { + bool MadeChange = false; + for (unsigned i = 0, e = TypeConstraints.size(); i != e; ++i) + MadeChange |= TypeConstraints[i].ApplyTypeConstraint(N, *this, TP); + return MadeChange; + } +}; + +/// FIXME: TreePatternNode's can be shared in some cases (due to dag-shaped +/// patterns), and as such should be ref counted. We currently just leak all +/// TreePatternNode objects! +class TreePatternNode { + /// The inferred type for this node, or EMVT::isUnknown if it hasn't + /// been determined yet. This is a std::vector because during inference + /// there may be multiple possible types. + std::vector<unsigned char> Types; + + /// Operator - The Record for the operator if this is an interior node (not + /// a leaf). + Record *Operator; + + /// Val - The init value (e.g. the "GPRC" record, or "7") for a leaf. + /// + Init *Val; + + /// Name - The name given to this node with the :$foo notation. + /// + std::string Name; + + /// PredicateFns - The predicate functions to execute on this node to check + /// for a match. If this list is empty, no predicate is involved. + std::vector<std::string> PredicateFns; + + /// TransformFn - The transformation function to execute on this node before + /// it can be substituted into the resulting instruction on a pattern match. + Record *TransformFn; + + std::vector<TreePatternNode*> Children; +public: + TreePatternNode(Record *Op, const std::vector<TreePatternNode*> &Ch) + : Types(), Operator(Op), Val(0), TransformFn(0), + Children(Ch) { Types.push_back(EMVT::isUnknown); } + TreePatternNode(Init *val) // leaf ctor + : Types(), Operator(0), Val(val), TransformFn(0) { + Types.push_back(EMVT::isUnknown); + } + ~TreePatternNode(); + + const std::string &getName() const { return Name; } + void setName(const std::string &N) { Name = N; } + + bool isLeaf() const { return Val != 0; } + bool hasTypeSet() const { + return (Types[0] < MVT::LAST_VALUETYPE) || (Types[0] == MVT::iPTR) || + (Types[0] == MVT::iPTRAny); + } + bool isTypeCompletelyUnknown() const { + return Types[0] == EMVT::isUnknown; + } + bool isTypeDynamicallyResolved() const { + return (Types[0] == MVT::iPTR) || (Types[0] == MVT::iPTRAny); + } + MVT::SimpleValueType getTypeNum(unsigned Num) const { + assert(hasTypeSet() && "Doesn't have a type yet!"); + assert(Types.size() > Num && "Type num out of range!"); + return (MVT::SimpleValueType)Types[Num]; + } + unsigned char getExtTypeNum(unsigned Num) const { + assert(Types.size() > Num && "Extended type num out of range!"); + return Types[Num]; + } + const std::vector<unsigned char> &getExtTypes() const { return Types; } + void setTypes(const std::vector<unsigned char> &T) { Types = T; } + void removeTypes() { Types = std::vector<unsigned char>(1, EMVT::isUnknown); } + + Init *getLeafValue() const { assert(isLeaf()); return Val; } + Record *getOperator() const { assert(!isLeaf()); return Operator; } + + unsigned getNumChildren() const { return Children.size(); } + TreePatternNode *getChild(unsigned N) const { return Children[N]; } + void setChild(unsigned i, TreePatternNode *N) { + Children[i] = N; + } + + const std::vector<std::string> &getPredicateFns() const { return PredicateFns; } + void clearPredicateFns() { PredicateFns.clear(); } + void setPredicateFns(const std::vector<std::string> &Fns) { + assert(PredicateFns.empty() && "Overwriting non-empty predicate list!"); + PredicateFns = Fns; + } + void addPredicateFn(const std::string &Fn) { + assert(!Fn.empty() && "Empty predicate string!"); + if (std::find(PredicateFns.begin(), PredicateFns.end(), Fn) == + PredicateFns.end()) + PredicateFns.push_back(Fn); + } + + Record *getTransformFn() const { return TransformFn; } + void setTransformFn(Record *Fn) { TransformFn = Fn; } + + /// getIntrinsicInfo - If this node corresponds to an intrinsic, return the + /// CodeGenIntrinsic information for it, otherwise return a null pointer. + const CodeGenIntrinsic *getIntrinsicInfo(const CodeGenDAGPatterns &CDP) const; + + /// isCommutativeIntrinsic - Return true if the node is an intrinsic which is + /// marked isCommutative. + bool isCommutativeIntrinsic(const CodeGenDAGPatterns &CDP) const; + + void print(std::ostream &OS) const; + void dump() const; + +public: // Higher level manipulation routines. + + /// clone - Return a new copy of this tree. + /// + TreePatternNode *clone() const; + + /// isIsomorphicTo - Return true if this node is recursively isomorphic to + /// the specified node. For this comparison, all of the state of the node + /// is considered, except for the assigned name. Nodes with differing names + /// that are otherwise identical are considered isomorphic. + bool isIsomorphicTo(const TreePatternNode *N, + const MultipleUseVarSet &DepVars) const; + + /// SubstituteFormalArguments - Replace the formal arguments in this tree + /// with actual values specified by ArgMap. + void SubstituteFormalArguments(std::map<std::string, + TreePatternNode*> &ArgMap); + + /// InlinePatternFragments - If this pattern refers to any pattern + /// fragments, inline them into place, giving us a pattern without any + /// PatFrag references. + TreePatternNode *InlinePatternFragments(TreePattern &TP); + + /// 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. + 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. + /// + bool UpdateNodeType(const std::vector<unsigned char> &ExtVTs, + TreePattern &TP); + bool UpdateNodeType(unsigned char ExtVT, TreePattern &TP) { + std::vector<unsigned char> ExtVTs(1, ExtVT); + return UpdateNodeType(ExtVTs, TP); + } + + /// ContainsUnresolvedType - Return true if this tree contains any + /// unresolved types. + bool ContainsUnresolvedType() const { + if (!hasTypeSet() && !isTypeDynamicallyResolved()) return true; + for (unsigned i = 0, e = getNumChildren(); i != e; ++i) + if (getChild(i)->ContainsUnresolvedType()) return true; + return false; + } + + /// canPatternMatch - If it is impossible for this pattern to match on this + /// target, fill in Reason and return false. Otherwise, return true. + bool canPatternMatch(std::string &Reason, const CodeGenDAGPatterns &CDP); +}; + + +/// TreePattern - Represent a pattern, used for instructions, pattern +/// fragments, etc. +/// +class TreePattern { + /// Trees - The list of pattern trees which corresponds to this pattern. + /// Note that PatFrag's only have a single tree. + /// + std::vector<TreePatternNode*> Trees; + + /// TheRecord - The actual TableGen record corresponding to this pattern. + /// + Record *TheRecord; + + /// Args - This is a list of all of the arguments to this pattern (for + /// PatFrag patterns), which are the 'node' markers in this pattern. + std::vector<std::string> Args; + + /// CDP - the top-level object coordinating this madness. + /// + CodeGenDAGPatterns &CDP; + + /// isInputPattern - True if this is an input pattern, something to match. + /// False if this is an output pattern, something to emit. + bool isInputPattern; +public: + + /// TreePattern constructor - Parse the specified DagInits into the + /// current record. + TreePattern(Record *TheRec, ListInit *RawPat, bool isInput, + CodeGenDAGPatterns &ise); + TreePattern(Record *TheRec, DagInit *Pat, bool isInput, + CodeGenDAGPatterns &ise); + TreePattern(Record *TheRec, TreePatternNode *Pat, bool isInput, + CodeGenDAGPatterns &ise); + + /// getTrees - Return the tree patterns which corresponds to this pattern. + /// + const std::vector<TreePatternNode*> &getTrees() const { return Trees; } + unsigned getNumTrees() const { return Trees.size(); } + TreePatternNode *getTree(unsigned i) const { return Trees[i]; } + TreePatternNode *getOnlyTree() const { + assert(Trees.size() == 1 && "Doesn't have exactly one pattern!"); + return Trees[0]; + } + + /// getRecord - Return the actual TableGen record corresponding to this + /// pattern. + /// + Record *getRecord() const { return TheRecord; } + + unsigned getNumArgs() const { return Args.size(); } + const std::string &getArgName(unsigned i) const { + assert(i < Args.size() && "Argument reference out of range!"); + return Args[i]; + } + std::vector<std::string> &getArgList() { return Args; } + + CodeGenDAGPatterns &getDAGPatterns() const { return CDP; } + + /// InlinePatternFragments - If this pattern refers to any pattern + /// fragments, inline them into place, giving us a pattern without any + /// PatFrag references. + void InlinePatternFragments() { + for (unsigned i = 0, e = Trees.size(); i != e; ++i) + Trees[i] = Trees[i]->InlinePatternFragments(*this); + } + + /// InferAllTypes - Infer/propagate as many types throughout the expression + /// patterns as possible. Return true if all types are inferred, false + /// otherwise. Throw an exception if a type contradiction is found. + bool InferAllTypes(); + + /// error - Throw an exception, prefixing it with information about this + /// pattern. + void error(const std::string &Msg) const; + + void print(std::ostream &OS) const; + void dump() const; + +private: + TreePatternNode *ParseTreePattern(DagInit *DI); +}; + +/// DAGDefaultOperand - One of these is created for each PredicateOperand +/// or OptionalDefOperand that has a set ExecuteAlways / DefaultOps field. +struct DAGDefaultOperand { + std::vector<TreePatternNode*> DefaultOps; +}; + +class DAGInstruction { + TreePattern *Pattern; + std::vector<Record*> Results; + std::vector<Record*> Operands; + std::vector<Record*> ImpResults; + std::vector<Record*> ImpOperands; + TreePatternNode *ResultPattern; +public: + DAGInstruction(TreePattern *TP, + const std::vector<Record*> &results, + const std::vector<Record*> &operands, + const std::vector<Record*> &impresults, + const std::vector<Record*> &impoperands) + : Pattern(TP), Results(results), Operands(operands), + ImpResults(impresults), ImpOperands(impoperands), + ResultPattern(0) {} + + const TreePattern *getPattern() const { return Pattern; } + unsigned getNumResults() const { return Results.size(); } + unsigned getNumOperands() const { return Operands.size(); } + unsigned getNumImpResults() const { return ImpResults.size(); } + unsigned getNumImpOperands() const { return ImpOperands.size(); } + const std::vector<Record*>& getImpResults() const { return ImpResults; } + + void setResultPattern(TreePatternNode *R) { ResultPattern = R; } + + Record *getResult(unsigned RN) const { + assert(RN < Results.size()); + return Results[RN]; + } + + Record *getOperand(unsigned ON) const { + assert(ON < Operands.size()); + return Operands[ON]; + } + + Record *getImpResult(unsigned RN) const { + assert(RN < ImpResults.size()); + return ImpResults[RN]; + } + + Record *getImpOperand(unsigned ON) const { + assert(ON < ImpOperands.size()); + return ImpOperands[ON]; + } + + TreePatternNode *getResultPattern() const { return ResultPattern; } +}; + +/// PatternToMatch - Used by CodeGenDAGPatterns to keep tab of patterns +/// processed to produce isel. +struct PatternToMatch { + PatternToMatch(ListInit *preds, + TreePatternNode *src, TreePatternNode *dst, + const std::vector<Record*> &dstregs, + unsigned complexity): + Predicates(preds), SrcPattern(src), DstPattern(dst), Dstregs(dstregs), + AddedComplexity(complexity) {}; + + ListInit *Predicates; // Top level predicate conditions to match. + TreePatternNode *SrcPattern; // Source pattern to match. + TreePatternNode *DstPattern; // Resulting pattern. + std::vector<Record*> Dstregs; // Physical register defs being matched. + unsigned AddedComplexity; // Add to matching pattern complexity. + + ListInit *getPredicates() const { return Predicates; } + TreePatternNode *getSrcPattern() const { return SrcPattern; } + TreePatternNode *getDstPattern() const { return DstPattern; } + const std::vector<Record*> &getDstRegs() const { return Dstregs; } + unsigned getAddedComplexity() const { return AddedComplexity; } + + std::string getPredicateCheck() const; +}; + + +class CodeGenDAGPatterns { + RecordKeeper &Records; + CodeGenTarget Target; + std::vector<CodeGenIntrinsic> Intrinsics; + std::vector<CodeGenIntrinsic> TgtIntrinsics; + + std::map<Record*, SDNodeInfo> SDNodes; + std::map<Record*, std::pair<Record*, std::string> > SDNodeXForms; + std::map<Record*, ComplexPattern> ComplexPatterns; + std::map<Record*, TreePattern*> PatternFragments; + std::map<Record*, DAGDefaultOperand> DefaultOperands; + std::map<Record*, DAGInstruction> Instructions; + + // Specific SDNode definitions: + Record *intrinsic_void_sdnode; + Record *intrinsic_w_chain_sdnode, *intrinsic_wo_chain_sdnode; + + /// PatternsToMatch - All of the things we are matching on the DAG. The first + /// value is the pattern to match, the second pattern is the result to + /// emit. + std::vector<PatternToMatch> PatternsToMatch; +public: + CodeGenDAGPatterns(RecordKeeper &R); + ~CodeGenDAGPatterns(); + + CodeGenTarget &getTargetInfo() { return Target; } + const CodeGenTarget &getTargetInfo() const { return Target; } + + Record *getSDNodeNamed(const std::string &Name) const; + + const SDNodeInfo &getSDNodeInfo(Record *R) const { + assert(SDNodes.count(R) && "Unknown node!"); + return SDNodes.find(R)->second; + } + + // Node transformation lookups. + typedef std::pair<Record*, std::string> NodeXForm; + const NodeXForm &getSDNodeTransform(Record *R) const { + assert(SDNodeXForms.count(R) && "Invalid transform!"); + return SDNodeXForms.find(R)->second; + } + + typedef std::map<Record*, NodeXForm>::const_iterator nx_iterator; + nx_iterator nx_begin() const { return SDNodeXForms.begin(); } + nx_iterator nx_end() const { return SDNodeXForms.end(); } + + + const ComplexPattern &getComplexPattern(Record *R) const { + assert(ComplexPatterns.count(R) && "Unknown addressing mode!"); + return ComplexPatterns.find(R)->second; + } + + const CodeGenIntrinsic &getIntrinsic(Record *R) const { + for (unsigned i = 0, e = Intrinsics.size(); i != e; ++i) + if (Intrinsics[i].TheDef == R) return Intrinsics[i]; + for (unsigned i = 0, e = TgtIntrinsics.size(); i != e; ++i) + if (TgtIntrinsics[i].TheDef == R) return TgtIntrinsics[i]; + assert(0 && "Unknown intrinsic!"); + abort(); + } + + const CodeGenIntrinsic &getIntrinsicInfo(unsigned IID) const { + if (IID-1 < Intrinsics.size()) + return Intrinsics[IID-1]; + if (IID-Intrinsics.size()-1 < TgtIntrinsics.size()) + return TgtIntrinsics[IID-Intrinsics.size()-1]; + assert(0 && "Bad intrinsic ID!"); + abort(); + } + + unsigned getIntrinsicID(Record *R) const { + for (unsigned i = 0, e = Intrinsics.size(); i != e; ++i) + if (Intrinsics[i].TheDef == R) return i; + for (unsigned i = 0, e = TgtIntrinsics.size(); i != e; ++i) + if (TgtIntrinsics[i].TheDef == R) return i + Intrinsics.size(); + assert(0 && "Unknown intrinsic!"); + abort(); + } + + const DAGDefaultOperand &getDefaultOperand(Record *R) { + assert(DefaultOperands.count(R) &&"Isn't an analyzed default operand!"); + return DefaultOperands.find(R)->second; + } + + // Pattern Fragment information. + TreePattern *getPatternFragment(Record *R) const { + assert(PatternFragments.count(R) && "Invalid pattern fragment request!"); + return PatternFragments.find(R)->second; + } + typedef std::map<Record*, TreePattern*>::const_iterator pf_iterator; + pf_iterator pf_begin() const { return PatternFragments.begin(); } + pf_iterator pf_end() const { return PatternFragments.end(); } + + // Patterns to match information. + typedef std::vector<PatternToMatch>::const_iterator ptm_iterator; + ptm_iterator ptm_begin() const { return PatternsToMatch.begin(); } + ptm_iterator ptm_end() const { return PatternsToMatch.end(); } + + + + const DAGInstruction &getInstruction(Record *R) const { + assert(Instructions.count(R) && "Unknown instruction!"); + return Instructions.find(R)->second; + } + + Record *get_intrinsic_void_sdnode() const { + return intrinsic_void_sdnode; + } + Record *get_intrinsic_w_chain_sdnode() const { + return intrinsic_w_chain_sdnode; + } + Record *get_intrinsic_wo_chain_sdnode() const { + return intrinsic_wo_chain_sdnode; + } + +private: + void ParseNodeInfo(); + void ParseNodeTransforms(); + void ParseComplexPatterns(); + void ParsePatternFragments(); + void ParseDefaultOperands(); + void ParseInstructions(); + void ParsePatterns(); + void InferInstructionFlags(); + void GenerateVariants(); + + void FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, + std::map<std::string, + TreePatternNode*> &InstInputs, + std::map<std::string, + TreePatternNode*> &InstResults, + std::vector<Record*> &InstImpInputs, + std::vector<Record*> &InstImpResults); +}; +} // end namespace llvm + +#endif diff --git a/utils/TableGen/CodeGenInstruction.cpp b/utils/TableGen/CodeGenInstruction.cpp new file mode 100644 index 0000000000000..4650b88fd5174 --- /dev/null +++ b/utils/TableGen/CodeGenInstruction.cpp @@ -0,0 +1,273 @@ +//===- CodeGenInstruction.cpp - CodeGen Instruction Class Wrapper ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the CodeGenInstruction class. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenInstruction.h" +#include "Record.h" +#include "llvm/ADT/StringExtras.h" +#include <set> +using namespace llvm; + +static void ParseConstraint(const std::string &CStr, CodeGenInstruction *I) { + // FIXME: Only supports TIED_TO for now. + std::string::size_type pos = CStr.find_first_of('='); + assert(pos != std::string::npos && "Unrecognized constraint"); + std::string::size_type start = CStr.find_first_not_of(" \t"); + std::string Name = CStr.substr(start, pos); + + // TIED_TO: $src1 = $dst + std::string::size_type wpos = Name.find_first_of(" \t"); + if (wpos == std::string::npos) + throw "Illegal format for tied-to constraint: '" + CStr + "'"; + std::string DestOpName = Name.substr(0, wpos); + std::pair<unsigned,unsigned> DestOp = I->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 = + I->ParseOperandName(Name.substr(wpos), false); + if (SrcOp > DestOp) + throw "Illegal tied-to operand constraint '" + CStr + "'"; + + + unsigned FlatOpNo = I->getFlattenedOperandNumber(SrcOp); + // Build the string for the operand. + std::string OpConstraint = + "((" + utostr(FlatOpNo) + " << 16) | (1 << TOI::TIED_TO))"; + + + if (!I->OperandList[DestOp.first].Constraints[DestOp.second].empty()) + throw "Operand '" + DestOpName + "' cannot have multiple constraints!"; + I->OperandList[DestOp.first].Constraints[DestOp.second] = OpConstraint; +} + +static void ParseConstraints(const std::string &CStr, CodeGenInstruction *I) { + // Make sure the constraints list for each operand is large enough to hold + // constraint info, even if none is present. + for (unsigned i = 0, e = I->OperandList.size(); i != e; ++i) + I->OperandList[i].Constraints.resize(I->OperandList[i].MINumOperands); + + if (CStr.empty()) return; + + const std::string delims(","); + std::string::size_type bidx, eidx; + + bidx = CStr.find_first_not_of(delims); + while (bidx != std::string::npos) { + eidx = CStr.find_first_of(delims, bidx); + if (eidx == std::string::npos) + eidx = CStr.length(); + + ParseConstraint(CStr.substr(bidx, eidx), I); + bidx = CStr.find_first_not_of(delims, eidx); + } +} + +CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr) + : TheDef(R), AsmString(AsmStr) { + Namespace = R->getValueAsString("Namespace"); + + isReturn = R->getValueAsBit("isReturn"); + isBranch = R->getValueAsBit("isBranch"); + isIndirectBranch = R->getValueAsBit("isIndirectBranch"); + isBarrier = R->getValueAsBit("isBarrier"); + isCall = R->getValueAsBit("isCall"); + canFoldAsLoad = R->getValueAsBit("canFoldAsLoad"); + mayLoad = R->getValueAsBit("mayLoad"); + mayStore = R->getValueAsBit("mayStore"); + bool isTwoAddress = R->getValueAsBit("isTwoAddress"); + isPredicable = R->getValueAsBit("isPredicable"); + isConvertibleToThreeAddress = R->getValueAsBit("isConvertibleToThreeAddress"); + isCommutable = R->getValueAsBit("isCommutable"); + isTerminator = R->getValueAsBit("isTerminator"); + isReMaterializable = R->getValueAsBit("isReMaterializable"); + hasDelaySlot = R->getValueAsBit("hasDelaySlot"); + usesCustomDAGSchedInserter = R->getValueAsBit("usesCustomDAGSchedInserter"); + hasCtrlDep = R->getValueAsBit("hasCtrlDep"); + isNotDuplicable = R->getValueAsBit("isNotDuplicable"); + hasSideEffects = R->getValueAsBit("hasSideEffects"); + mayHaveSideEffects = R->getValueAsBit("mayHaveSideEffects"); + neverHasSideEffects = R->getValueAsBit("neverHasSideEffects"); + isAsCheapAsAMove = R->getValueAsBit("isAsCheapAsAMove"); + hasOptionalDef = false; + isVariadic = false; + + if (mayHaveSideEffects + neverHasSideEffects + hasSideEffects > 1) + throw R->getName() + ": multiple conflicting side-effect flags set!"; + + DagInit *DI; + try { + DI = R->getValueAsDag("OutOperandList"); + } catch (...) { + // Error getting operand list, just ignore it (sparcv9). + AsmString.clear(); + OperandList.clear(); + return; + } + NumDefs = DI->getNumArgs(); + + DagInit *IDI; + try { + IDI = R->getValueAsDag("InOperandList"); + } catch (...) { + // Error getting operand list, just ignore it (sparcv9). + AsmString.clear(); + OperandList.clear(); + return; + } + DI = (DagInit*)(new BinOpInit(BinOpInit::CONCAT, DI, IDI, new DagRecTy))->Fold(R, 0); + + unsigned MIOperandNo = 0; + std::set<std::string> OperandNames; + for (unsigned i = 0, e = DI->getNumArgs(); i != e; ++i) { + DefInit *Arg = dynamic_cast<DefInit*>(DI->getArg(i)); + if (!Arg) + throw "Illegal operand for the '" + R->getName() + "' instruction!"; + + Record *Rec = Arg->getDef(); + std::string PrintMethod = "printOperand"; + unsigned NumOps = 1; + DagInit *MIOpInfo = 0; + if (Rec->isSubClassOf("Operand")) { + PrintMethod = Rec->getValueAsString("PrintMethod"); + 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 we have MIOpInfo, then we have #operands equal to number of entries + // in MIOperandInfo. + if (unsigned NumArgs = MIOpInfo->getNumArgs()) + NumOps = NumArgs; + + if (Rec->isSubClassOf("PredicateOperand")) + isPredicable = true; + else if (Rec->isSubClassOf("OptionalDefOperand")) + hasOptionalDef = true; + } else if (Rec->getName() == "variable_ops") { + isVariadic = true; + continue; + } else if (!Rec->isSubClassOf("RegisterClass") && + Rec->getName() != "ptr_rc" && Rec->getName() != "unknown") + throw "Unknown operand class '" + Rec->getName() + + "' in '" + R->getName() + "' instruction!"; + + // Check that the operand has a name and that it's unique. + if (DI->getArgName(i).empty()) + throw "In instruction '" + R->getName() + "', operand #" + utostr(i) + + " has no name!"; + if (!OperandNames.insert(DI->getArgName(i)).second) + throw "In instruction '" + R->getName() + "', operand #" + utostr(i) + + " has the same name as a previous operand!"; + + OperandList.push_back(OperandInfo(Rec, DI->getArgName(i), PrintMethod, + MIOperandNo, NumOps, MIOpInfo)); + MIOperandNo += NumOps; + } + + // Parse Constraints. + ParseConstraints(R->getValueAsString("Constraints"), this); + + // For backward compatibility: isTwoAddress means operand 1 is tied to + // operand 0. + if (isTwoAddress) { + if (!OperandList[1].Constraints[0].empty()) + throw R->getName() + ": cannot use isTwoAddress property: instruction " + "already has constraint set!"; + OperandList[1].Constraints[0] = "((0 << 16) | (1 << TOI::TIED_TO))"; + } + + // Any operands with unset constraints get 0 as their constraint. + for (unsigned op = 0, e = OperandList.size(); op != e; ++op) + for (unsigned j = 0, e = OperandList[op].MINumOperands; j != e; ++j) + if (OperandList[op].Constraints[j].empty()) + OperandList[op].Constraints[j] = "0"; + + // Parse the DisableEncoding field. + std::string DisableEncoding = R->getValueAsString("DisableEncoding"); + while (1) { + std::string OpName = getToken(DisableEncoding, " ,\t"); + if (OpName.empty()) break; + + // Figure out which operand this is. + std::pair<unsigned,unsigned> Op = ParseOperandName(OpName, false); + + // Mark the operand as not-to-be encoded. + if (Op.second >= OperandList[Op.first].DoNotEncode.size()) + OperandList[Op.first].DoNotEncode.resize(Op.second+1); + OperandList[Op.first].DoNotEncode[Op.second] = true; + } +} + +/// 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. +/// +unsigned CodeGenInstruction::getOperandNamed(const std::string &Name) const { + assert(!Name.empty() && "Cannot search for operand with no name!"); + for (unsigned i = 0, e = OperandList.size(); i != e; ++i) + if (OperandList[i].Name == Name) return i; + throw "Instruction '" + TheDef->getName() + + "' does not have an operand named '$" + Name + "'!"; +} + +std::pair<unsigned,unsigned> +CodeGenInstruction::ParseOperandName(const std::string &Op, + bool AllowWholeOp) { + if (Op.empty() || Op[0] != '$') + throw TheDef->getName() + ": Illegal operand name: '" + Op + "'"; + + std::string OpName = Op.substr(1); + std::string SubOpName; + + // Check to see if this is $foo.bar. + std::string::size_type DotIdx = OpName.find_first_of("."); + if (DotIdx != std::string::npos) { + SubOpName = OpName.substr(DotIdx+1); + if (SubOpName.empty()) + throw TheDef->getName() + ": illegal empty suboperand name in '" +Op +"'"; + OpName = OpName.substr(0, DotIdx); + } + + unsigned OpIdx = getOperandNamed(OpName); + + if (SubOpName.empty()) { // If no suboperand name was specified: + // 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 + "'"; + + // Otherwise, return the operand. + return std::make_pair(OpIdx, 0U); + } + + // Find the suboperand number involved. + DagInit *MIOpInfo = OperandList[OpIdx].MIOperandInfo; + if (MIOpInfo == 0) + throw TheDef->getName() + ": unknown suboperand name in '" + Op + "'"; + + // Find the operand with the right name. + for (unsigned i = 0, e = MIOpInfo->getNumArgs(); i != e; ++i) + if (MIOpInfo->getArgName(i) == SubOpName) + return std::make_pair(OpIdx, i); + + // Otherwise, didn't find it! + throw TheDef->getName() + ": unknown suboperand name in '" + Op + "'"; +} diff --git a/utils/TableGen/CodeGenInstruction.h b/utils/TableGen/CodeGenInstruction.h new file mode 100644 index 0000000000000..f4afd5e45ba3e --- /dev/null +++ b/utils/TableGen/CodeGenInstruction.h @@ -0,0 +1,153 @@ +//===- CodeGenInstruction.h - Instruction Class Wrapper ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a wrapper class for the 'Instruction' TableGen class. +// +//===----------------------------------------------------------------------===// + +#ifndef CODEGEN_INSTRUCTION_H +#define CODEGEN_INSTRUCTION_H + +#include "llvm/CodeGen/ValueTypes.h" +#include <string> +#include <vector> +#include <utility> + +namespace llvm { + class Record; + class DagInit; + + class CodeGenInstruction { + public: + Record *TheDef; // The actual record defining this instruction. + std::string Namespace; // The namespace the instruction is in. + + /// AsmString - The format string used to emit a .s file for the + /// instruction. + std::string AsmString; + + /// OperandInfo - The information we keep track of for each operand in the + /// operand list for a tablegen instruction. + struct OperandInfo { + /// Rec - The definition this operand is declared as. + /// + Record *Rec; + + /// Name - If this operand was assigned a symbolic name, this is it, + /// otherwise, it's empty. + std::string Name; + + /// PrinterMethodName - The method used to print operands of this type in + /// the asmprinter. + std::string PrinterMethodName; + + /// MIOperandNo - Currently (this is meant to be phased out), some logical + /// operands correspond to multiple MachineInstr operands. In the X86 + /// target for example, one address operand is represented as 4 + /// MachineOperands. Because of this, the operand number in the + /// OperandList may not match the MachineInstr operand num. Until it + /// does, this contains the MI operand index of this operand. + unsigned MIOperandNo; + unsigned MINumOperands; // The number of operands. + + /// DoNotEncode - Bools are set to true in this vector for each operand in + /// the DisableEncoding list. These should not be emitted by the code + /// emitter. + std::vector<bool> DoNotEncode; + + /// MIOperandInfo - Default MI operand type. Note an operand may be made + /// up of multiple MI operands. + DagInit *MIOperandInfo; + + /// Constraint info for this operand. This operand can have pieces, so we + /// track constraint info for each. + std::vector<std::string> Constraints; + + OperandInfo(Record *R, const std::string &N, const std::string &PMN, + unsigned MION, unsigned MINO, DagInit *MIOI) + : Rec(R), Name(N), PrinterMethodName(PMN), MIOperandNo(MION), + MINumOperands(MINO), MIOperandInfo(MIOI) {} + }; + + /// NumDefs - Number of def operands declared. + /// + unsigned NumDefs; + + /// OperandList - The list of declared operands, along with their declared + /// type (which is a record). + std::vector<OperandInfo> OperandList; + + // Various boolean values we track for the instruction. + bool isReturn; + bool isBranch; + bool isIndirectBranch; + bool isBarrier; + bool isCall; + bool canFoldAsLoad; + bool mayLoad, mayStore; + bool isPredicable; + bool isConvertibleToThreeAddress; + bool isCommutable; + bool isTerminator; + bool isReMaterializable; + bool hasDelaySlot; + bool usesCustomDAGSchedInserter; + bool isVariadic; + bool hasCtrlDep; + bool isNotDuplicable; + bool hasOptionalDef; + bool hasSideEffects; + bool mayHaveSideEffects; + bool neverHasSideEffects; + bool isAsCheapAsAMove; + + /// 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. + std::pair<unsigned,unsigned> ParseOperandName(const std::string &Op, + bool AllowWholeOp = true); + + /// getFlattenedOperandNumber - Flatten a operand/suboperand pair into a + /// flat machineinstr operand #. + unsigned getFlattenedOperandNumber(std::pair<unsigned,unsigned> Op) const { + return OperandList[Op.first].MIOperandNo + Op.second; + } + + /// getSubOperandNumber - Unflatten a operand number into an + /// operand/suboperand pair. + std::pair<unsigned,unsigned> getSubOperandNumber(unsigned Op) const { + for (unsigned i = 0; ; ++i) { + assert(i < OperandList.size() && "Invalid flat operand #"); + if (OperandList[i].MIOperandNo+OperandList[i].MINumOperands > Op) + return std::make_pair(i, Op-OperandList[i].MIOperandNo); + } + } + + + /// isFlatOperandNotEmitted - Return true if the specified flat operand # + /// should not be emitted with the code emitter. + bool isFlatOperandNotEmitted(unsigned FlatOpNo) const { + std::pair<unsigned,unsigned> Op = getSubOperandNumber(FlatOpNo); + if (OperandList[Op.first].DoNotEncode.size() > Op.second) + return OperandList[Op.first].DoNotEncode[Op.second]; + return false; + } + + CodeGenInstruction(Record *R, const std::string &AsmStr); + + /// 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. + unsigned getOperandNamed(const std::string &Name) const; + }; +} + +#endif diff --git a/utils/TableGen/CodeGenIntrinsics.h b/utils/TableGen/CodeGenIntrinsics.h new file mode 100644 index 0000000000000..7e7bdf989acf8 --- /dev/null +++ b/utils/TableGen/CodeGenIntrinsics.h @@ -0,0 +1,87 @@ +//===- CodeGenIntrinsic.h - Intrinsic Class Wrapper ------------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a wrapper class for the 'Intrinsic' TableGen class. +// +//===----------------------------------------------------------------------===// + +#ifndef CODEGEN_INTRINSIC_H +#define CODEGEN_INTRINSIC_H + +#include <string> +#include <vector> +#include "llvm/CodeGen/ValueTypes.h" + +namespace llvm { + class Record; + class RecordKeeper; + class CodeGenTarget; + + struct CodeGenIntrinsic { + Record *TheDef; // The actual record defining this intrinsic. + std::string Name; // The name of the LLVM function "llvm.bswap.i32" + std::string EnumName; // The name of the enum "bswap_i32" + std::string GCCBuiltinName;// Name of the corresponding GCC builtin, or "". + std::string TargetPrefix; // Target prefix, e.g. "ppc" for t-s intrinsics. + + /// IntrinsicSignature - This structure holds the return values and + /// parameter values of an intrinsic. If the number of return values is > 1, + /// then the intrinsic implicitly returns a first-class aggregate. The + /// numbering of the types starts at 0 with the first return value and + /// continues from there through the parameter list. This is useful for + /// "matching" types. + struct IntrinsicSignature { + /// RetVTs - The MVT::SimpleValueType for each return type. Note that this + /// list is only populated when in the context of a target .td file. When + /// building Intrinsics.td, this isn't available, because we don't know + /// the target pointer size. + std::vector<MVT::SimpleValueType> RetVTs; + + /// RetTypeDefs - The records for each return type. + std::vector<Record*> RetTypeDefs; + + /// ParamVTs - The MVT::SimpleValueType for each parameter type. Note that + /// this list is only populated when in the context of a target .td file. + /// When building Intrinsics.td, this isn't available, because we don't + /// know the target pointer size. + std::vector<MVT::SimpleValueType> ParamVTs; + + /// ParamTypeDefs - The records for each parameter type. + std::vector<Record*> ParamTypeDefs; + }; + + IntrinsicSignature IS; + + // Memory mod/ref behavior of this intrinsic. + enum { + NoMem, ReadArgMem, ReadMem, WriteArgMem, WriteMem + } ModRef; + + /// This is set to true if the intrinsic is overloaded by its argument + /// types. + bool isOverloaded; + + /// isCommutative - True if the intrinsic is commutative. + bool isCommutative; + + enum ArgAttribute { + NoCapture + }; + std::vector<std::pair<unsigned, ArgAttribute> > ArgumentAttributes; + + CodeGenIntrinsic(Record *R); + }; + + /// LoadIntrinsics - Read all of the intrinsics defined in the specified + /// .td file. + std::vector<CodeGenIntrinsic> LoadIntrinsics(const RecordKeeper &RC, + bool TargetOnly); +} + +#endif diff --git a/utils/TableGen/CodeGenRegisters.h b/utils/TableGen/CodeGenRegisters.h new file mode 100644 index 0000000000000..6f8682be59d3d --- /dev/null +++ b/utils/TableGen/CodeGenRegisters.h @@ -0,0 +1,61 @@ +//===- CodeGenRegisters.h - Register and RegisterClass Info -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines structures to encapsulate information gleaned from the +// target register and register class definitions. +// +//===----------------------------------------------------------------------===// + +#ifndef CODEGEN_REGISTERS_H +#define CODEGEN_REGISTERS_H + +#include "llvm/CodeGen/ValueTypes.h" +#include <string> +#include <vector> +#include <cstdlib> + +namespace llvm { + class Record; + + /// CodeGenRegister - Represents a register definition. + struct CodeGenRegister { + Record *TheDef; + const std::string &getName() const; + unsigned DeclaredSpillSize, DeclaredSpillAlignment; + CodeGenRegister(Record *R); + }; + + + struct CodeGenRegisterClass { + Record *TheDef; + std::string Namespace; + std::vector<Record*> Elements; + std::vector<MVT::SimpleValueType> VTs; + unsigned SpillSize; + unsigned SpillAlignment; + int CopyCost; + std::vector<Record*> SubRegClasses; + std::string MethodProtos, MethodBodies; + + const std::string &getName() const; + const std::vector<MVT::SimpleValueType> &getValueTypes() const {return VTs;} + unsigned getNumValueTypes() const { return VTs.size(); } + + MVT::SimpleValueType getValueTypeNum(unsigned VTNum) const { + if (VTNum < VTs.size()) + return VTs[VTNum]; + assert(0 && "VTNum greater than number of ValueTypes in RegClass!"); + abort(); + } + + CodeGenRegisterClass(Record *R); + }; +} + +#endif diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp new file mode 100644 index 0000000000000..aad1be9416222 --- /dev/null +++ b/utils/TableGen/CodeGenTarget.cpp @@ -0,0 +1,576 @@ +//===- CodeGenTarget.cpp - CodeGen Target Class Wrapper -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenTarget.h" +#include "CodeGenIntrinsics.h" +#include "Record.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Streams.h" +#include <algorithm> +using namespace llvm; + +static cl::opt<unsigned> +AsmWriterNum("asmwriternum", cl::init(0), + cl::desc("Make -gen-asm-writer emit assembly writer #N")); + +/// getValueType - Return the MVT::SimpleValueType that the specified TableGen +/// record corresponds to. +MVT::SimpleValueType llvm::getValueType(Record *Rec) { + return (MVT::SimpleValueType)Rec->getValueAsInt("Value"); +} + +std::string llvm::getName(MVT::SimpleValueType T) { + switch (T) { + case MVT::Other: return "UNKNOWN"; + case MVT::i1: return "MVT::i1"; + case MVT::i8: return "MVT::i8"; + case MVT::i16: return "MVT::i16"; + case MVT::i32: return "MVT::i32"; + case MVT::i64: return "MVT::i64"; + case MVT::i128: return "MVT::i128"; + case MVT::iAny: return "MVT::iAny"; + case MVT::fAny: return "MVT::fAny"; + case MVT::f32: return "MVT::f32"; + case MVT::f64: return "MVT::f64"; + case MVT::f80: return "MVT::f80"; + case MVT::f128: return "MVT::f128"; + case MVT::ppcf128: return "MVT::ppcf128"; + case MVT::Flag: return "MVT::Flag"; + case MVT::isVoid:return "MVT::isVoid"; + case MVT::v2i8: return "MVT::v2i8"; + case MVT::v4i8: return "MVT::v4i8"; + case MVT::v2i16: return "MVT::v2i16"; + case MVT::v8i8: return "MVT::v8i8"; + case MVT::v4i16: return "MVT::v4i16"; + case MVT::v2i32: return "MVT::v2i32"; + case MVT::v1i64: return "MVT::v1i64"; + case MVT::v16i8: return "MVT::v16i8"; + case MVT::v8i16: return "MVT::v8i16"; + case MVT::v4i32: return "MVT::v4i32"; + case MVT::v2i64: return "MVT::v2i64"; + case MVT::v2f32: return "MVT::v2f32"; + case MVT::v4f32: return "MVT::v4f32"; + case MVT::v2f64: return "MVT::v2f64"; + case MVT::v3i32: return "MVT::v3i32"; + case MVT::v3f32: return "MVT::v3f32"; + case MVT::iPTR: return "TLI.getPointerTy()"; + case MVT::iPTRAny: return "TLI.getPointerTy()"; + default: assert(0 && "ILLEGAL VALUE TYPE!"); return ""; + } +} + +std::string llvm::getEnumName(MVT::SimpleValueType T) { + switch (T) { + case MVT::Other: return "MVT::Other"; + case MVT::i1: return "MVT::i1"; + case MVT::i8: return "MVT::i8"; + case MVT::i16: return "MVT::i16"; + case MVT::i32: return "MVT::i32"; + case MVT::i64: return "MVT::i64"; + case MVT::i128: return "MVT::i128"; + case MVT::iAny: return "MVT::iAny"; + case MVT::fAny: return "MVT::fAny"; + case MVT::f32: return "MVT::f32"; + case MVT::f64: return "MVT::f64"; + case MVT::f80: return "MVT::f80"; + case MVT::f128: return "MVT::f128"; + case MVT::ppcf128: return "MVT::ppcf128"; + case MVT::Flag: return "MVT::Flag"; + case MVT::isVoid:return "MVT::isVoid"; + case MVT::v2i8: return "MVT::v2i8"; + case MVT::v4i8: return "MVT::v4i8"; + case MVT::v2i16: return "MVT::v2i16"; + case MVT::v8i8: return "MVT::v8i8"; + case MVT::v4i16: return "MVT::v4i16"; + case MVT::v2i32: return "MVT::v2i32"; + case MVT::v1i64: return "MVT::v1i64"; + case MVT::v16i8: return "MVT::v16i8"; + case MVT::v8i16: return "MVT::v8i16"; + case MVT::v4i32: return "MVT::v4i32"; + case MVT::v2i64: return "MVT::v2i64"; + case MVT::v2f32: return "MVT::v2f32"; + case MVT::v4f32: return "MVT::v4f32"; + case MVT::v2f64: return "MVT::v2f64"; + case MVT::v3i32: return "MVT::v3i32"; + case MVT::v3f32: return "MVT::v3f32"; + case MVT::iPTR: return "MVT::iPTR"; + case MVT::iPTRAny: return "MVT::iPTRAny"; + default: assert(0 && "ILLEGAL VALUE TYPE!"); return ""; + } +} + +/// getQualifiedName - Return the name of the specified record, with a +/// namespace qualifier if the record contains one. +/// +std::string llvm::getQualifiedName(const Record *R) { + std::string Namespace = R->getValueAsString("Namespace"); + if (Namespace.empty()) return R->getName(); + return Namespace + "::" + R->getName(); +} + + + + +/// getTarget - Return the current instance of the Target class. +/// +CodeGenTarget::CodeGenTarget() { + std::vector<Record*> Targets = Records.getAllDerivedDefinitions("Target"); + if (Targets.size() == 0) + throw std::string("ERROR: No 'Target' subclasses defined!"); + if (Targets.size() != 1) + throw std::string("ERROR: Multiple subclasses of Target defined!"); + TargetRec = Targets[0]; +} + + +const std::string &CodeGenTarget::getName() const { + return TargetRec->getName(); +} + +std::string CodeGenTarget::getInstNamespace() const { + std::string InstNS; + + for (inst_iterator i = inst_begin(), e = inst_end(); i != e; ++i) { + InstNS = i->second.Namespace; + + // Make sure not to pick up "TargetInstrInfo" by accidentally getting + // the namespace off the PHI instruction or something. + if (InstNS != "TargetInstrInfo") + break; + } + + return InstNS; +} + +Record *CodeGenTarget::getInstructionSet() const { + return TargetRec->getValueAsDef("InstructionSet"); +} + +/// getAsmWriter - Return the AssemblyWriter definition for this target. +/// +Record *CodeGenTarget::getAsmWriter() const { + std::vector<Record*> LI = TargetRec->getValueAsListOfDefs("AssemblyWriters"); + if (AsmWriterNum >= LI.size()) + throw "Target does not have an AsmWriter #" + utostr(AsmWriterNum) + "!"; + return LI[AsmWriterNum]; +} + +void CodeGenTarget::ReadRegisters() const { + std::vector<Record*> Regs = Records.getAllDerivedDefinitions("Register"); + if (Regs.empty()) + throw std::string("No 'Register' subclasses defined!"); + + Registers.reserve(Regs.size()); + Registers.assign(Regs.begin(), Regs.end()); +} + +CodeGenRegister::CodeGenRegister(Record *R) : TheDef(R) { + DeclaredSpillSize = R->getValueAsInt("SpillSize"); + DeclaredSpillAlignment = R->getValueAsInt("SpillAlignment"); +} + +const std::string &CodeGenRegister::getName() const { + return TheDef->getName(); +} + +void CodeGenTarget::ReadRegisterClasses() const { + std::vector<Record*> RegClasses = + Records.getAllDerivedDefinitions("RegisterClass"); + if (RegClasses.empty()) + throw std::string("No 'RegisterClass' subclasses defined!"); + + RegisterClasses.reserve(RegClasses.size()); + RegisterClasses.assign(RegClasses.begin(), RegClasses.end()); +} + +std::vector<unsigned char> CodeGenTarget::getRegisterVTs(Record *R) const { + std::vector<unsigned char> Result; + const std::vector<CodeGenRegisterClass> &RCs = getRegisterClasses(); + for (unsigned i = 0, e = RCs.size(); i != e; ++i) { + const CodeGenRegisterClass &RC = RegisterClasses[i]; + for (unsigned ei = 0, ee = RC.Elements.size(); ei != ee; ++ei) { + if (R == RC.Elements[ei]) { + const std::vector<MVT::SimpleValueType> &InVTs = RC.getValueTypes(); + for (unsigned i = 0, e = InVTs.size(); i != e; ++i) + Result.push_back(InVTs[i]); + } + } + } + return Result; +} + + +CodeGenRegisterClass::CodeGenRegisterClass(Record *R) : TheDef(R) { + // Rename anonymous register classes. + if (R->getName().size() > 9 && R->getName()[9] == '.') { + static unsigned AnonCounter = 0; + R->setName("AnonRegClass_"+utostr(AnonCounter++)); + } + + std::vector<Record*> TypeList = R->getValueAsListOfDefs("RegTypes"); + 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!"; + VTs.push_back(getValueType(Type)); + } + assert(!VTs.empty() && "RegisterClass must contain at least one ValueType!"); + + std::vector<Record*> RegList = R->getValueAsListOfDefs("MemberList"); + for (unsigned i = 0, e = RegList.size(); i != e; ++i) { + Record *Reg = RegList[i]; + if (!Reg->isSubClassOf("Register")) + throw "Register Class member '" + Reg->getName() + + "' does not derive from the Register class!"; + Elements.push_back(Reg); + } + + std::vector<Record*> SubRegClassList = + R->getValueAsListOfDefs("SubRegClassList"); + for (unsigned i = 0, e = SubRegClassList.size(); i != e; ++i) { + Record *SubRegClass = SubRegClassList[i]; + if (!SubRegClass->isSubClassOf("RegisterClass")) + throw "Register Class member '" + SubRegClass->getName() + + "' does not derive from the RegisterClass class!"; + SubRegClasses.push_back(SubRegClass); + } + + // Allow targets to override the size in bits of the RegisterClass. + unsigned Size = R->getValueAsInt("Size"); + + Namespace = R->getValueAsString("Namespace"); + SpillSize = Size ? Size : MVT(VTs[0]).getSizeInBits(); + SpillAlignment = R->getValueAsInt("Alignment"); + CopyCost = R->getValueAsInt("CopyCost"); + MethodBodies = R->getValueAsCode("MethodBodies"); + MethodProtos = R->getValueAsCode("MethodProtos"); +} + +const std::string &CodeGenRegisterClass::getName() const { + return TheDef->getName(); +} + +void CodeGenTarget::ReadLegalValueTypes() const { + const std::vector<CodeGenRegisterClass> &RCs = getRegisterClasses(); + for (unsigned i = 0, e = RCs.size(); i != e; ++i) + for (unsigned ri = 0, re = RCs[i].VTs.size(); ri != re; ++ri) + LegalValueTypes.push_back(RCs[i].VTs[ri]); + + // Remove duplicates. + std::sort(LegalValueTypes.begin(), LegalValueTypes.end()); + LegalValueTypes.erase(std::unique(LegalValueTypes.begin(), + LegalValueTypes.end()), + LegalValueTypes.end()); +} + + +void CodeGenTarget::ReadInstructions() const { + std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction"); + if (Insts.size() <= 2) + throw std::string("No 'Instruction' subclasses defined!"); + + // Parse the instructions defined in the .td file. + std::string InstFormatName = + getAsmWriter()->getValueAsString("InstFormatName"); + + for (unsigned i = 0, e = Insts.size(); i != e; ++i) { + std::string AsmStr = Insts[i]->getValueAsString(InstFormatName); + Instructions.insert(std::make_pair(Insts[i]->getName(), + CodeGenInstruction(Insts[i], AsmStr))); + } +} + +/// getInstructionsByEnumValue - Return all of the instructions defined by the +/// target, ordered by their enum value. +void CodeGenTarget:: +getInstructionsByEnumValue(std::vector<const CodeGenInstruction*> + &NumberedInstructions) { + std::map<std::string, CodeGenInstruction>::const_iterator I; + I = getInstructions().find("PHI"); + if (I == Instructions.end()) throw "Could not find 'PHI' instruction!"; + const CodeGenInstruction *PHI = &I->second; + + I = getInstructions().find("INLINEASM"); + if (I == Instructions.end()) throw "Could not find 'INLINEASM' instruction!"; + const CodeGenInstruction *INLINEASM = &I->second; + + I = getInstructions().find("DBG_LABEL"); + if (I == Instructions.end()) throw "Could not find 'DBG_LABEL' instruction!"; + const CodeGenInstruction *DBG_LABEL = &I->second; + + I = getInstructions().find("EH_LABEL"); + if (I == Instructions.end()) throw "Could not find 'EH_LABEL' instruction!"; + const CodeGenInstruction *EH_LABEL = &I->second; + + I = getInstructions().find("GC_LABEL"); + if (I == Instructions.end()) throw "Could not find 'GC_LABEL' instruction!"; + const CodeGenInstruction *GC_LABEL = &I->second; + + I = getInstructions().find("DECLARE"); + if (I == Instructions.end()) throw "Could not find 'DECLARE' instruction!"; + const CodeGenInstruction *DECLARE = &I->second; + + I = getInstructions().find("EXTRACT_SUBREG"); + if (I == Instructions.end()) + throw "Could not find 'EXTRACT_SUBREG' instruction!"; + const CodeGenInstruction *EXTRACT_SUBREG = &I->second; + + I = getInstructions().find("INSERT_SUBREG"); + if (I == Instructions.end()) + throw "Could not find 'INSERT_SUBREG' instruction!"; + const CodeGenInstruction *INSERT_SUBREG = &I->second; + + I = getInstructions().find("IMPLICIT_DEF"); + if (I == Instructions.end()) + throw "Could not find 'IMPLICIT_DEF' instruction!"; + const CodeGenInstruction *IMPLICIT_DEF = &I->second; + + I = getInstructions().find("SUBREG_TO_REG"); + if (I == Instructions.end()) + throw "Could not find 'SUBREG_TO_REG' instruction!"; + const CodeGenInstruction *SUBREG_TO_REG = &I->second; + + I = getInstructions().find("COPY_TO_REGCLASS"); + if (I == Instructions.end()) + throw "Could not find 'COPY_TO_REGCLASS' instruction!"; + const CodeGenInstruction *COPY_TO_REGCLASS = &I->second; + + // Print out the rest of the instructions now. + NumberedInstructions.push_back(PHI); + NumberedInstructions.push_back(INLINEASM); + NumberedInstructions.push_back(DBG_LABEL); + NumberedInstructions.push_back(EH_LABEL); + NumberedInstructions.push_back(GC_LABEL); + NumberedInstructions.push_back(DECLARE); + NumberedInstructions.push_back(EXTRACT_SUBREG); + NumberedInstructions.push_back(INSERT_SUBREG); + NumberedInstructions.push_back(IMPLICIT_DEF); + NumberedInstructions.push_back(SUBREG_TO_REG); + NumberedInstructions.push_back(COPY_TO_REGCLASS); + for (inst_iterator II = inst_begin(), E = inst_end(); II != E; ++II) + if (&II->second != PHI && + &II->second != INLINEASM && + &II->second != DBG_LABEL && + &II->second != EH_LABEL && + &II->second != GC_LABEL && + &II->second != DECLARE && + &II->second != EXTRACT_SUBREG && + &II->second != INSERT_SUBREG && + &II->second != IMPLICIT_DEF && + &II->second != SUBREG_TO_REG && + &II->second != COPY_TO_REGCLASS) + NumberedInstructions.push_back(&II->second); +} + + +/// isLittleEndianEncoding - Return whether this target encodes its instruction +/// in little-endian format, i.e. bits laid out in the order [0..n] +/// +bool CodeGenTarget::isLittleEndianEncoding() const { + return getInstructionSet()->getValueAsBit("isLittleEndianEncoding"); +} + +//===----------------------------------------------------------------------===// +// ComplexPattern implementation +// +ComplexPattern::ComplexPattern(Record *R) { + Ty = ::getValueType(R->getValueAsDef("Ty")); + NumOperands = R->getValueAsInt("NumOperands"); + SelectFunc = R->getValueAsString("SelectFunc"); + RootNodes = R->getValueAsListOfDefs("RootNodes"); + + // Parse the properties. + Properties = 0; + std::vector<Record*> PropList = R->getValueAsListOfDefs("Properties"); + for (unsigned i = 0, e = PropList.size(); i != e; ++i) + if (PropList[i]->getName() == "SDNPHasChain") { + Properties |= 1 << SDNPHasChain; + } else if (PropList[i]->getName() == "SDNPOptInFlag") { + Properties |= 1 << SDNPOptInFlag; + } else if (PropList[i]->getName() == "SDNPMayStore") { + Properties |= 1 << SDNPMayStore; + } else if (PropList[i]->getName() == "SDNPMayLoad") { + Properties |= 1 << SDNPMayLoad; + } else if (PropList[i]->getName() == "SDNPSideEffect") { + Properties |= 1 << SDNPSideEffect; + } else if (PropList[i]->getName() == "SDNPMemOperand") { + Properties |= 1 << SDNPMemOperand; + } else { + cerr << "Unsupported SD Node property '" << PropList[i]->getName() + << "' on ComplexPattern '" << R->getName() << "'!\n"; + exit(1); + } + + // Parse the attributes. + Attributes = 0; + PropList = R->getValueAsListOfDefs("Attributes"); + for (unsigned i = 0, e = PropList.size(); i != e; ++i) + if (PropList[i]->getName() == "CPAttrParentAsRoot") { + Attributes |= 1 << CPAttrParentAsRoot; + } else { + cerr << "Unsupported pattern attribute '" << PropList[i]->getName() + << "' on ComplexPattern '" << R->getName() << "'!\n"; + exit(1); + } +} + +//===----------------------------------------------------------------------===// +// CodeGenIntrinsic Implementation +//===----------------------------------------------------------------------===// + +std::vector<CodeGenIntrinsic> llvm::LoadIntrinsics(const RecordKeeper &RC, + bool TargetOnly) { + std::vector<Record*> I = RC.getAllDerivedDefinitions("Intrinsic"); + + std::vector<CodeGenIntrinsic> Result; + + for (unsigned i = 0, e = I.size(); i != e; ++i) { + bool isTarget = I[i]->getValueAsBit("isTarget"); + if (isTarget == TargetOnly) + Result.push_back(CodeGenIntrinsic(I[i])); + } + return Result; +} + +CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { + TheDef = R; + std::string DefName = R->getName(); + ModRef = WriteMem; + isOverloaded = false; + isCommutative = false; + + if (DefName.size() <= 4 || + std::string(DefName.begin(), DefName.begin() + 4) != "int_") + throw "Intrinsic '" + DefName + "' does not start with 'int_'!"; + + EnumName = std::string(DefName.begin()+4, DefName.end()); + + if (R->getValue("GCCBuiltinName")) // Ignore a missing GCCBuiltinName field. + GCCBuiltinName = R->getValueAsString("GCCBuiltinName"); + + TargetPrefix = R->getValueAsString("TargetPrefix"); + Name = R->getValueAsString("LLVMName"); + + if (Name == "") { + // If an explicit name isn't specified, derive one from the DefName. + Name = "llvm."; + + for (unsigned i = 0, e = EnumName.size(); i != e; ++i) + Name += (EnumName[i] == '_') ? '.' : EnumName[i]; + } else { + // 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.'!"; + } + + // If TargetPrefix is specified, make sure that Name starts with + // "llvm.<targetprefix>.". + if (!TargetPrefix.empty()) { + 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 + ".'!"; + } + + // Parse the list of return types. + std::vector<MVT::SimpleValueType> OverloadedVTs; + ListInit *TypeList = R->getValueAsListInit("RetTypes"); + for (unsigned i = 0, e = TypeList->getSize(); i != e; ++i) { + Record *TyEl = TypeList->getElementAsRecord(i); + assert(TyEl->isSubClassOf("LLVMType") && "Expected a type!"); + MVT::SimpleValueType VT; + if (TyEl->isSubClassOf("LLVMMatchType")) { + unsigned MatchTy = TyEl->getValueAsInt("Number"); + assert(MatchTy < OverloadedVTs.size() && + "Invalid matching number!"); + VT = OverloadedVTs[MatchTy]; + // It only makes sense to use the extended and truncated vector element + // variants with iAny types; otherwise, if the intrinsic is not + // overloaded, all the types can be specified directly. + assert(((!TyEl->isSubClassOf("LLVMExtendedElementVectorType") && + !TyEl->isSubClassOf("LLVMTruncatedElementVectorType")) || + VT == MVT::iAny) && "Expected iAny type"); + } else { + VT = getValueType(TyEl->getValueAsDef("VT")); + } + if (VT == MVT::iAny || VT == MVT::fAny || VT == MVT::iPTRAny) { + OverloadedVTs.push_back(VT); + isOverloaded |= true; + } + IS.RetVTs.push_back(VT); + IS.RetTypeDefs.push_back(TyEl); + } + + if (IS.RetVTs.size() == 0) + throw "Intrinsic '"+DefName+"' needs at least a type for the ret value!"; + + // Parse the list of parameter types. + TypeList = R->getValueAsListInit("ParamTypes"); + for (unsigned i = 0, e = TypeList->getSize(); i != e; ++i) { + Record *TyEl = TypeList->getElementAsRecord(i); + assert(TyEl->isSubClassOf("LLVMType") && "Expected a type!"); + MVT::SimpleValueType VT; + if (TyEl->isSubClassOf("LLVMMatchType")) { + unsigned MatchTy = TyEl->getValueAsInt("Number"); + assert(MatchTy < OverloadedVTs.size() && + "Invalid matching number!"); + VT = OverloadedVTs[MatchTy]; + // It only makes sense to use the extended and truncated vector element + // variants with iAny types; otherwise, if the intrinsic is not + // overloaded, all the types can be specified directly. + assert(((!TyEl->isSubClassOf("LLVMExtendedElementVectorType") && + !TyEl->isSubClassOf("LLVMTruncatedElementVectorType")) || + VT == MVT::iAny) && "Expected iAny type"); + } else + VT = getValueType(TyEl->getValueAsDef("VT")); + if (VT == MVT::iAny || VT == MVT::fAny || VT == MVT::iPTRAny) { + OverloadedVTs.push_back(VT); + isOverloaded |= true; + } + IS.ParamVTs.push_back(VT); + IS.ParamTypeDefs.push_back(TyEl); + } + + // Parse the intrinsic properties. + ListInit *PropList = R->getValueAsListInit("Properties"); + for (unsigned i = 0, e = PropList->getSize(); i != e; ++i) { + Record *Property = PropList->getElementAsRecord(i); + assert(Property->isSubClassOf("IntrinsicProperty") && + "Expected a property!"); + + if (Property->getName() == "IntrNoMem") + ModRef = NoMem; + else if (Property->getName() == "IntrReadArgMem") + ModRef = ReadArgMem; + else if (Property->getName() == "IntrReadMem") + ModRef = ReadMem; + else if (Property->getName() == "IntrWriteArgMem") + ModRef = WriteArgMem; + else if (Property->getName() == "IntrWriteMem") + ModRef = WriteMem; + else if (Property->getName() == "Commutative") + isCommutative = true; + else if (Property->isSubClassOf("NoCapture")) { + unsigned ArgNo = Property->getValueAsInt("ArgNo"); + ArgumentAttributes.push_back(std::make_pair(ArgNo, NoCapture)); + } else + assert(0 && "Unknown property!"); + } +} diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h new file mode 100644 index 0000000000000..c7cc77ccd41aa --- /dev/null +++ b/utils/TableGen/CodeGenTarget.h @@ -0,0 +1,243 @@ +//===- CodeGenTarget.h - Target Class Wrapper -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#ifndef CODEGEN_TARGET_H +#define CODEGEN_TARGET_H + +#include "CodeGenRegisters.h" +#include "CodeGenInstruction.h" +#include <algorithm> +#include <iosfwd> +#include <map> + +namespace llvm { + +class Record; +class RecordKeeper; +struct CodeGenRegister; +class CodeGenTarget; + +// SelectionDAG node properties. +// SDNPMemOperand: indicates that a node touches memory and therefore must +// have an associated memory operand that describes the access. +enum SDNP { + SDNPCommutative, + SDNPAssociative, + SDNPHasChain, + SDNPOutFlag, + SDNPInFlag, + SDNPOptInFlag, + SDNPMayLoad, + SDNPMayStore, + SDNPSideEffect, + SDNPMemOperand +}; + +// ComplexPattern attributes. +enum CPAttr { CPAttrParentAsRoot }; + +/// getValueType - Return the MVT::SimpleValueType that the specified TableGen +/// record corresponds to. +MVT::SimpleValueType getValueType(Record *Rec); + +std::string getName(MVT::SimpleValueType T); +std::string getEnumName(MVT::SimpleValueType T); + +/// getQualifiedName - Return the name of the specified record, with a +/// namespace qualifier if the record contains one. +std::string getQualifiedName(const Record *R); + +/// CodeGenTarget - This class corresponds to the Target class in the .td files. +/// +class CodeGenTarget { + Record *TargetRec; + + mutable std::map<std::string, CodeGenInstruction> Instructions; + mutable std::vector<CodeGenRegister> Registers; + mutable std::vector<CodeGenRegisterClass> RegisterClasses; + mutable std::vector<MVT::SimpleValueType> LegalValueTypes; + void ReadRegisters() const; + void ReadRegisterClasses() const; + void ReadInstructions() const; + void ReadLegalValueTypes() const; +public: + CodeGenTarget(); + + Record *getTargetRecord() const { return TargetRec; } + const std::string &getName() const; + + /// getInstNamespace - Return the target-specific instruction namespace. + /// + std::string getInstNamespace() const; + + /// getInstructionSet - Return the InstructionSet object. + /// + Record *getInstructionSet() const; + + /// getAsmWriter - Return the AssemblyWriter definition for this target. + /// + Record *getAsmWriter() const; + + const std::vector<CodeGenRegister> &getRegisters() const { + if (Registers.empty()) ReadRegisters(); + return Registers; + } + + const std::vector<CodeGenRegisterClass> &getRegisterClasses() const { + if (RegisterClasses.empty()) ReadRegisterClasses(); + return RegisterClasses; + } + + const CodeGenRegisterClass &getRegisterClass(Record *R) const { + const std::vector<CodeGenRegisterClass> &RC = getRegisterClasses(); + for (unsigned i = 0, e = RC.size(); i != e; ++i) + if (RC[i].TheDef == R) + return RC[i]; + assert(0 && "Didn't find the register class"); + abort(); + } + + /// getRegisterClassForRegister - Find the register class that contains the + /// specified physical register. If the register is not in a register + /// class, return null. If the register is in multiple classes, and the + /// classes have a superset-subset relationship and the same set of + /// types, return the superclass. Otherwise return null. + const CodeGenRegisterClass *getRegisterClassForRegister(Record *R) const { + const std::vector<CodeGenRegisterClass> &RCs = getRegisterClasses(); + const CodeGenRegisterClass *FoundRC = 0; + for (unsigned i = 0, e = RCs.size(); i != e; ++i) { + const CodeGenRegisterClass &RC = RegisterClasses[i]; + for (unsigned ei = 0, ee = RC.Elements.size(); ei != ee; ++ei) { + if (R != RC.Elements[ei]) + continue; + + // If a register's classes have different types, return null. + if (FoundRC && RC.getValueTypes() != FoundRC->getValueTypes()) + return 0; + + // If this is the first class that contains the register, + // make a note of it and go on to the next class. + if (!FoundRC) { + FoundRC = &RC; + break; + } + + std::vector<Record *> Elements(RC.Elements); + std::vector<Record *> FoundElements(FoundRC->Elements); + std::sort(Elements.begin(), Elements.end()); + std::sort(FoundElements.begin(), FoundElements.end()); + + // Check to see if the previously found class that contains + // the register is a subclass of the current class. If so, + // prefer the superclass. + if (std::includes(Elements.begin(), Elements.end(), + FoundElements.begin(), FoundElements.end())) { + FoundRC = &RC; + break; + } + + // Check to see if the previously found class that contains + // the register is a superclass of the current class. If so, + // prefer the superclass. + if (std::includes(FoundElements.begin(), FoundElements.end(), + Elements.begin(), Elements.end())) + break; + + // Multiple classes, and neither is a superclass of the other. + // Return null. + return 0; + } + } + return FoundRC; + } + + /// getRegisterVTs - Find the union of all possible SimpleValueTypes for the + /// specified physical register. + std::vector<unsigned char> getRegisterVTs(Record *R) const; + + const std::vector<MVT::SimpleValueType> &getLegalValueTypes() const { + if (LegalValueTypes.empty()) ReadLegalValueTypes(); + return LegalValueTypes; + } + + /// isLegalValueType - Return true if the specified value type is natively + /// supported by the target (i.e. there are registers that directly hold it). + bool isLegalValueType(MVT::SimpleValueType VT) const { + const std::vector<MVT::SimpleValueType> &LegalVTs = getLegalValueTypes(); + for (unsigned i = 0, e = LegalVTs.size(); i != e; ++i) + if (LegalVTs[i] == VT) return true; + return false; + } + + /// getInstructions - Return all of the instructions defined for this target. + /// + const std::map<std::string, CodeGenInstruction> &getInstructions() const { + if (Instructions.empty()) ReadInstructions(); + return Instructions; + } + std::map<std::string, CodeGenInstruction> &getInstructions() { + if (Instructions.empty()) ReadInstructions(); + return Instructions; + } + + CodeGenInstruction &getInstruction(const std::string &Name) const { + const std::map<std::string, CodeGenInstruction> &Insts = getInstructions(); + assert(Insts.count(Name) && "Not an instruction!"); + return const_cast<CodeGenInstruction&>(Insts.find(Name)->second); + } + + typedef std::map<std::string, + CodeGenInstruction>::const_iterator inst_iterator; + inst_iterator inst_begin() const { return getInstructions().begin(); } + inst_iterator inst_end() const { return Instructions.end(); } + + /// getInstructionsByEnumValue - Return all of the instructions defined by the + /// target, ordered by their enum value. + void getInstructionsByEnumValue(std::vector<const CodeGenInstruction*> + &NumberedInstructions); + + + /// isLittleEndianEncoding - are instruction bit patterns defined as [0..n]? + /// + bool isLittleEndianEncoding() const; +}; + +/// ComplexPattern - ComplexPattern info, corresponding to the ComplexPattern +/// tablegen class in TargetSelectionDAG.td +class ComplexPattern { + MVT::SimpleValueType Ty; + unsigned NumOperands; + std::string SelectFunc; + std::vector<Record*> RootNodes; + unsigned Properties; // Node properties + unsigned Attributes; // Pattern attributes +public: + ComplexPattern() : NumOperands(0) {}; + ComplexPattern(Record *R); + + MVT::SimpleValueType getValueType() const { return Ty; } + unsigned getNumOperands() const { return NumOperands; } + const std::string &getSelectFunc() const { return SelectFunc; } + const std::vector<Record*> &getRootNodes() const { + return RootNodes; + } + bool hasProperty(enum SDNP Prop) const { return Properties & (1 << Prop); } + bool hasAttribute(enum CPAttr Attr) const { return Attributes & (1 << Attr); } +}; + +} // End llvm namespace + +#endif diff --git a/utils/TableGen/DAGISelEmitter.cpp b/utils/TableGen/DAGISelEmitter.cpp new file mode 100644 index 0000000000000..0e2e61596f69c --- /dev/null +++ b/utils/TableGen/DAGISelEmitter.cpp @@ -0,0 +1,2131 @@ +//===- DAGISelEmitter.cpp - Generate an instruction selector --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend emits a DAG instruction selector. +// +//===----------------------------------------------------------------------===// + +#include "DAGISelEmitter.h" +#include "Record.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Streams.h" +#include <algorithm> +#include <deque> +using namespace llvm; + +namespace { + cl::opt<bool> + GenDebug("gen-debug", cl::desc("Generate debug code"), + cl::init(false)); +} + +//===----------------------------------------------------------------------===// +// DAGISelEmitter Helper methods +// + +/// NodeIsComplexPattern - return true if N is a leaf node and a subclass of +/// ComplexPattern. +static bool NodeIsComplexPattern(TreePatternNode *N) { + return (N->isLeaf() && + dynamic_cast<DefInit*>(N->getLeafValue()) && + static_cast<DefInit*>(N->getLeafValue())->getDef()-> + isSubClassOf("ComplexPattern")); +} + +/// NodeGetComplexPattern - return the pointer to the ComplexPattern if N +/// is a leaf node and a subclass of ComplexPattern, else it returns NULL. +static const ComplexPattern *NodeGetComplexPattern(TreePatternNode *N, + CodeGenDAGPatterns &CGP) { + if (N->isLeaf() && + dynamic_cast<DefInit*>(N->getLeafValue()) && + static_cast<DefInit*>(N->getLeafValue())->getDef()-> + isSubClassOf("ComplexPattern")) { + return &CGP.getComplexPattern(static_cast<DefInit*>(N->getLeafValue()) + ->getDef()); + } + return NULL; +} + +/// getPatternSize - Return the 'size' of this pattern. We want to match large +/// patterns before small ones. This is used to determine the size of a +/// pattern. +static unsigned getPatternSize(TreePatternNode *P, CodeGenDAGPatterns &CGP) { + assert((EMVT::isExtIntegerInVTs(P->getExtTypes()) || + EMVT::isExtFloatingPointInVTs(P->getExtTypes()) || + P->getExtTypeNum(0) == MVT::isVoid || + P->getExtTypeNum(0) == MVT::Flag || + P->getExtTypeNum(0) == MVT::iPTR || + P->getExtTypeNum(0) == MVT::iPTRAny) && + "Not a valid pattern node to size!"); + unsigned Size = 3; // The node itself. + // If the root node is a ConstantSDNode, increases its size. + // e.g. (set R32:$dst, 0). + if (P->isLeaf() && dynamic_cast<IntInit*>(P->getLeafValue())) + Size += 2; + + // FIXME: This is a hack to statically increase the priority of patterns + // which maps a sub-dag to a complex pattern. e.g. favors LEA over ADD. + // Later we can allow complexity / cost for each pattern to be (optionally) + // specified. To get best possible pattern match we'll need to dynamically + // calculate the complexity of all patterns a dag can potentially map to. + const ComplexPattern *AM = NodeGetComplexPattern(P, CGP); + if (AM) + Size += AM->getNumOperands() * 3; + + // If this node has some predicate function that must match, it adds to the + // complexity of this node. + if (!P->getPredicateFns().empty()) + ++Size; + + // Count children in the count if they are also nodes. + for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i) { + TreePatternNode *Child = P->getChild(i); + if (!Child->isLeaf() && Child->getExtTypeNum(0) != MVT::Other) + Size += getPatternSize(Child, CGP); + else if (Child->isLeaf()) { + if (dynamic_cast<IntInit*>(Child->getLeafValue())) + Size += 5; // Matches a ConstantSDNode (+3) and a specific value (+2). + else if (NodeIsComplexPattern(Child)) + Size += getPatternSize(Child, CGP); + else if (!Child->getPredicateFns().empty()) + ++Size; + } + } + + return Size; +} + +/// getResultPatternCost - Compute the number of instructions for this pattern. +/// This is a temporary hack. We should really include the instruction +/// latencies in this calculation. +static unsigned getResultPatternCost(TreePatternNode *P, + CodeGenDAGPatterns &CGP) { + if (P->isLeaf()) return 0; + + unsigned Cost = 0; + Record *Op = P->getOperator(); + if (Op->isSubClassOf("Instruction")) { + Cost++; + CodeGenInstruction &II = CGP.getTargetInfo().getInstruction(Op->getName()); + if (II.usesCustomDAGSchedInserter) + Cost += 10; + } + for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i) + Cost += getResultPatternCost(P->getChild(i), CGP); + return Cost; +} + +/// getResultPatternCodeSize - Compute the code size of instructions for this +/// pattern. +static unsigned getResultPatternSize(TreePatternNode *P, + CodeGenDAGPatterns &CGP) { + if (P->isLeaf()) return 0; + + unsigned Cost = 0; + Record *Op = P->getOperator(); + if (Op->isSubClassOf("Instruction")) { + Cost += Op->getValueAsInt("CodeSize"); + } + for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i) + Cost += getResultPatternSize(P->getChild(i), CGP); + return Cost; +} + +// PatternSortingPredicate - return true if we prefer to match LHS before RHS. +// In particular, we want to match maximal patterns first and lowest cost within +// a particular complexity first. +struct PatternSortingPredicate { + PatternSortingPredicate(CodeGenDAGPatterns &cgp) : CGP(cgp) {} + CodeGenDAGPatterns &CGP; + + typedef std::pair<unsigned, std::string> CodeLine; + typedef std::vector<CodeLine> CodeList; + typedef std::vector<std::pair<const PatternToMatch*, CodeList> > PatternList; + + bool operator()(const std::pair<const PatternToMatch*, CodeList> &LHSPair, + const std::pair<const PatternToMatch*, CodeList> &RHSPair) { + const PatternToMatch *LHS = LHSPair.first; + const PatternToMatch *RHS = RHSPair.first; + + unsigned LHSSize = getPatternSize(LHS->getSrcPattern(), CGP); + unsigned RHSSize = getPatternSize(RHS->getSrcPattern(), CGP); + LHSSize += LHS->getAddedComplexity(); + RHSSize += RHS->getAddedComplexity(); + if (LHSSize > RHSSize) return true; // LHS -> bigger -> less cost + if (LHSSize < RHSSize) return false; + + // If the patterns have equal complexity, compare generated instruction cost + unsigned LHSCost = getResultPatternCost(LHS->getDstPattern(), CGP); + unsigned RHSCost = getResultPatternCost(RHS->getDstPattern(), CGP); + if (LHSCost < RHSCost) return true; + if (LHSCost > RHSCost) return false; + + return getResultPatternSize(LHS->getDstPattern(), CGP) < + getResultPatternSize(RHS->getDstPattern(), CGP); + } +}; + +/// getRegisterValueType - Look up and return the ValueType of the specified +/// register. If the register is a member of multiple register classes which +/// have different associated types, return MVT::Other. +static MVT::SimpleValueType getRegisterValueType(Record *R, const CodeGenTarget &T) { + bool FoundRC = false; + MVT::SimpleValueType VT = MVT::Other; + const std::vector<CodeGenRegisterClass> &RCs = T.getRegisterClasses(); + std::vector<CodeGenRegisterClass>::const_iterator RC; + std::vector<Record*>::const_iterator Element; + + for (RC = RCs.begin() ; RC != RCs.end() ; RC++) { + Element = find((*RC).Elements.begin(), (*RC).Elements.end(), R); + if (Element != (*RC).Elements.end()) { + if (!FoundRC) { + FoundRC = true; + VT = (*RC).getValueTypeNum(0); + } else { + // In multiple RC's + if (VT != (*RC).getValueTypeNum(0)) { + // Types of the RC's do not agree. Return MVT::Other. The + // target is responsible for handling this. + return MVT::Other; + } + } + } + } + return VT; +} + + +/// RemoveAllTypes - A quick recursive walk over a pattern which removes all +/// type information from it. +static void RemoveAllTypes(TreePatternNode *N) { + N->removeTypes(); + if (!N->isLeaf()) + for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) + RemoveAllTypes(N->getChild(i)); +} + +/// NodeHasProperty - return true if TreePatternNode has the specified +/// property. +static bool NodeHasProperty(TreePatternNode *N, SDNP Property, + CodeGenDAGPatterns &CGP) { + if (N->isLeaf()) { + const ComplexPattern *CP = NodeGetComplexPattern(N, CGP); + if (CP) + return CP->hasProperty(Property); + return false; + } + Record *Operator = N->getOperator(); + if (!Operator->isSubClassOf("SDNode")) return false; + + return CGP.getSDNodeInfo(Operator).hasProperty(Property); +} + +static bool PatternHasProperty(TreePatternNode *N, SDNP Property, + CodeGenDAGPatterns &CGP) { + if (NodeHasProperty(N, Property, CGP)) + return true; + + for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) { + TreePatternNode *Child = N->getChild(i); + if (PatternHasProperty(Child, Property, CGP)) + return true; + } + + return false; +} + +static std::string getOpcodeName(Record *Op, CodeGenDAGPatterns &CGP) { + return CGP.getSDNodeInfo(Op).getEnumName(); +} + +static +bool DisablePatternForFastISel(TreePatternNode *N, CodeGenDAGPatterns &CGP) { + bool isStore = !N->isLeaf() && + getOpcodeName(N->getOperator(), CGP) == "ISD::STORE"; + if (!isStore && NodeHasProperty(N, SDNPHasChain, CGP)) + return false; + + bool HasChain = false; + for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) { + TreePatternNode *Child = N->getChild(i); + if (PatternHasProperty(Child, SDNPHasChain, CGP)) { + HasChain = true; + break; + } + } + return HasChain; +} + +//===----------------------------------------------------------------------===// +// Node Transformation emitter implementation. +// +void DAGISelEmitter::EmitNodeTransforms(std::ostream &OS) { + // Walk the pattern fragments, adding them to a map, which sorts them by + // name. + typedef std::map<std::string, CodeGenDAGPatterns::NodeXForm> NXsByNameTy; + NXsByNameTy NXsByName; + + for (CodeGenDAGPatterns::nx_iterator I = CGP.nx_begin(), E = CGP.nx_end(); + I != E; ++I) + NXsByName.insert(std::make_pair(I->first->getName(), I->second)); + + OS << "\n// Node transformations.\n"; + + for (NXsByNameTy::iterator I = NXsByName.begin(), E = NXsByName.end(); + I != E; ++I) { + Record *SDNode = I->second.first; + std::string Code = I->second.second; + + if (Code.empty()) continue; // Empty code? Skip it. + + std::string ClassName = CGP.getSDNodeInfo(SDNode).getSDClassName(); + const char *C2 = ClassName == "SDNode" ? "N" : "inN"; + + OS << "inline SDValue Transform_" << I->first << "(SDNode *" << C2 + << ") {\n"; + if (ClassName != "SDNode") + OS << " " << ClassName << " *N = cast<" << ClassName << ">(inN);\n"; + OS << Code << "\n}\n"; + } +} + +//===----------------------------------------------------------------------===// +// Predicate emitter implementation. +// + +void DAGISelEmitter::EmitPredicateFunctions(std::ostream &OS) { + OS << "\n// Predicate functions.\n"; + + // Walk the pattern fragments, adding them to a map, which sorts them by + // name. + typedef std::map<std::string, std::pair<Record*, TreePattern*> > PFsByNameTy; + PFsByNameTy PFsByName; + + for (CodeGenDAGPatterns::pf_iterator I = CGP.pf_begin(), E = CGP.pf_end(); + I != E; ++I) + PFsByName.insert(std::make_pair(I->first->getName(), *I)); + + + for (PFsByNameTy::iterator I = PFsByName.begin(), E = PFsByName.end(); + I != E; ++I) { + Record *PatFragRecord = I->second.first;// Record that derives from PatFrag. + TreePattern *P = I->second.second; + + // If there is a code init for this fragment, emit the predicate code. + std::string Code = PatFragRecord->getValueAsCode("Predicate"); + if (Code.empty()) continue; + + if (P->getOnlyTree()->isLeaf()) + OS << "inline bool Predicate_" << PatFragRecord->getName() + << "(SDNode *N) {\n"; + else { + std::string ClassName = + CGP.getSDNodeInfo(P->getOnlyTree()->getOperator()).getSDClassName(); + const char *C2 = ClassName == "SDNode" ? "N" : "inN"; + + OS << "inline bool Predicate_" << PatFragRecord->getName() + << "(SDNode *" << C2 << ") {\n"; + if (ClassName != "SDNode") + OS << " " << ClassName << " *N = cast<" << ClassName << ">(inN);\n"; + } + OS << Code << "\n}\n"; + } + + OS << "\n\n"; +} + + +//===----------------------------------------------------------------------===// +// PatternCodeEmitter implementation. +// +class PatternCodeEmitter { +private: + CodeGenDAGPatterns &CGP; + + // Predicates. + std::string PredicateCheck; + // Pattern cost. + unsigned Cost; + // Instruction selector pattern. + TreePatternNode *Pattern; + // Matched instruction. + TreePatternNode *Instruction; + + // Node to name mapping + std::map<std::string, std::string> VariableMap; + // Node to operator mapping + std::map<std::string, Record*> OperatorMap; + // Name of the folded node which produces a flag. + std::pair<std::string, unsigned> FoldedFlag; + // Names of all the folded nodes which produce chains. + std::vector<std::pair<std::string, unsigned> > FoldedChains; + // Original input chain(s). + std::vector<std::pair<std::string, std::string> > OrigChains; + std::set<std::string> Duplicates; + + /// LSI - Load/Store information. + /// Save loads/stores matched by a pattern, and generate a MemOperandSDNode + /// for each memory access. This facilitates the use of AliasAnalysis in + /// the backend. + std::vector<std::string> LSI; + + /// GeneratedCode - This is the buffer that we emit code to. The first int + /// indicates whether this is an exit predicate (something that should be + /// tested, and if true, the match fails) [when 1], or normal code to emit + /// [when 0], or initialization code to emit [when 2]. + std::vector<std::pair<unsigned, std::string> > &GeneratedCode; + /// GeneratedDecl - This is the set of all SDValue declarations needed for + /// the set of patterns for each top-level opcode. + std::set<std::string> &GeneratedDecl; + /// TargetOpcodes - The target specific opcodes used by the resulting + /// instructions. + std::vector<std::string> &TargetOpcodes; + std::vector<std::string> &TargetVTs; + /// OutputIsVariadic - Records whether the instruction output pattern uses + /// variable_ops. This requires that the Emit function be passed an + /// additional argument to indicate where the input varargs operands + /// begin. + bool &OutputIsVariadic; + /// NumInputRootOps - Records the number of operands the root node of the + /// input pattern has. This information is used in the generated code to + /// pass to Emit functions when variable_ops processing is needed. + unsigned &NumInputRootOps; + + std::string ChainName; + unsigned TmpNo; + unsigned OpcNo; + unsigned VTNo; + + void emitCheck(const std::string &S) { + if (!S.empty()) + GeneratedCode.push_back(std::make_pair(1, S)); + } + void emitCode(const std::string &S) { + if (!S.empty()) + GeneratedCode.push_back(std::make_pair(0, S)); + } + void emitInit(const std::string &S) { + if (!S.empty()) + GeneratedCode.push_back(std::make_pair(2, S)); + } + void emitDecl(const std::string &S) { + assert(!S.empty() && "Invalid declaration"); + GeneratedDecl.insert(S); + } + void emitOpcode(const std::string &Opc) { + TargetOpcodes.push_back(Opc); + OpcNo++; + } + void emitVT(const std::string &VT) { + TargetVTs.push_back(VT); + VTNo++; + } +public: + PatternCodeEmitter(CodeGenDAGPatterns &cgp, std::string predcheck, + TreePatternNode *pattern, TreePatternNode *instr, + std::vector<std::pair<unsigned, std::string> > &gc, + std::set<std::string> &gd, + std::vector<std::string> &to, + std::vector<std::string> &tv, + bool &oiv, + unsigned &niro) + : CGP(cgp), PredicateCheck(predcheck), Pattern(pattern), Instruction(instr), + GeneratedCode(gc), GeneratedDecl(gd), + TargetOpcodes(to), TargetVTs(tv), + OutputIsVariadic(oiv), NumInputRootOps(niro), + TmpNo(0), OpcNo(0), VTNo(0) {} + + /// EmitMatchCode - Emit a matcher for N, going to the label for PatternNo + /// if the match fails. At this point, we already know that the opcode for N + /// matches, and the SDNode for the result has the RootName specified name. + void EmitMatchCode(TreePatternNode *N, TreePatternNode *P, + const std::string &RootName, const std::string &ChainSuffix, + bool &FoundChain) { + + // Save loads/stores matched by a pattern. + if (!N->isLeaf() && N->getName().empty()) { + if (NodeHasProperty(N, SDNPMemOperand, CGP)) + LSI.push_back(RootName); + } + + bool isRoot = (P == NULL); + // Emit instruction predicates. Each predicate is just a string for now. + if (isRoot) { + // Record input varargs info. + NumInputRootOps = N->getNumChildren(); + + if (DisablePatternForFastISel(N, CGP)) + emitCheck("OptLevel != CodeGenOpt::None"); + + emitCheck(PredicateCheck); + } + + if (N->isLeaf()) { + if (IntInit *II = dynamic_cast<IntInit*>(N->getLeafValue())) { + emitCheck("cast<ConstantSDNode>(" + RootName + + ")->getSExtValue() == INT64_C(" + + itostr(II->getValue()) + ")"); + return; + } else if (!NodeIsComplexPattern(N)) { + assert(0 && "Cannot match this as a leaf value!"); + abort(); + } + } + + // If this node has a name associated with it, capture it in VariableMap. If + // we already saw this in the pattern, emit code to verify dagness. + if (!N->getName().empty()) { + std::string &VarMapEntry = VariableMap[N->getName()]; + if (VarMapEntry.empty()) { + VarMapEntry = RootName; + } else { + // If we get here, this is a second reference to a specific name. Since + // we already have checked that the first reference is valid, we don't + // have to recursively match it, just check that it's the same as the + // previously named thing. + emitCheck(VarMapEntry + " == " + RootName); + return; + } + + if (!N->isLeaf()) + OperatorMap[N->getName()] = N->getOperator(); + } + + + // Emit code to load the child nodes and match their contents recursively. + unsigned OpNo = 0; + bool NodeHasChain = NodeHasProperty (N, SDNPHasChain, CGP); + bool HasChain = PatternHasProperty(N, SDNPHasChain, CGP); + bool EmittedUseCheck = false; + if (HasChain) { + if (NodeHasChain) + OpNo = 1; + if (!isRoot) { + // Multiple uses of actual result? + emitCheck(RootName + ".hasOneUse()"); + EmittedUseCheck = true; + if (NodeHasChain) { + // If the immediate use can somehow reach this node through another + // path, then can't fold it either or it will create a cycle. + // e.g. In the following diagram, XX can reach ld through YY. If + // ld is folded into XX, then YY is both a predecessor and a successor + // of XX. + // + // [ld] + // ^ ^ + // | | + // / \--- + // / [YY] + // | ^ + // [XX]-------| + bool NeedCheck = P != Pattern; + if (!NeedCheck) { + const SDNodeInfo &PInfo = CGP.getSDNodeInfo(P->getOperator()); + NeedCheck = + P->getOperator() == CGP.get_intrinsic_void_sdnode() || + P->getOperator() == CGP.get_intrinsic_w_chain_sdnode() || + P->getOperator() == CGP.get_intrinsic_wo_chain_sdnode() || + PInfo.getNumOperands() > 1 || + PInfo.hasProperty(SDNPHasChain) || + PInfo.hasProperty(SDNPInFlag) || + PInfo.hasProperty(SDNPOptInFlag); + } + + if (NeedCheck) { + std::string ParentName(RootName.begin(), RootName.end()-1); + emitCheck("IsLegalAndProfitableToFold(" + RootName + + ".getNode(), " + ParentName + ".getNode(), N.getNode())"); + } + } + } + + if (NodeHasChain) { + if (FoundChain) { + emitCheck("(" + ChainName + ".getNode() == " + RootName + ".getNode() || " + "IsChainCompatible(" + ChainName + ".getNode(), " + + RootName + ".getNode()))"); + OrigChains.push_back(std::make_pair(ChainName, RootName)); + } else + FoundChain = true; + ChainName = "Chain" + ChainSuffix; + emitInit("SDValue " + ChainName + " = " + RootName + + ".getOperand(0);"); + } + } + + // Don't fold any node which reads or writes a flag and has multiple uses. + // FIXME: We really need to separate the concepts of flag and "glue". Those + // real flag results, e.g. X86CMP output, can have multiple uses. + // FIXME: If the optional incoming flag does not exist. Then it is ok to + // fold it. + if (!isRoot && + (PatternHasProperty(N, SDNPInFlag, CGP) || + PatternHasProperty(N, SDNPOptInFlag, CGP) || + PatternHasProperty(N, SDNPOutFlag, CGP))) { + if (!EmittedUseCheck) { + // Multiple uses of actual result? + emitCheck(RootName + ".hasOneUse()"); + } + } + + // If there are node predicates for this, emit the calls. + for (unsigned i = 0, e = N->getPredicateFns().size(); i != e; ++i) + emitCheck(N->getPredicateFns()[i] + "(" + RootName + ".getNode())"); + + // If this is an 'and R, 1234' where the operation is AND/OR and the RHS is + // a constant without a predicate fn that has more that one bit set, handle + // this as a special case. This is usually for targets that have special + // handling of certain large constants (e.g. alpha with it's 8/16/32-bit + // handling stuff). Using these instructions is often far more efficient + // than materializing the constant. Unfortunately, both the instcombiner + // and the dag combiner can often infer that bits are dead, and thus drop + // them from the mask in the dag. For example, it might turn 'AND X, 255' + // into 'AND X, 254' if it knows the low bit is set. Emit code that checks + // to handle this. + if (!N->isLeaf() && + (N->getOperator()->getName() == "and" || + N->getOperator()->getName() == "or") && + N->getChild(1)->isLeaf() && + N->getChild(1)->getPredicateFns().empty()) { + if (IntInit *II = dynamic_cast<IntInit*>(N->getChild(1)->getLeafValue())) { + if (!isPowerOf2_32(II->getValue())) { // Don't bother with single bits. + emitInit("SDValue " + RootName + "0" + " = " + + RootName + ".getOperand(" + utostr(0) + ");"); + emitInit("SDValue " + RootName + "1" + " = " + + RootName + ".getOperand(" + utostr(1) + ");"); + + unsigned NTmp = TmpNo++; + emitCode("ConstantSDNode *Tmp" + utostr(NTmp) + + " = dyn_cast<ConstantSDNode>(" + RootName + "1);"); + emitCheck("Tmp" + utostr(NTmp)); + const char *MaskPredicate = N->getOperator()->getName() == "or" + ? "CheckOrMask(" : "CheckAndMask("; + emitCheck(MaskPredicate + RootName + "0, Tmp" + utostr(NTmp) + + ", INT64_C(" + itostr(II->getValue()) + "))"); + + EmitChildMatchCode(N->getChild(0), N, RootName + utostr(0), RootName, + ChainSuffix + utostr(0), FoundChain); + return; + } + } + } + + for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i, ++OpNo) { + emitInit("SDValue " + RootName + utostr(OpNo) + " = " + + RootName + ".getOperand(" +utostr(OpNo) + ");"); + + EmitChildMatchCode(N->getChild(i), N, RootName + utostr(OpNo), RootName, + ChainSuffix + utostr(OpNo), FoundChain); + } + + // Handle cases when root is a complex pattern. + const ComplexPattern *CP; + if (isRoot && N->isLeaf() && (CP = NodeGetComplexPattern(N, CGP))) { + std::string Fn = CP->getSelectFunc(); + unsigned NumOps = CP->getNumOperands(); + for (unsigned i = 0; i < NumOps; ++i) { + emitDecl("CPTmp" + RootName + "_" + utostr(i)); + emitCode("SDValue CPTmp" + RootName + "_" + utostr(i) + ";"); + } + if (CP->hasProperty(SDNPHasChain)) { + emitDecl("CPInChain"); + emitDecl("Chain" + ChainSuffix); + emitCode("SDValue CPInChain;"); + emitCode("SDValue Chain" + ChainSuffix + ";"); + } + + std::string Code = Fn + "(" + RootName + ", " + RootName; + for (unsigned i = 0; i < NumOps; i++) + Code += ", CPTmp" + RootName + "_" + utostr(i); + if (CP->hasProperty(SDNPHasChain)) { + ChainName = "Chain" + ChainSuffix; + Code += ", CPInChain, Chain" + ChainSuffix; + } + emitCheck(Code + ")"); + } + } + + void EmitChildMatchCode(TreePatternNode *Child, TreePatternNode *Parent, + const std::string &RootName, + const std::string &ParentRootName, + const std::string &ChainSuffix, bool &FoundChain) { + if (!Child->isLeaf()) { + // If it's not a leaf, recursively match. + const SDNodeInfo &CInfo = CGP.getSDNodeInfo(Child->getOperator()); + emitCheck(RootName + ".getOpcode() == " + + CInfo.getEnumName()); + EmitMatchCode(Child, Parent, RootName, ChainSuffix, FoundChain); + bool HasChain = false; + if (NodeHasProperty(Child, SDNPHasChain, CGP)) { + HasChain = true; + FoldedChains.push_back(std::make_pair(RootName, CInfo.getNumResults())); + } + if (NodeHasProperty(Child, SDNPOutFlag, CGP)) { + assert(FoldedFlag.first == "" && FoldedFlag.second == 0 && + "Pattern folded multiple nodes which produce flags?"); + FoldedFlag = std::make_pair(RootName, + CInfo.getNumResults() + (unsigned)HasChain); + } + } else { + // If this child has a name associated with it, capture it in VarMap. If + // we already saw this in the pattern, emit code to verify dagness. + if (!Child->getName().empty()) { + std::string &VarMapEntry = VariableMap[Child->getName()]; + if (VarMapEntry.empty()) { + VarMapEntry = RootName; + } else { + // If we get here, this is a second reference to a specific name. + // Since we already have checked that the first reference is valid, + // we don't have to recursively match it, just check that it's the + // same as the previously named thing. + emitCheck(VarMapEntry + " == " + RootName); + Duplicates.insert(RootName); + return; + } + } + + // Handle leaves of various types. + if (DefInit *DI = dynamic_cast<DefInit*>(Child->getLeafValue())) { + Record *LeafRec = DI->getDef(); + if (LeafRec->isSubClassOf("RegisterClass") || + LeafRec->getName() == "ptr_rc") { + // Handle register references. Nothing to do here. + } else if (LeafRec->isSubClassOf("Register")) { + // Handle register references. + } else if (LeafRec->isSubClassOf("ComplexPattern")) { + // Handle complex pattern. + const ComplexPattern *CP = NodeGetComplexPattern(Child, CGP); + std::string Fn = CP->getSelectFunc(); + unsigned NumOps = CP->getNumOperands(); + for (unsigned i = 0; i < NumOps; ++i) { + emitDecl("CPTmp" + RootName + "_" + utostr(i)); + emitCode("SDValue CPTmp" + RootName + "_" + utostr(i) + ";"); + } + if (CP->hasProperty(SDNPHasChain)) { + const SDNodeInfo &PInfo = CGP.getSDNodeInfo(Parent->getOperator()); + FoldedChains.push_back(std::make_pair("CPInChain", + PInfo.getNumResults())); + ChainName = "Chain" + ChainSuffix; + emitDecl("CPInChain"); + emitDecl(ChainName); + emitCode("SDValue CPInChain;"); + emitCode("SDValue " + ChainName + ";"); + } + + std::string Code = Fn + "("; + if (CP->hasAttribute(CPAttrParentAsRoot)) { + Code += ParentRootName + ", "; + } else { + Code += "N, "; + } + if (CP->hasProperty(SDNPHasChain)) { + std::string ParentName(RootName.begin(), RootName.end()-1); + Code += ParentName + ", "; + } + Code += RootName; + for (unsigned i = 0; i < NumOps; i++) + Code += ", CPTmp" + RootName + "_" + utostr(i); + if (CP->hasProperty(SDNPHasChain)) + Code += ", CPInChain, Chain" + ChainSuffix; + emitCheck(Code + ")"); + } else if (LeafRec->getName() == "srcvalue") { + // Place holder for SRCVALUE nodes. Nothing to do here. + } else if (LeafRec->isSubClassOf("ValueType")) { + // Make sure this is the specified value type. + emitCheck("cast<VTSDNode>(" + RootName + + ")->getVT() == MVT::" + LeafRec->getName()); + } else if (LeafRec->isSubClassOf("CondCode")) { + // Make sure this is the specified cond code. + emitCheck("cast<CondCodeSDNode>(" + RootName + + ")->get() == ISD::" + LeafRec->getName()); + } else { +#ifndef NDEBUG + Child->dump(); + cerr << " "; +#endif + assert(0 && "Unknown leaf type!"); + } + + // If there are node predicates for this, emit the calls. + for (unsigned i = 0, e = Child->getPredicateFns().size(); i != e; ++i) + emitCheck(Child->getPredicateFns()[i] + "(" + RootName + + ".getNode())"); + } else if (IntInit *II = + dynamic_cast<IntInit*>(Child->getLeafValue())) { + unsigned NTmp = TmpNo++; + emitCode("ConstantSDNode *Tmp"+ utostr(NTmp) + + " = dyn_cast<ConstantSDNode>("+ + RootName + ");"); + emitCheck("Tmp" + utostr(NTmp)); + unsigned CTmp = TmpNo++; + emitCode("int64_t CN"+ utostr(CTmp) + + " = Tmp" + utostr(NTmp) + "->getSExtValue();"); + emitCheck("CN" + utostr(CTmp) + " == " + "INT64_C(" +itostr(II->getValue()) + ")"); + } else { +#ifndef NDEBUG + Child->dump(); +#endif + assert(0 && "Unknown leaf type!"); + } + } + } + + /// EmitResultCode - Emit the action for a pattern. Now that it has matched + /// we actually have to build a DAG! + std::vector<std::string> + EmitResultCode(TreePatternNode *N, std::vector<Record*> DstRegs, + bool InFlagDecled, bool ResNodeDecled, + bool LikeLeaf = false, bool isRoot = false) { + // List of arguments of getTargetNode() or SelectNodeTo(). + std::vector<std::string> NodeOps; + // This is something selected from the pattern we matched. + if (!N->getName().empty()) { + const std::string &VarName = N->getName(); + std::string Val = VariableMap[VarName]; + bool ModifiedVal = false; + if (Val.empty()) { + cerr << "Variable '" << VarName << " referenced but not defined " + << "and not caught earlier!\n"; + abort(); + } + if (Val[0] == 'T' && Val[1] == 'm' && Val[2] == 'p') { + // Already selected this operand, just return the tmpval. + NodeOps.push_back(Val); + return NodeOps; + } + + const ComplexPattern *CP; + unsigned ResNo = TmpNo++; + if (!N->isLeaf() && N->getOperator()->getName() == "imm") { + assert(N->getExtTypes().size() == 1 && "Multiple types not handled!"); + std::string CastType; + std::string TmpVar = "Tmp" + utostr(ResNo); + switch (N->getTypeNum(0)) { + default: + cerr << "Cannot handle " << getEnumName(N->getTypeNum(0)) + << " type as an immediate constant. Aborting\n"; + abort(); + case MVT::i1: CastType = "bool"; break; + case MVT::i8: CastType = "unsigned char"; break; + case MVT::i16: CastType = "unsigned short"; break; + case MVT::i32: CastType = "unsigned"; break; + case MVT::i64: CastType = "uint64_t"; break; + } + emitCode("SDValue " + TmpVar + + " = CurDAG->getTargetConstant(((" + CastType + + ") cast<ConstantSDNode>(" + Val + ")->getZExtValue()), " + + getEnumName(N->getTypeNum(0)) + ");"); + // Add Tmp<ResNo> to VariableMap, so that we don't multiply select this + // value if used multiple times by this pattern result. + Val = TmpVar; + ModifiedVal = true; + NodeOps.push_back(Val); + } else if (!N->isLeaf() && N->getOperator()->getName() == "fpimm") { + assert(N->getExtTypes().size() == 1 && "Multiple types not handled!"); + std::string TmpVar = "Tmp" + utostr(ResNo); + emitCode("SDValue " + TmpVar + + " = CurDAG->getTargetConstantFP(*cast<ConstantFPSDNode>(" + + Val + ")->getConstantFPValue(), cast<ConstantFPSDNode>(" + + Val + ")->getValueType(0));"); + // Add Tmp<ResNo> to VariableMap, so that we don't multiply select this + // value if used multiple times by this pattern result. + Val = TmpVar; + ModifiedVal = true; + NodeOps.push_back(Val); + } else if (!N->isLeaf() && N->getOperator()->getName() == "texternalsym"){ + Record *Op = OperatorMap[N->getName()]; + // Transform ExternalSymbol to TargetExternalSymbol + if (Op && Op->getName() == "externalsym") { + std::string TmpVar = "Tmp"+utostr(ResNo); + emitCode("SDValue " + TmpVar + " = CurDAG->getTarget" + "ExternalSymbol(cast<ExternalSymbolSDNode>(" + + Val + ")->getSymbol(), " + + getEnumName(N->getTypeNum(0)) + ");"); + // Add Tmp<ResNo> to VariableMap, so that we don't multiply select + // this value if used multiple times by this pattern result. + Val = TmpVar; + ModifiedVal = true; + } + NodeOps.push_back(Val); + } else if (!N->isLeaf() && (N->getOperator()->getName() == "tglobaladdr" + || N->getOperator()->getName() == "tglobaltlsaddr")) { + Record *Op = OperatorMap[N->getName()]; + // Transform GlobalAddress to TargetGlobalAddress + if (Op && (Op->getName() == "globaladdr" || + Op->getName() == "globaltlsaddr")) { + std::string TmpVar = "Tmp" + utostr(ResNo); + emitCode("SDValue " + TmpVar + " = CurDAG->getTarget" + "GlobalAddress(cast<GlobalAddressSDNode>(" + Val + + ")->getGlobal(), " + getEnumName(N->getTypeNum(0)) + + ");"); + // Add Tmp<ResNo> to VariableMap, so that we don't multiply select + // this value if used multiple times by this pattern result. + Val = TmpVar; + ModifiedVal = true; + } + NodeOps.push_back(Val); + } else if (!N->isLeaf() + && (N->getOperator()->getName() == "texternalsym" + || N->getOperator()->getName() == "tconstpool")) { + // Do not rewrite the variable name, since we don't generate a new + // temporary. + NodeOps.push_back(Val); + } else if (N->isLeaf() && (CP = NodeGetComplexPattern(N, CGP))) { + for (unsigned i = 0; i < CP->getNumOperands(); ++i) { + NodeOps.push_back("CPTmp" + Val + "_" + utostr(i)); + } + } else { + // This node, probably wrapped in a SDNodeXForm, behaves like a leaf + // node even if it isn't one. Don't select it. + if (!LikeLeaf) { + if (isRoot && N->isLeaf()) { + emitCode("ReplaceUses(N, " + Val + ");"); + emitCode("return NULL;"); + } + } + NodeOps.push_back(Val); + } + + if (ModifiedVal) { + VariableMap[VarName] = Val; + } + return NodeOps; + } + if (N->isLeaf()) { + // If this is an explicit register reference, handle it. + if (DefInit *DI = dynamic_cast<DefInit*>(N->getLeafValue())) { + unsigned ResNo = TmpNo++; + if (DI->getDef()->isSubClassOf("Register")) { + emitCode("SDValue Tmp" + utostr(ResNo) + " = CurDAG->getRegister(" + + getQualifiedName(DI->getDef()) + ", " + + getEnumName(N->getTypeNum(0)) + ");"); + NodeOps.push_back("Tmp" + utostr(ResNo)); + return NodeOps; + } else if (DI->getDef()->getName() == "zero_reg") { + emitCode("SDValue Tmp" + utostr(ResNo) + + " = CurDAG->getRegister(0, " + + getEnumName(N->getTypeNum(0)) + ");"); + NodeOps.push_back("Tmp" + utostr(ResNo)); + return NodeOps; + } else if (DI->getDef()->isSubClassOf("RegisterClass")) { + // Handle a reference to a register class. This is used + // in COPY_TO_SUBREG instructions. + emitCode("SDValue Tmp" + utostr(ResNo) + + " = CurDAG->getTargetConstant(" + + getQualifiedName(DI->getDef()) + "RegClassID, " + + "MVT::i32);"); + NodeOps.push_back("Tmp" + utostr(ResNo)); + return NodeOps; + } + } else if (IntInit *II = dynamic_cast<IntInit*>(N->getLeafValue())) { + unsigned ResNo = TmpNo++; + assert(N->getExtTypes().size() == 1 && "Multiple types not handled!"); + emitCode("SDValue Tmp" + utostr(ResNo) + + " = CurDAG->getTargetConstant(0x" + itohexstr(II->getValue()) + + "ULL, " + getEnumName(N->getTypeNum(0)) + ");"); + NodeOps.push_back("Tmp" + utostr(ResNo)); + return NodeOps; + } + +#ifndef NDEBUG + N->dump(); +#endif + assert(0 && "Unknown leaf type!"); + return NodeOps; + } + + Record *Op = N->getOperator(); + if (Op->isSubClassOf("Instruction")) { + const CodeGenTarget &CGT = CGP.getTargetInfo(); + CodeGenInstruction &II = CGT.getInstruction(Op->getName()); + const DAGInstruction &Inst = CGP.getInstruction(Op); + const TreePattern *InstPat = Inst.getPattern(); + // FIXME: Assume actual pattern comes before "implicit". + TreePatternNode *InstPatNode = + isRoot ? (InstPat ? InstPat->getTree(0) : Pattern) + : (InstPat ? InstPat->getTree(0) : NULL); + if (InstPatNode && !InstPatNode->isLeaf() && + InstPatNode->getOperator()->getName() == "set") { + InstPatNode = InstPatNode->getChild(InstPatNode->getNumChildren()-1); + } + bool IsVariadic = isRoot && II.isVariadic; + // FIXME: fix how we deal with physical register operands. + bool HasImpInputs = isRoot && Inst.getNumImpOperands() > 0; + bool HasImpResults = isRoot && DstRegs.size() > 0; + bool NodeHasOptInFlag = isRoot && + PatternHasProperty(Pattern, SDNPOptInFlag, CGP); + bool NodeHasInFlag = isRoot && + PatternHasProperty(Pattern, SDNPInFlag, CGP); + bool NodeHasOutFlag = isRoot && + PatternHasProperty(Pattern, SDNPOutFlag, CGP); + bool NodeHasChain = InstPatNode && + PatternHasProperty(InstPatNode, SDNPHasChain, CGP); + bool InputHasChain = isRoot && + NodeHasProperty(Pattern, SDNPHasChain, CGP); + unsigned NumResults = Inst.getNumResults(); + unsigned NumDstRegs = HasImpResults ? DstRegs.size() : 0; + + // Record output varargs info. + OutputIsVariadic = IsVariadic; + + if (NodeHasOptInFlag) { + emitCode("bool HasInFlag = " + "(N.getOperand(N.getNumOperands()-1).getValueType() == MVT::Flag);"); + } + if (IsVariadic) + emitCode("SmallVector<SDValue, 8> Ops" + utostr(OpcNo) + ";"); + + // How many results is this pattern expected to produce? + unsigned NumPatResults = 0; + for (unsigned i = 0, e = Pattern->getExtTypes().size(); i != e; i++) { + MVT::SimpleValueType VT = Pattern->getTypeNum(i); + if (VT != MVT::isVoid && VT != MVT::Flag) + NumPatResults++; + } + + if (OrigChains.size() > 0) { + // The original input chain is being ignored. If it is not just + // pointing to the op that's being folded, we should create a + // TokenFactor with it and the chain of the folded op as the new chain. + // We could potentially be doing multiple levels of folding, in that + // case, the TokenFactor can have more operands. + emitCode("SmallVector<SDValue, 8> InChains;"); + for (unsigned i = 0, e = OrigChains.size(); i < e; ++i) { + emitCode("if (" + OrigChains[i].first + ".getNode() != " + + OrigChains[i].second + ".getNode()) {"); + emitCode(" InChains.push_back(" + OrigChains[i].first + ");"); + emitCode("}"); + } + emitCode("InChains.push_back(" + ChainName + ");"); + emitCode(ChainName + " = CurDAG->getNode(ISD::TokenFactor, " + "N.getDebugLoc(), MVT::Other, " + "&InChains[0], InChains.size());"); + if (GenDebug) { + emitCode("CurDAG->setSubgraphColor(" + ChainName +".getNode(), \"yellow\");"); + emitCode("CurDAG->setSubgraphColor(" + ChainName +".getNode(), \"black\");"); + } + } + + // Loop over all of the operands of the instruction pattern, emitting code + // to fill them all in. The node 'N' usually has number children equal to + // the number of input operands of the instruction. However, in cases + // where there are predicate operands for an instruction, we need to fill + // in the 'execute always' values. Match up the node operands to the + // instruction operands to do this. + std::vector<std::string> AllOps; + for (unsigned ChildNo = 0, InstOpNo = NumResults; + InstOpNo != II.OperandList.size(); ++InstOpNo) { + std::vector<std::string> Ops; + + // Determine what to emit for this operand. + Record *OperandNode = II.OperandList[InstOpNo].Rec; + if ((OperandNode->isSubClassOf("PredicateOperand") || + OperandNode->isSubClassOf("OptionalDefOperand")) && + !CGP.getDefaultOperand(OperandNode).DefaultOps.empty()) { + // This is a predicate or optional def operand; emit the + // 'default ops' operands. + const DAGDefaultOperand &DefaultOp = + CGP.getDefaultOperand(II.OperandList[InstOpNo].Rec); + for (unsigned i = 0, e = DefaultOp.DefaultOps.size(); i != e; ++i) { + Ops = EmitResultCode(DefaultOp.DefaultOps[i], DstRegs, + InFlagDecled, ResNodeDecled); + AllOps.insert(AllOps.end(), Ops.begin(), Ops.end()); + } + } else { + // Otherwise this is a normal operand or a predicate operand without + // 'execute always'; emit it. + Ops = EmitResultCode(N->getChild(ChildNo), DstRegs, + InFlagDecled, ResNodeDecled); + AllOps.insert(AllOps.end(), Ops.begin(), Ops.end()); + ++ChildNo; + } + } + + // Emit all the chain and CopyToReg stuff. + bool ChainEmitted = NodeHasChain; + if (NodeHasInFlag || HasImpInputs) + EmitInFlagSelectCode(Pattern, "N", ChainEmitted, + InFlagDecled, ResNodeDecled, true); + if (NodeHasOptInFlag || NodeHasInFlag || HasImpInputs) { + if (!InFlagDecled) { + emitCode("SDValue InFlag(0, 0);"); + InFlagDecled = true; + } + if (NodeHasOptInFlag) { + emitCode("if (HasInFlag) {"); + emitCode(" InFlag = N.getOperand(N.getNumOperands()-1);"); + emitCode("}"); + } + } + + unsigned ResNo = TmpNo++; + + unsigned OpsNo = OpcNo; + std::string CodePrefix; + bool ChainAssignmentNeeded = NodeHasChain && !isRoot; + std::deque<std::string> After; + std::string NodeName; + if (!isRoot) { + NodeName = "Tmp" + utostr(ResNo); + CodePrefix = "SDValue " + NodeName + "("; + } else { + NodeName = "ResNode"; + if (!ResNodeDecled) { + CodePrefix = "SDNode *" + NodeName + " = "; + ResNodeDecled = true; + } else + CodePrefix = NodeName + " = "; + } + + std::string Code = "Opc" + utostr(OpcNo); + + if (!isRoot || (InputHasChain && !NodeHasChain)) + // For call to "getTargetNode()". + Code += ", N.getDebugLoc()"; + + emitOpcode(II.Namespace + "::" + II.TheDef->getName()); + + // Output order: results, chain, flags + // Result types. + if (NumResults > 0 && N->getTypeNum(0) != MVT::isVoid) { + Code += ", VT" + utostr(VTNo); + emitVT(getEnumName(N->getTypeNum(0))); + } + // Add types for implicit results in physical registers, scheduler will + // care of adding copyfromreg nodes. + for (unsigned i = 0; i < NumDstRegs; i++) { + Record *RR = DstRegs[i]; + if (RR->isSubClassOf("Register")) { + MVT::SimpleValueType RVT = getRegisterValueType(RR, CGT); + Code += ", " + getEnumName(RVT); + } + } + if (NodeHasChain) + Code += ", MVT::Other"; + if (NodeHasOutFlag) + Code += ", MVT::Flag"; + + // Inputs. + if (IsVariadic) { + for (unsigned i = 0, e = AllOps.size(); i != e; ++i) + emitCode("Ops" + utostr(OpsNo) + ".push_back(" + AllOps[i] + ");"); + AllOps.clear(); + + // Figure out whether any operands at the end of the op list are not + // part of the variable section. + std::string EndAdjust; + if (NodeHasInFlag || HasImpInputs) + EndAdjust = "-1"; // Always has one flag. + else if (NodeHasOptInFlag) + EndAdjust = "-(HasInFlag?1:0)"; // May have a flag. + + emitCode("for (unsigned i = NumInputRootOps + " + utostr(NodeHasChain) + + ", e = N.getNumOperands()" + EndAdjust + "; i != e; ++i) {"); + + emitCode(" Ops" + utostr(OpsNo) + ".push_back(N.getOperand(i));"); + emitCode("}"); + } + + // Generate MemOperandSDNodes nodes for each memory accesses covered by + // this pattern. + if (II.mayLoad | II.mayStore) { + std::vector<std::string>::const_iterator mi, mie; + for (mi = LSI.begin(), mie = LSI.end(); mi != mie; ++mi) { + std::string LSIName = "LSI_" + *mi; + emitCode("SDValue " + LSIName + " = " + "CurDAG->getMemOperand(cast<MemSDNode>(" + + *mi + ")->getMemOperand());"); + if (GenDebug) { + emitCode("CurDAG->setSubgraphColor(" + LSIName +".getNode(), \"yellow\");"); + emitCode("CurDAG->setSubgraphColor(" + LSIName +".getNode(), \"black\");"); + } + if (IsVariadic) + emitCode("Ops" + utostr(OpsNo) + ".push_back(" + LSIName + ");"); + else + AllOps.push_back(LSIName); + } + } + + if (NodeHasChain) { + if (IsVariadic) + emitCode("Ops" + utostr(OpsNo) + ".push_back(" + ChainName + ");"); + else + AllOps.push_back(ChainName); + } + + if (IsVariadic) { + if (NodeHasInFlag || HasImpInputs) + emitCode("Ops" + utostr(OpsNo) + ".push_back(InFlag);"); + else if (NodeHasOptInFlag) { + emitCode("if (HasInFlag)"); + emitCode(" Ops" + utostr(OpsNo) + ".push_back(InFlag);"); + } + Code += ", &Ops" + utostr(OpsNo) + "[0], Ops" + utostr(OpsNo) + + ".size()"; + } else if (NodeHasInFlag || NodeHasOptInFlag || HasImpInputs) + AllOps.push_back("InFlag"); + + unsigned NumOps = AllOps.size(); + if (NumOps) { + if (!NodeHasOptInFlag && NumOps < 4) { + for (unsigned i = 0; i != NumOps; ++i) + Code += ", " + AllOps[i]; + } else { + std::string OpsCode = "SDValue Ops" + utostr(OpsNo) + "[] = { "; + for (unsigned i = 0; i != NumOps; ++i) { + OpsCode += AllOps[i]; + if (i != NumOps-1) + OpsCode += ", "; + } + emitCode(OpsCode + " };"); + Code += ", Ops" + utostr(OpsNo) + ", "; + if (NodeHasOptInFlag) { + Code += "HasInFlag ? "; + Code += utostr(NumOps) + " : " + utostr(NumOps-1); + } else + Code += utostr(NumOps); + } + } + + if (!isRoot) + Code += "), 0"; + + std::vector<std::string> ReplaceFroms; + std::vector<std::string> ReplaceTos; + if (!isRoot) { + NodeOps.push_back("Tmp" + utostr(ResNo)); + } else { + + if (NodeHasOutFlag) { + if (!InFlagDecled) { + After.push_back("SDValue InFlag(ResNode, " + + utostr(NumResults+NumDstRegs+(unsigned)NodeHasChain) + + ");"); + InFlagDecled = true; + } else + After.push_back("InFlag = SDValue(ResNode, " + + utostr(NumResults+NumDstRegs+(unsigned)NodeHasChain) + + ");"); + } + + for (unsigned j = 0, e = FoldedChains.size(); j < e; j++) { + ReplaceFroms.push_back("SDValue(" + + FoldedChains[j].first + ".getNode(), " + + utostr(FoldedChains[j].second) + + ")"); + ReplaceTos.push_back("SDValue(ResNode, " + + utostr(NumResults+NumDstRegs) + ")"); + } + + if (NodeHasOutFlag) { + if (FoldedFlag.first != "") { + ReplaceFroms.push_back("SDValue(" + FoldedFlag.first + ".getNode(), " + + utostr(FoldedFlag.second) + ")"); + ReplaceTos.push_back("InFlag"); + } else { + assert(NodeHasProperty(Pattern, SDNPOutFlag, CGP)); + ReplaceFroms.push_back("SDValue(N.getNode(), " + + utostr(NumPatResults + (unsigned)InputHasChain) + + ")"); + ReplaceTos.push_back("InFlag"); + } + } + + if (!ReplaceFroms.empty() && InputHasChain) { + ReplaceFroms.push_back("SDValue(N.getNode(), " + + utostr(NumPatResults) + ")"); + ReplaceTos.push_back("SDValue(" + ChainName + ".getNode(), " + + ChainName + ".getResNo()" + ")"); + ChainAssignmentNeeded |= NodeHasChain; + } + + // User does not expect the instruction would produce a chain! + if ((!InputHasChain && NodeHasChain) && NodeHasOutFlag) { + ; + } else if (InputHasChain && !NodeHasChain) { + // One of the inner node produces a chain. + if (NodeHasOutFlag) { + ReplaceFroms.push_back("SDValue(N.getNode(), " + + utostr(NumPatResults+1) + + ")"); + ReplaceTos.push_back("SDValue(ResNode, N.getResNo()-1)"); + } + ReplaceFroms.push_back("SDValue(N.getNode(), " + + utostr(NumPatResults) + ")"); + ReplaceTos.push_back(ChainName); + } + } + + if (ChainAssignmentNeeded) { + // Remember which op produces the chain. + std::string ChainAssign; + if (!isRoot) + ChainAssign = ChainName + " = SDValue(" + NodeName + + ".getNode(), " + utostr(NumResults+NumDstRegs) + ");"; + else + ChainAssign = ChainName + " = SDValue(" + NodeName + + ", " + utostr(NumResults+NumDstRegs) + ");"; + + After.push_front(ChainAssign); + } + + if (ReplaceFroms.size() == 1) { + After.push_back("ReplaceUses(" + ReplaceFroms[0] + ", " + + ReplaceTos[0] + ");"); + } else if (!ReplaceFroms.empty()) { + After.push_back("const SDValue Froms[] = {"); + for (unsigned i = 0, e = ReplaceFroms.size(); i != e; ++i) + After.push_back(" " + ReplaceFroms[i] + (i + 1 != e ? "," : "")); + After.push_back("};"); + After.push_back("const SDValue Tos[] = {"); + for (unsigned i = 0, e = ReplaceFroms.size(); i != e; ++i) + After.push_back(" " + ReplaceTos[i] + (i + 1 != e ? "," : "")); + After.push_back("};"); + After.push_back("ReplaceUses(Froms, Tos, " + + itostr(ReplaceFroms.size()) + ");"); + } + + // We prefer to use SelectNodeTo since it avoids allocation when + // possible and it avoids CSE map recalculation for the node's + // users, however it's tricky to use in a non-root context. + // + // We also don't use if the pattern replacement is being used to + // jettison a chain result, since morphing the node in place + // would leave users of the chain dangling. + // + if (!isRoot || (InputHasChain && !NodeHasChain)) { + Code = "CurDAG->getTargetNode(" + Code; + } else { + Code = "CurDAG->SelectNodeTo(N.getNode(), " + Code; + } + if (isRoot) { + if (After.empty()) + CodePrefix = "return "; + else + After.push_back("return ResNode;"); + } + + emitCode(CodePrefix + Code + ");"); + + if (GenDebug) { + if (!isRoot) { + emitCode("CurDAG->setSubgraphColor(" + NodeName +".getNode(), \"yellow\");"); + emitCode("CurDAG->setSubgraphColor(" + NodeName +".getNode(), \"black\");"); + } + else { + emitCode("CurDAG->setSubgraphColor(" + NodeName +", \"yellow\");"); + emitCode("CurDAG->setSubgraphColor(" + NodeName +", \"black\");"); + } + } + + for (unsigned i = 0, e = After.size(); i != e; ++i) + emitCode(After[i]); + + return NodeOps; + } + if (Op->isSubClassOf("SDNodeXForm")) { + assert(N->getNumChildren() == 1 && "node xform should have one child!"); + // PatLeaf node - the operand may or may not be a leaf node. But it should + // behave like one. + std::vector<std::string> Ops = + EmitResultCode(N->getChild(0), DstRegs, InFlagDecled, + ResNodeDecled, true); + unsigned ResNo = TmpNo++; + emitCode("SDValue Tmp" + utostr(ResNo) + " = Transform_" + Op->getName() + + "(" + Ops.back() + ".getNode());"); + NodeOps.push_back("Tmp" + utostr(ResNo)); + if (isRoot) + emitCode("return Tmp" + utostr(ResNo) + ".getNode();"); + return NodeOps; + } + + N->dump(); + cerr << "\n"; + throw std::string("Unknown node in result pattern!"); + } + + /// InsertOneTypeCheck - Insert a type-check for an unresolved type in 'Pat' + /// and add it to the tree. 'Pat' and 'Other' are isomorphic trees except that + /// 'Pat' may be missing types. If we find an unresolved type to add a check + /// for, this returns true otherwise false if Pat has all types. + bool InsertOneTypeCheck(TreePatternNode *Pat, TreePatternNode *Other, + const std::string &Prefix, bool isRoot = false) { + // Did we find one? + if (Pat->getExtTypes() != Other->getExtTypes()) { + // Move a type over from 'other' to 'pat'. + Pat->setTypes(Other->getExtTypes()); + // The top level node type is checked outside of the select function. + if (!isRoot) + emitCheck(Prefix + ".getNode()->getValueType(0) == " + + getName(Pat->getTypeNum(0))); + return true; + } + + unsigned OpNo = + (unsigned) NodeHasProperty(Pat, SDNPHasChain, CGP); + for (unsigned i = 0, e = Pat->getNumChildren(); i != e; ++i, ++OpNo) + if (InsertOneTypeCheck(Pat->getChild(i), Other->getChild(i), + Prefix + utostr(OpNo))) + return true; + return false; + } + +private: + /// EmitInFlagSelectCode - Emit the flag operands for the DAG that is + /// being built. + void EmitInFlagSelectCode(TreePatternNode *N, const std::string &RootName, + bool &ChainEmitted, bool &InFlagDecled, + bool &ResNodeDecled, bool isRoot = false) { + const CodeGenTarget &T = CGP.getTargetInfo(); + unsigned OpNo = + (unsigned) NodeHasProperty(N, SDNPHasChain, CGP); + bool HasInFlag = NodeHasProperty(N, SDNPInFlag, CGP); + for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i, ++OpNo) { + TreePatternNode *Child = N->getChild(i); + if (!Child->isLeaf()) { + EmitInFlagSelectCode(Child, RootName + utostr(OpNo), ChainEmitted, + InFlagDecled, ResNodeDecled); + } else { + if (DefInit *DI = dynamic_cast<DefInit*>(Child->getLeafValue())) { + if (!Child->getName().empty()) { + std::string Name = RootName + utostr(OpNo); + if (Duplicates.find(Name) != Duplicates.end()) + // A duplicate! Do not emit a copy for this node. + continue; + } + + Record *RR = DI->getDef(); + if (RR->isSubClassOf("Register")) { + MVT::SimpleValueType RVT = getRegisterValueType(RR, T); + if (RVT == MVT::Flag) { + if (!InFlagDecled) { + emitCode("SDValue InFlag = " + RootName + utostr(OpNo) + ";"); + InFlagDecled = true; + } else + emitCode("InFlag = " + RootName + utostr(OpNo) + ";"); + } else { + if (!ChainEmitted) { + emitCode("SDValue Chain = CurDAG->getEntryNode();"); + ChainName = "Chain"; + ChainEmitted = true; + } + if (!InFlagDecled) { + emitCode("SDValue InFlag(0, 0);"); + InFlagDecled = true; + } + std::string Decl = (!ResNodeDecled) ? "SDNode *" : ""; + emitCode(Decl + "ResNode = CurDAG->getCopyToReg(" + ChainName + + ", " + RootName + ".getDebugLoc()" + + ", " + getQualifiedName(RR) + + ", " + RootName + utostr(OpNo) + ", InFlag).getNode();"); + ResNodeDecled = true; + emitCode(ChainName + " = SDValue(ResNode, 0);"); + emitCode("InFlag = SDValue(ResNode, 1);"); + } + } + } + } + } + + if (HasInFlag) { + if (!InFlagDecled) { + emitCode("SDValue InFlag = " + RootName + + ".getOperand(" + utostr(OpNo) + ");"); + InFlagDecled = true; + } else + emitCode("InFlag = " + RootName + + ".getOperand(" + utostr(OpNo) + ");"); + } + } +}; + +/// EmitCodeForPattern - Given a pattern to match, emit code to the specified +/// stream to match the pattern, and generate the code for the match if it +/// succeeds. Returns true if the pattern is not guaranteed to match. +void DAGISelEmitter::GenerateCodeForPattern(const PatternToMatch &Pattern, + std::vector<std::pair<unsigned, std::string> > &GeneratedCode, + std::set<std::string> &GeneratedDecl, + std::vector<std::string> &TargetOpcodes, + std::vector<std::string> &TargetVTs, + bool &OutputIsVariadic, + unsigned &NumInputRootOps) { + OutputIsVariadic = false; + NumInputRootOps = 0; + + PatternCodeEmitter Emitter(CGP, Pattern.getPredicateCheck(), + Pattern.getSrcPattern(), Pattern.getDstPattern(), + GeneratedCode, GeneratedDecl, + TargetOpcodes, TargetVTs, + OutputIsVariadic, NumInputRootOps); + + // Emit the matcher, capturing named arguments in VariableMap. + bool FoundChain = false; + Emitter.EmitMatchCode(Pattern.getSrcPattern(), NULL, "N", "", FoundChain); + + // TP - Get *SOME* tree pattern, we don't care which. + TreePattern &TP = *CGP.pf_begin()->second; + + // At this point, we know that we structurally match the pattern, but the + // types of the nodes may not match. Figure out the fewest number of type + // comparisons we need to emit. For example, if there is only one integer + // type supported by a target, there should be no type comparisons at all for + // integer patterns! + // + // To figure out the fewest number of type checks needed, clone the pattern, + // remove the types, then perform type inference on the pattern as a whole. + // If there are unresolved types, emit an explicit check for those types, + // apply the type to the tree, then rerun type inference. Iterate until all + // types are resolved. + // + TreePatternNode *Pat = Pattern.getSrcPattern()->clone(); + RemoveAllTypes(Pat); + + do { + // Resolve/propagate as many types as possible. + try { + bool MadeChange = true; + while (MadeChange) + MadeChange = Pat->ApplyTypeConstraints(TP, + true/*Ignore reg constraints*/); + } catch (...) { + assert(0 && "Error: could not find consistent types for something we" + " already decided was ok!"); + abort(); + } + + // Insert a check for an unresolved type and add it to the tree. If we find + // an unresolved type to add a check for, this returns true and we iterate, + // otherwise we are done. + } while (Emitter.InsertOneTypeCheck(Pat, Pattern.getSrcPattern(), "N", true)); + + Emitter.EmitResultCode(Pattern.getDstPattern(), Pattern.getDstRegs(), + false, false, false, true); + delete Pat; +} + +/// EraseCodeLine - Erase one code line from all of the patterns. If removing +/// a line causes any of them to be empty, remove them and return true when +/// done. +static bool EraseCodeLine(std::vector<std::pair<const PatternToMatch*, + std::vector<std::pair<unsigned, std::string> > > > + &Patterns) { + bool ErasedPatterns = false; + for (unsigned i = 0, e = Patterns.size(); i != e; ++i) { + Patterns[i].second.pop_back(); + if (Patterns[i].second.empty()) { + Patterns.erase(Patterns.begin()+i); + --i; --e; + ErasedPatterns = true; + } + } + return ErasedPatterns; +} + +/// EmitPatterns - Emit code for at least one pattern, but try to group common +/// code together between the patterns. +void DAGISelEmitter::EmitPatterns(std::vector<std::pair<const PatternToMatch*, + std::vector<std::pair<unsigned, std::string> > > > + &Patterns, unsigned Indent, + std::ostream &OS) { + typedef std::pair<unsigned, std::string> CodeLine; + typedef std::vector<CodeLine> CodeList; + typedef std::vector<std::pair<const PatternToMatch*, CodeList> > PatternList; + + if (Patterns.empty()) return; + + // Figure out how many patterns share the next code line. Explicitly copy + // FirstCodeLine so that we don't invalidate a reference when changing + // Patterns. + const CodeLine FirstCodeLine = Patterns.back().second.back(); + unsigned LastMatch = Patterns.size()-1; + while (LastMatch != 0 && Patterns[LastMatch-1].second.back() == FirstCodeLine) + --LastMatch; + + // If not all patterns share this line, split the list into two pieces. The + // first chunk will use this line, the second chunk won't. + if (LastMatch != 0) { + PatternList Shared(Patterns.begin()+LastMatch, Patterns.end()); + PatternList Other(Patterns.begin(), Patterns.begin()+LastMatch); + + // FIXME: Emit braces? + if (Shared.size() == 1) { + const PatternToMatch &Pattern = *Shared.back().first; + OS << "\n" << std::string(Indent, ' ') << "// Pattern: "; + Pattern.getSrcPattern()->print(OS); + OS << "\n" << std::string(Indent, ' ') << "// Emits: "; + Pattern.getDstPattern()->print(OS); + OS << "\n"; + unsigned AddedComplexity = Pattern.getAddedComplexity(); + OS << std::string(Indent, ' ') << "// Pattern complexity = " + << getPatternSize(Pattern.getSrcPattern(), CGP) + AddedComplexity + << " cost = " + << getResultPatternCost(Pattern.getDstPattern(), CGP) + << " size = " + << getResultPatternSize(Pattern.getDstPattern(), CGP) << "\n"; + } + if (FirstCodeLine.first != 1) { + OS << std::string(Indent, ' ') << "{\n"; + Indent += 2; + } + EmitPatterns(Shared, Indent, OS); + if (FirstCodeLine.first != 1) { + Indent -= 2; + OS << std::string(Indent, ' ') << "}\n"; + } + + if (Other.size() == 1) { + const PatternToMatch &Pattern = *Other.back().first; + OS << "\n" << std::string(Indent, ' ') << "// Pattern: "; + Pattern.getSrcPattern()->print(OS); + OS << "\n" << std::string(Indent, ' ') << "// Emits: "; + Pattern.getDstPattern()->print(OS); + OS << "\n"; + unsigned AddedComplexity = Pattern.getAddedComplexity(); + OS << std::string(Indent, ' ') << "// Pattern complexity = " + << getPatternSize(Pattern.getSrcPattern(), CGP) + AddedComplexity + << " cost = " + << getResultPatternCost(Pattern.getDstPattern(), CGP) + << " size = " + << getResultPatternSize(Pattern.getDstPattern(), CGP) << "\n"; + } + EmitPatterns(Other, Indent, OS); + return; + } + + // Remove this code from all of the patterns that share it. + bool ErasedPatterns = EraseCodeLine(Patterns); + + bool isPredicate = FirstCodeLine.first == 1; + + // Otherwise, every pattern in the list has this line. Emit it. + if (!isPredicate) { + // Normal code. + OS << std::string(Indent, ' ') << FirstCodeLine.second << "\n"; + } else { + OS << std::string(Indent, ' ') << "if (" << FirstCodeLine.second; + + // If the next code line is another predicate, and if all of the pattern + // in this group share the same next line, emit it inline now. Do this + // until we run out of common predicates. + while (!ErasedPatterns && Patterns.back().second.back().first == 1) { + // Check that all of the patterns in Patterns end with the same predicate. + bool AllEndWithSamePredicate = true; + for (unsigned i = 0, e = Patterns.size(); i != e; ++i) + if (Patterns[i].second.back() != Patterns.back().second.back()) { + AllEndWithSamePredicate = false; + break; + } + // If all of the predicates aren't the same, we can't share them. + if (!AllEndWithSamePredicate) break; + + // Otherwise we can. Emit it shared now. + OS << " &&\n" << std::string(Indent+4, ' ') + << Patterns.back().second.back().second; + ErasedPatterns = EraseCodeLine(Patterns); + } + + OS << ") {\n"; + Indent += 2; + } + + EmitPatterns(Patterns, Indent, OS); + + if (isPredicate) + OS << std::string(Indent-2, ' ') << "}\n"; +} + +static std::string getLegalCName(std::string OpName) { + std::string::size_type pos = OpName.find("::"); + if (pos != std::string::npos) + OpName.replace(pos, 2, "_"); + return OpName; +} + +void DAGISelEmitter::EmitInstructionSelector(std::ostream &OS) { + const CodeGenTarget &Target = CGP.getTargetInfo(); + + // Get the namespace to insert instructions into. + std::string InstNS = Target.getInstNamespace(); + if (!InstNS.empty()) InstNS += "::"; + + // Group the patterns by their top-level opcodes. + std::map<std::string, std::vector<const PatternToMatch*> > PatternsByOpcode; + // All unique target node emission functions. + std::map<std::string, unsigned> EmitFunctions; + for (CodeGenDAGPatterns::ptm_iterator I = CGP.ptm_begin(), + E = CGP.ptm_end(); I != E; ++I) { + const PatternToMatch &Pattern = *I; + + TreePatternNode *Node = Pattern.getSrcPattern(); + if (!Node->isLeaf()) { + PatternsByOpcode[getOpcodeName(Node->getOperator(), CGP)]. + push_back(&Pattern); + } else { + const ComplexPattern *CP; + if (dynamic_cast<IntInit*>(Node->getLeafValue())) { + PatternsByOpcode[getOpcodeName(CGP.getSDNodeNamed("imm"), CGP)]. + push_back(&Pattern); + } else if ((CP = NodeGetComplexPattern(Node, CGP))) { + std::vector<Record*> OpNodes = CP->getRootNodes(); + for (unsigned j = 0, e = OpNodes.size(); j != e; j++) { + PatternsByOpcode[getOpcodeName(OpNodes[j], CGP)] + .insert(PatternsByOpcode[getOpcodeName(OpNodes[j], CGP)].begin(), + &Pattern); + } + } else { + cerr << "Unrecognized opcode '"; + Node->dump(); + cerr << "' on tree pattern '"; + cerr << Pattern.getDstPattern()->getOperator()->getName() << "'!\n"; + exit(1); + } + } + } + + // For each opcode, there might be multiple select functions, one per + // ValueType of the node (or its first operand if it doesn't produce a + // non-chain result. + std::map<std::string, std::vector<std::string> > OpcodeVTMap; + + // Emit one Select_* method for each top-level opcode. We do this instead of + // emitting one giant switch statement to support compilers where this will + // result in the recursive functions taking less stack space. + for (std::map<std::string, std::vector<const PatternToMatch*> >::iterator + PBOI = PatternsByOpcode.begin(), E = PatternsByOpcode.end(); + PBOI != E; ++PBOI) { + const std::string &OpName = PBOI->first; + std::vector<const PatternToMatch*> &PatternsOfOp = PBOI->second; + assert(!PatternsOfOp.empty() && "No patterns but map has entry?"); + + // Split them into groups by type. + std::map<MVT::SimpleValueType, + std::vector<const PatternToMatch*> > PatternsByType; + for (unsigned i = 0, e = PatternsOfOp.size(); i != e; ++i) { + const PatternToMatch *Pat = PatternsOfOp[i]; + TreePatternNode *SrcPat = Pat->getSrcPattern(); + PatternsByType[SrcPat->getTypeNum(0)].push_back(Pat); + } + + for (std::map<MVT::SimpleValueType, + std::vector<const PatternToMatch*> >::iterator + II = PatternsByType.begin(), EE = PatternsByType.end(); II != EE; + ++II) { + MVT::SimpleValueType OpVT = II->first; + std::vector<const PatternToMatch*> &Patterns = II->second; + typedef std::pair<unsigned, std::string> CodeLine; + typedef std::vector<CodeLine> CodeList; + typedef CodeList::iterator CodeListI; + + std::vector<std::pair<const PatternToMatch*, CodeList> > CodeForPatterns; + std::vector<std::vector<std::string> > PatternOpcodes; + std::vector<std::vector<std::string> > PatternVTs; + std::vector<std::set<std::string> > PatternDecls; + std::vector<bool> OutputIsVariadicFlags; + std::vector<unsigned> NumInputRootOpsCounts; + for (unsigned i = 0, e = Patterns.size(); i != e; ++i) { + CodeList GeneratedCode; + std::set<std::string> GeneratedDecl; + std::vector<std::string> TargetOpcodes; + std::vector<std::string> TargetVTs; + bool OutputIsVariadic; + unsigned NumInputRootOps; + GenerateCodeForPattern(*Patterns[i], GeneratedCode, GeneratedDecl, + TargetOpcodes, TargetVTs, + OutputIsVariadic, NumInputRootOps); + CodeForPatterns.push_back(std::make_pair(Patterns[i], GeneratedCode)); + PatternDecls.push_back(GeneratedDecl); + PatternOpcodes.push_back(TargetOpcodes); + PatternVTs.push_back(TargetVTs); + OutputIsVariadicFlags.push_back(OutputIsVariadic); + NumInputRootOpsCounts.push_back(NumInputRootOps); + } + + // Factor target node emission code (emitted by EmitResultCode) into + // separate functions. Uniquing and share them among all instruction + // selection routines. + for (unsigned i = 0, e = CodeForPatterns.size(); i != e; ++i) { + CodeList &GeneratedCode = CodeForPatterns[i].second; + std::vector<std::string> &TargetOpcodes = PatternOpcodes[i]; + std::vector<std::string> &TargetVTs = PatternVTs[i]; + std::set<std::string> Decls = PatternDecls[i]; + bool OutputIsVariadic = OutputIsVariadicFlags[i]; + unsigned NumInputRootOps = NumInputRootOpsCounts[i]; + std::vector<std::string> AddedInits; + int CodeSize = (int)GeneratedCode.size(); + int LastPred = -1; + for (int j = CodeSize-1; j >= 0; --j) { + if (LastPred == -1 && GeneratedCode[j].first == 1) + LastPred = j; + else if (LastPred != -1 && GeneratedCode[j].first == 2) + AddedInits.push_back(GeneratedCode[j].second); + } + + std::string CalleeCode = "(const SDValue &N"; + std::string CallerCode = "(N"; + for (unsigned j = 0, e = TargetOpcodes.size(); j != e; ++j) { + CalleeCode += ", unsigned Opc" + utostr(j); + CallerCode += ", " + TargetOpcodes[j]; + } + for (unsigned j = 0, e = TargetVTs.size(); j != e; ++j) { + CalleeCode += ", MVT VT" + utostr(j); + CallerCode += ", " + TargetVTs[j]; + } + for (std::set<std::string>::iterator + I = Decls.begin(), E = Decls.end(); I != E; ++I) { + std::string Name = *I; + CalleeCode += ", SDValue &" + Name; + CallerCode += ", " + Name; + } + + if (OutputIsVariadic) { + CalleeCode += ", unsigned NumInputRootOps"; + CallerCode += ", " + utostr(NumInputRootOps); + } + + CallerCode += ");"; + CalleeCode += ") "; + // Prevent emission routines from being inlined to reduce selection + // routines stack frame sizes. + CalleeCode += "DISABLE_INLINE "; + CalleeCode += "{\n"; + + for (std::vector<std::string>::const_reverse_iterator + I = AddedInits.rbegin(), E = AddedInits.rend(); I != E; ++I) + CalleeCode += " " + *I + "\n"; + + for (int j = LastPred+1; j < CodeSize; ++j) + CalleeCode += " " + GeneratedCode[j].second + "\n"; + for (int j = LastPred+1; j < CodeSize; ++j) + GeneratedCode.pop_back(); + CalleeCode += "}\n"; + + // Uniquing the emission routines. + unsigned EmitFuncNum; + std::map<std::string, unsigned>::iterator EFI = + EmitFunctions.find(CalleeCode); + if (EFI != EmitFunctions.end()) { + EmitFuncNum = EFI->second; + } else { + EmitFuncNum = EmitFunctions.size(); + EmitFunctions.insert(std::make_pair(CalleeCode, EmitFuncNum)); + OS << "SDNode *Emit_" << utostr(EmitFuncNum) << CalleeCode; + } + + // Replace the emission code within selection routines with calls to the + // emission functions. + if (GenDebug) { + GeneratedCode.push_back(std::make_pair(0, "CurDAG->setSubgraphColor(N.getNode(), \"red\");")); + } + CallerCode = "SDNode *Result = Emit_" + utostr(EmitFuncNum) + CallerCode; + GeneratedCode.push_back(std::make_pair(3, CallerCode)); + if (GenDebug) { + GeneratedCode.push_back(std::make_pair(0, "if(Result) {")); + GeneratedCode.push_back(std::make_pair(0, " CurDAG->setSubgraphColor(Result, \"yellow\");")); + GeneratedCode.push_back(std::make_pair(0, " CurDAG->setSubgraphColor(Result, \"black\");")); + GeneratedCode.push_back(std::make_pair(0, "}")); + //GeneratedCode.push_back(std::make_pair(0, "CurDAG->setSubgraphColor(N.getNode(), \"black\");")); + } + GeneratedCode.push_back(std::make_pair(0, "return Result;")); + } + + // Print function. + std::string OpVTStr; + if (OpVT == MVT::iPTR) { + OpVTStr = "_iPTR"; + } else if (OpVT == MVT::iPTRAny) { + OpVTStr = "_iPTRAny"; + } else if (OpVT == MVT::isVoid) { + // Nodes with a void result actually have a first result type of either + // Other (a chain) or Flag. Since there is no one-to-one mapping from + // void to this case, we handle it specially here. + } else { + OpVTStr = "_" + getEnumName(OpVT).substr(5); // Skip 'MVT::' + } + std::map<std::string, std::vector<std::string> >::iterator OpVTI = + OpcodeVTMap.find(OpName); + if (OpVTI == OpcodeVTMap.end()) { + std::vector<std::string> VTSet; + VTSet.push_back(OpVTStr); + OpcodeVTMap.insert(std::make_pair(OpName, VTSet)); + } else + OpVTI->second.push_back(OpVTStr); + + // We want to emit all of the matching code now. However, we want to emit + // the matches in order of minimal cost. Sort the patterns so the least + // cost one is at the start. + std::stable_sort(CodeForPatterns.begin(), CodeForPatterns.end(), + PatternSortingPredicate(CGP)); + + // Scan the code to see if all of the patterns are reachable and if it is + // possible that the last one might not match. + bool mightNotMatch = true; + for (unsigned i = 0, e = CodeForPatterns.size(); i != e; ++i) { + CodeList &GeneratedCode = CodeForPatterns[i].second; + mightNotMatch = false; + + for (unsigned j = 0, e = GeneratedCode.size(); j != e; ++j) { + if (GeneratedCode[j].first == 1) { // predicate. + mightNotMatch = true; + break; + } + } + + // If this pattern definitely matches, and if it isn't the last one, the + // patterns after it CANNOT ever match. Error out. + if (mightNotMatch == false && i != CodeForPatterns.size()-1) { + cerr << "Pattern '"; + CodeForPatterns[i].first->getSrcPattern()->print(*cerr.stream()); + cerr << "' is impossible to select!\n"; + exit(1); + } + } + + // Loop through and reverse all of the CodeList vectors, as we will be + // accessing them from their logical front, but accessing the end of a + // vector is more efficient. + for (unsigned i = 0, e = CodeForPatterns.size(); i != e; ++i) { + CodeList &GeneratedCode = CodeForPatterns[i].second; + std::reverse(GeneratedCode.begin(), GeneratedCode.end()); + } + + // Next, reverse the list of patterns itself for the same reason. + std::reverse(CodeForPatterns.begin(), CodeForPatterns.end()); + + OS << "SDNode *Select_" << getLegalCName(OpName) + << OpVTStr << "(const SDValue &N) {\n"; + + // Emit all of the patterns now, grouped together to share code. + EmitPatterns(CodeForPatterns, 2, OS); + + // If the last pattern has predicates (which could fail) emit code to + // catch the case where nothing handles a pattern. + if (mightNotMatch) { + OS << "\n"; + if (OpName != "ISD::INTRINSIC_W_CHAIN" && + OpName != "ISD::INTRINSIC_WO_CHAIN" && + OpName != "ISD::INTRINSIC_VOID") + OS << " CannotYetSelect(N);\n"; + else + OS << " CannotYetSelectIntrinsic(N);\n"; + + OS << " return NULL;\n"; + } + OS << "}\n\n"; + } + } + + // Emit boilerplate. + OS << "SDNode *Select_INLINEASM(SDValue N) {\n" + << " std::vector<SDValue> Ops(N.getNode()->op_begin(), N.getNode()->op_end());\n" + << " SelectInlineAsmMemoryOperands(Ops);\n\n" + + << " std::vector<MVT> VTs;\n" + << " VTs.push_back(MVT::Other);\n" + << " VTs.push_back(MVT::Flag);\n" + << " SDValue New = CurDAG->getNode(ISD::INLINEASM, N.getDebugLoc(), " + "VTs, &Ops[0], Ops.size());\n" + << " return New.getNode();\n" + << "}\n\n"; + + OS << "SDNode *Select_UNDEF(const SDValue &N) {\n" + << " return CurDAG->SelectNodeTo(N.getNode(), TargetInstrInfo::IMPLICIT_DEF,\n" + << " N.getValueType());\n" + << "}\n\n"; + + OS << "SDNode *Select_DBG_LABEL(const SDValue &N) {\n" + << " SDValue Chain = N.getOperand(0);\n" + << " unsigned C = cast<LabelSDNode>(N)->getLabelID();\n" + << " SDValue Tmp = CurDAG->getTargetConstant(C, MVT::i32);\n" + << " return CurDAG->SelectNodeTo(N.getNode(), TargetInstrInfo::DBG_LABEL,\n" + << " MVT::Other, Tmp, Chain);\n" + << "}\n\n"; + + OS << "SDNode *Select_EH_LABEL(const SDValue &N) {\n" + << " SDValue Chain = N.getOperand(0);\n" + << " unsigned C = cast<LabelSDNode>(N)->getLabelID();\n" + << " SDValue Tmp = CurDAG->getTargetConstant(C, MVT::i32);\n" + << " return CurDAG->SelectNodeTo(N.getNode(), TargetInstrInfo::EH_LABEL,\n" + << " MVT::Other, Tmp, Chain);\n" + << "}\n\n"; + + OS << "SDNode *Select_DECLARE(const SDValue &N) {\n" + << " SDValue Chain = N.getOperand(0);\n" + << " SDValue N1 = N.getOperand(1);\n" + << " SDValue N2 = N.getOperand(2);\n" + << " if (!isa<FrameIndexSDNode>(N1) || !isa<GlobalAddressSDNode>(N2)) {\n" + << " CannotYetSelect(N);\n" + << " }\n" + << " int FI = cast<FrameIndexSDNode>(N1)->getIndex();\n" + << " GlobalValue *GV = cast<GlobalAddressSDNode>(N2)->getGlobal();\n" + << " SDValue Tmp1 = " + << "CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy());\n" + << " SDValue Tmp2 = " + << "CurDAG->getTargetGlobalAddress(GV, TLI.getPointerTy());\n" + << " return CurDAG->SelectNodeTo(N.getNode(), TargetInstrInfo::DECLARE,\n" + << " MVT::Other, Tmp1, Tmp2, Chain);\n" + << "}\n\n"; + + OS << "// The main instruction selector code.\n" + << "SDNode *SelectCode(SDValue N) {\n" + << " MVT::SimpleValueType NVT = N.getNode()->getValueType(0).getSimpleVT();\n" + << " switch (N.getOpcode()) {\n" + << " default:\n" + << " assert(!N.isMachineOpcode() && \"Node already selected!\");\n" + << " break;\n" + << " case ISD::EntryToken: // These nodes remain the same.\n" + << " case ISD::MEMOPERAND:\n" + << " case ISD::BasicBlock:\n" + << " case ISD::Register:\n" + << " case ISD::HANDLENODE:\n" + << " case ISD::TargetConstant:\n" + << " case ISD::TargetConstantFP:\n" + << " case ISD::TargetConstantPool:\n" + << " case ISD::TargetFrameIndex:\n" + << " case ISD::TargetExternalSymbol:\n" + << " case ISD::TargetJumpTable:\n" + << " case ISD::TargetGlobalTLSAddress:\n" + << " case ISD::TargetGlobalAddress:\n" + << " case ISD::TokenFactor:\n" + << " case ISD::CopyFromReg:\n" + << " case ISD::CopyToReg: {\n" + << " return NULL;\n" + << " }\n" + << " case ISD::AssertSext:\n" + << " case ISD::AssertZext: {\n" + << " ReplaceUses(N, N.getOperand(0));\n" + << " return NULL;\n" + << " }\n" + << " case ISD::INLINEASM: return Select_INLINEASM(N);\n" + << " case ISD::DBG_LABEL: return Select_DBG_LABEL(N);\n" + << " case ISD::EH_LABEL: return Select_EH_LABEL(N);\n" + << " case ISD::DECLARE: return Select_DECLARE(N);\n" + << " case ISD::UNDEF: return Select_UNDEF(N);\n"; + + // Loop over all of the case statements, emiting a call to each method we + // emitted above. + for (std::map<std::string, std::vector<const PatternToMatch*> >::iterator + PBOI = PatternsByOpcode.begin(), E = PatternsByOpcode.end(); + PBOI != E; ++PBOI) { + const std::string &OpName = PBOI->first; + // Potentially multiple versions of select for this opcode. One for each + // ValueType of the node (or its first true operand if it doesn't produce a + // result. + std::map<std::string, std::vector<std::string> >::iterator OpVTI = + OpcodeVTMap.find(OpName); + std::vector<std::string> &OpVTs = OpVTI->second; + OS << " case " << OpName << ": {\n"; + // If we have only one variant and it's the default, elide the + // switch. Marginally faster, and makes MSVC happier. + if (OpVTs.size()==1 && OpVTs[0].empty()) { + OS << " return Select_" << getLegalCName(OpName) << "(N);\n"; + OS << " break;\n"; + OS << " }\n"; + continue; + } + // Keep track of whether we see a pattern that has an iPtr result. + bool HasPtrPattern = false; + bool HasDefaultPattern = false; + + OS << " switch (NVT) {\n"; + for (unsigned i = 0, e = OpVTs.size(); i < e; ++i) { + std::string &VTStr = OpVTs[i]; + if (VTStr.empty()) { + HasDefaultPattern = true; + continue; + } + + // If this is a match on iPTR: don't emit it directly, we need special + // code. + if (VTStr == "_iPTR") { + HasPtrPattern = true; + continue; + } + OS << " case MVT::" << VTStr.substr(1) << ":\n" + << " return Select_" << getLegalCName(OpName) + << VTStr << "(N);\n"; + } + OS << " default:\n"; + + // If there is an iPTR result version of this pattern, emit it here. + if (HasPtrPattern) { + OS << " if (TLI.getPointerTy() == NVT)\n"; + OS << " return Select_" << getLegalCName(OpName) <<"_iPTR(N);\n"; + } + if (HasDefaultPattern) { + OS << " return Select_" << getLegalCName(OpName) << "(N);\n"; + } + OS << " break;\n"; + OS << " }\n"; + OS << " break;\n"; + OS << " }\n"; + } + + OS << " } // end of big switch.\n\n" + << " if (N.getOpcode() != ISD::INTRINSIC_W_CHAIN &&\n" + << " N.getOpcode() != ISD::INTRINSIC_WO_CHAIN &&\n" + << " N.getOpcode() != ISD::INTRINSIC_VOID) {\n" + << " CannotYetSelect(N);\n" + << " } else {\n" + << " CannotYetSelectIntrinsic(N);\n" + << " }\n" + << " return NULL;\n" + << "}\n\n"; + + OS << "void CannotYetSelect(SDValue N) DISABLE_INLINE {\n" + << " cerr << \"Cannot yet select: \";\n" + << " N.getNode()->dump(CurDAG);\n" + << " cerr << '\\n';\n" + << " abort();\n" + << "}\n\n"; + + OS << "void CannotYetSelectIntrinsic(SDValue N) DISABLE_INLINE {\n" + << " cerr << \"Cannot yet select: \";\n" + << " unsigned iid = cast<ConstantSDNode>(N.getOperand(" + << "N.getOperand(0).getValueType() == MVT::Other))->getZExtValue();\n" + << " cerr << \"intrinsic %\"<< " + << "Intrinsic::getName((Intrinsic::ID)iid);\n" + << " cerr << '\\n';\n" + << " abort();\n" + << "}\n\n"; +} + +void DAGISelEmitter::run(std::ostream &OS) { + EmitSourceFileHeader("DAG Instruction Selector for the " + + CGP.getTargetInfo().getName() + " target", OS); + + OS << "// *** NOTE: This file is #included into the middle of the target\n" + << "// *** instruction selector class. These functions are really " + << "methods.\n\n"; + + OS << "// Include standard, target-independent definitions and methods used\n" + << "// by the instruction selector.\n"; + OS << "#include \"llvm/CodeGen/DAGISelHeader.h\"\n\n"; + + EmitNodeTransforms(OS); + EmitPredicateFunctions(OS); + + DOUT << "\n\nALL PATTERNS TO MATCH:\n\n"; + for (CodeGenDAGPatterns::ptm_iterator I = CGP.ptm_begin(), E = CGP.ptm_end(); + I != E; ++I) { + DOUT << "PATTERN: "; DEBUG(I->getSrcPattern()->dump()); + DOUT << "\nRESULT: "; DEBUG(I->getDstPattern()->dump()); + DOUT << "\n"; + } + + // At this point, we have full information about the 'Patterns' we need to + // parse, both implicitly from instructions as well as from explicit pattern + // definitions. Emit the resultant instruction selector. + EmitInstructionSelector(OS); + +} diff --git a/utils/TableGen/DAGISelEmitter.h b/utils/TableGen/DAGISelEmitter.h new file mode 100644 index 0000000000000..1b9f8bad88cd5 --- /dev/null +++ b/utils/TableGen/DAGISelEmitter.h @@ -0,0 +1,56 @@ +//===- DAGISelEmitter.h - Generate an instruction selector ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend emits a DAG instruction selector. +// +//===----------------------------------------------------------------------===// + +#ifndef DAGISEL_EMITTER_H +#define DAGISEL_EMITTER_H + +#include "TableGenBackend.h" +#include "CodeGenDAGPatterns.h" +#include <set> + +namespace llvm { + +/// DAGISelEmitter - The top-level class which coordinates construction +/// and emission of the instruction selector. +/// +class DAGISelEmitter : public TableGenBackend { + RecordKeeper &Records; + CodeGenDAGPatterns CGP; +public: + explicit DAGISelEmitter(RecordKeeper &R) : Records(R), CGP(R) {} + + // run - Output the isel, returning true on failure. + void run(std::ostream &OS); + + +private: + void EmitNodeTransforms(std::ostream &OS); + void EmitPredicateFunctions(std::ostream &OS); + + void GenerateCodeForPattern(const PatternToMatch &Pattern, + std::vector<std::pair<unsigned, std::string> > &GeneratedCode, + std::set<std::string> &GeneratedDecl, + std::vector<std::string> &TargetOpcodes, + std::vector<std::string> &TargetVTs, + bool &OutputIsVariadic, + unsigned &NumInputRootOps); + void EmitPatterns(std::vector<std::pair<const PatternToMatch*, + std::vector<std::pair<unsigned, std::string> > > > &Patterns, + unsigned Indent, std::ostream &OS); + + void EmitInstructionSelector(std::ostream &OS); +}; + +} // End llvm namespace + +#endif diff --git a/utils/TableGen/FastISelEmitter.cpp b/utils/TableGen/FastISelEmitter.cpp new file mode 100644 index 0000000000000..8c60b088627e3 --- /dev/null +++ b/utils/TableGen/FastISelEmitter.cpp @@ -0,0 +1,636 @@ +//===- FastISelEmitter.cpp - Generate an instruction selector -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend emits code for use by the "fast" instruction +// selection algorithm. See the comments at the top of +// lib/CodeGen/SelectionDAG/FastISel.cpp for background. +// +// This file scans through the target's tablegen instruction-info files +// and extracts instructions with obvious-looking patterns, and it emits +// code to look up these instructions by type and operator. +// +//===----------------------------------------------------------------------===// + +#include "FastISelEmitter.h" +#include "Record.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Streams.h" +#include "llvm/ADT/VectorExtras.h" +using namespace llvm; + +namespace { + +/// InstructionMemo - This class holds additional information about an +/// instruction needed to emit code for it. +/// +struct InstructionMemo { + std::string Name; + const CodeGenRegisterClass *RC; + unsigned char SubRegNo; + std::vector<std::string>* PhysRegs; +}; + +/// OperandsSignature - This class holds a description of a list of operand +/// types. It has utility methods for emitting text based on the operands. +/// +struct OperandsSignature { + std::vector<std::string> Operands; + + bool operator<(const OperandsSignature &O) const { + return Operands < O.Operands; + } + + bool empty() const { return Operands.empty(); } + + /// initialize - Examine the given pattern and initialize the contents + /// of the Operands array accordingly. Return true if all the operands + /// are supported, false otherwise. + /// + bool initialize(TreePatternNode *InstPatNode, + const CodeGenTarget &Target, + MVT::SimpleValueType VT) { + if (!InstPatNode->isLeaf() && + InstPatNode->getOperator()->getName() == "imm") { + Operands.push_back("i"); + return true; + } + if (!InstPatNode->isLeaf() && + InstPatNode->getOperator()->getName() == "fpimm") { + Operands.push_back("f"); + return true; + } + + const CodeGenRegisterClass *DstRC = 0; + + for (unsigned i = 0, e = InstPatNode->getNumChildren(); i != e; ++i) { + TreePatternNode *Op = InstPatNode->getChild(i); + // For now, filter out any operand with a predicate. + if (!Op->getPredicateFns().empty()) + return false; + // For now, filter out any operand with multiple values. + if (Op->getExtTypes().size() != 1) + return false; + // For now, all the operands must have the same type. + if (Op->getTypeNum(0) != VT) + return false; + if (!Op->isLeaf()) { + if (Op->getOperator()->getName() == "imm") { + Operands.push_back("i"); + continue; + } + if (Op->getOperator()->getName() == "fpimm") { + Operands.push_back("f"); + continue; + } + // For now, ignore other non-leaf nodes. + return false; + } + DefInit *OpDI = dynamic_cast<DefInit*>(Op->getLeafValue()); + if (!OpDI) + return false; + Record *OpLeafRec = OpDI->getDef(); + // For now, the only other thing we accept is register operands. + + const CodeGenRegisterClass *RC = 0; + if (OpLeafRec->isSubClassOf("RegisterClass")) + RC = &Target.getRegisterClass(OpLeafRec); + else if (OpLeafRec->isSubClassOf("Register")) + RC = Target.getRegisterClassForRegister(OpLeafRec); + else + return false; + // For now, require the register operands' register classes to all + // be the same. + if (!RC) + return false; + // For now, all the operands must have the same register class. + if (DstRC) { + if (DstRC != RC) + return false; + } else + DstRC = RC; + Operands.push_back("r"); + } + return true; + } + + void PrintParameters(std::ostream &OS) const { + for (unsigned i = 0, e = Operands.size(); i != e; ++i) { + if (Operands[i] == "r") { + OS << "unsigned Op" << i; + } else if (Operands[i] == "i") { + OS << "uint64_t imm" << i; + } else if (Operands[i] == "f") { + OS << "ConstantFP *f" << i; + } else { + assert("Unknown operand kind!"); + abort(); + } + if (i + 1 != e) + OS << ", "; + } + } + + void PrintArguments(std::ostream &OS, + const std::vector<std::string>& PR) const { + assert(PR.size() == Operands.size()); + bool PrintedArg = false; + for (unsigned i = 0, e = Operands.size(); i != e; ++i) { + if (PR[i] != "") + // Implicit physical register operand. + continue; + + if (PrintedArg) + OS << ", "; + if (Operands[i] == "r") { + OS << "Op" << i; + PrintedArg = true; + } else if (Operands[i] == "i") { + OS << "imm" << i; + PrintedArg = true; + } else if (Operands[i] == "f") { + OS << "f" << i; + PrintedArg = true; + } else { + assert("Unknown operand kind!"); + abort(); + } + } + } + + void PrintArguments(std::ostream &OS) const { + for (unsigned i = 0, e = Operands.size(); i != e; ++i) { + if (Operands[i] == "r") { + OS << "Op" << i; + } else if (Operands[i] == "i") { + OS << "imm" << i; + } else if (Operands[i] == "f") { + OS << "f" << i; + } else { + assert("Unknown operand kind!"); + abort(); + } + if (i + 1 != e) + OS << ", "; + } + } + + + void PrintManglingSuffix(std::ostream &OS, + const std::vector<std::string>& PR) const { + for (unsigned i = 0, e = Operands.size(); i != e; ++i) { + if (PR[i] != "") + // Implicit physical register operand. e.g. Instruction::Mul expect to + // select to a binary op. On x86, mul may take a single operand with + // the other operand being implicit. We must emit something that looks + // like a binary instruction except for the very inner FastEmitInst_* + // call. + continue; + OS << Operands[i]; + } + } + + void PrintManglingSuffix(std::ostream &OS) const { + for (unsigned i = 0, e = Operands.size(); i != e; ++i) { + OS << Operands[i]; + } + } +}; + +class FastISelMap { + typedef std::map<std::string, InstructionMemo> PredMap; + typedef std::map<MVT::SimpleValueType, PredMap> RetPredMap; + typedef std::map<MVT::SimpleValueType, RetPredMap> TypeRetPredMap; + typedef std::map<std::string, TypeRetPredMap> OpcodeTypeRetPredMap; + typedef std::map<OperandsSignature, OpcodeTypeRetPredMap> OperandsOpcodeTypeRetPredMap; + + OperandsOpcodeTypeRetPredMap SimplePatterns; + + std::string InstNS; + +public: + explicit FastISelMap(std::string InstNS); + + void CollectPatterns(CodeGenDAGPatterns &CGP); + void PrintClass(std::ostream &OS); + void PrintFunctionDefinitions(std::ostream &OS); +}; + +} + +static std::string getOpcodeName(Record *Op, CodeGenDAGPatterns &CGP) { + return CGP.getSDNodeInfo(Op).getEnumName(); +} + +static std::string getLegalCName(std::string OpName) { + std::string::size_type pos = OpName.find("::"); + if (pos != std::string::npos) + OpName.replace(pos, 2, "_"); + return OpName; +} + +FastISelMap::FastISelMap(std::string instns) + : InstNS(instns) { +} + +void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) { + const CodeGenTarget &Target = CGP.getTargetInfo(); + + // Determine the target's namespace name. + InstNS = Target.getInstNamespace() + "::"; + assert(InstNS.size() > 2 && "Can't determine target-specific namespace!"); + + // Scan through all the patterns and record the simple ones. + for (CodeGenDAGPatterns::ptm_iterator I = CGP.ptm_begin(), + E = CGP.ptm_end(); I != E; ++I) { + const PatternToMatch &Pattern = *I; + + // For now, just look at Instructions, so that we don't have to worry + // about emitting multiple instructions for a pattern. + TreePatternNode *Dst = Pattern.getDstPattern(); + if (Dst->isLeaf()) continue; + Record *Op = Dst->getOperator(); + if (!Op->isSubClassOf("Instruction")) + continue; + CodeGenInstruction &II = CGP.getTargetInfo().getInstruction(Op->getName()); + if (II.OperandList.empty()) + continue; + + // For now, ignore multi-instruction patterns. + bool MultiInsts = false; + for (unsigned i = 0, e = Dst->getNumChildren(); i != e; ++i) { + TreePatternNode *ChildOp = Dst->getChild(i); + if (ChildOp->isLeaf()) + continue; + if (ChildOp->getOperator()->isSubClassOf("Instruction")) { + MultiInsts = true; + break; + } + } + if (MultiInsts) + continue; + + // For now, ignore instructions where the first operand is not an + // output register. + const CodeGenRegisterClass *DstRC = 0; + unsigned SubRegNo = ~0; + if (Op->getName() != "EXTRACT_SUBREG") { + Record *Op0Rec = II.OperandList[0].Rec; + if (!Op0Rec->isSubClassOf("RegisterClass")) + continue; + DstRC = &Target.getRegisterClass(Op0Rec); + if (!DstRC) + continue; + } else { + SubRegNo = static_cast<IntInit*>( + Dst->getChild(1)->getLeafValue())->getValue(); + } + + // Inspect the pattern. + TreePatternNode *InstPatNode = Pattern.getSrcPattern(); + if (!InstPatNode) continue; + if (InstPatNode->isLeaf()) continue; + + Record *InstPatOp = InstPatNode->getOperator(); + std::string OpcodeName = getOpcodeName(InstPatOp, CGP); + MVT::SimpleValueType RetVT = InstPatNode->getTypeNum(0); + MVT::SimpleValueType VT = RetVT; + if (InstPatNode->getNumChildren()) + VT = InstPatNode->getChild(0)->getTypeNum(0); + + // For now, filter out instructions which just set a register to + // an Operand or an immediate, like MOV32ri. + if (InstPatOp->isSubClassOf("Operand")) + continue; + + // For now, filter out any instructions with predicates. + if (!InstPatNode->getPredicateFns().empty()) + continue; + + // Check all the operands. + OperandsSignature Operands; + if (!Operands.initialize(InstPatNode, Target, VT)) + continue; + + std::vector<std::string>* PhysRegInputs = new std::vector<std::string>(); + if (!InstPatNode->isLeaf() && + (InstPatNode->getOperator()->getName() == "imm" || + InstPatNode->getOperator()->getName() == "fpimmm")) + PhysRegInputs->push_back(""); + else if (!InstPatNode->isLeaf()) { + for (unsigned i = 0, e = InstPatNode->getNumChildren(); i != e; ++i) { + TreePatternNode *Op = InstPatNode->getChild(i); + if (!Op->isLeaf()) { + PhysRegInputs->push_back(""); + continue; + } + + DefInit *OpDI = dynamic_cast<DefInit*>(Op->getLeafValue()); + Record *OpLeafRec = OpDI->getDef(); + std::string PhysReg; + if (OpLeafRec->isSubClassOf("Register")) { + PhysReg += static_cast<StringInit*>(OpLeafRec->getValue( \ + "Namespace")->getValue())->getValue(); + PhysReg += "::"; + + std::vector<CodeGenRegister> Regs = Target.getRegisters(); + for (unsigned i = 0; i < Regs.size(); ++i) { + if (Regs[i].TheDef == OpLeafRec) { + PhysReg += Regs[i].getName(); + break; + } + } + } + + PhysRegInputs->push_back(PhysReg); + } + } else + PhysRegInputs->push_back(""); + + // Get the predicate that guards this pattern. + std::string PredicateCheck = Pattern.getPredicateCheck(); + + // Ok, we found a pattern that we can handle. Remember it. + InstructionMemo Memo = { + Pattern.getDstPattern()->getOperator()->getName(), + DstRC, + SubRegNo, + PhysRegInputs + }; + assert(!SimplePatterns[Operands][OpcodeName][VT][RetVT].count(PredicateCheck) && + "Duplicate pattern!"); + SimplePatterns[Operands][OpcodeName][VT][RetVT][PredicateCheck] = Memo; + } +} + +void FastISelMap::PrintFunctionDefinitions(std::ostream &OS) { + // Now emit code for all the patterns that we collected. + for (OperandsOpcodeTypeRetPredMap::const_iterator OI = SimplePatterns.begin(), + OE = SimplePatterns.end(); OI != OE; ++OI) { + const OperandsSignature &Operands = OI->first; + const OpcodeTypeRetPredMap &OTM = OI->second; + + for (OpcodeTypeRetPredMap::const_iterator I = OTM.begin(), E = OTM.end(); + I != E; ++I) { + const std::string &Opcode = I->first; + const TypeRetPredMap &TM = I->second; + + OS << "// FastEmit functions for " << Opcode << ".\n"; + OS << "\n"; + + // Emit one function for each opcode,type pair. + for (TypeRetPredMap::const_iterator TI = TM.begin(), TE = TM.end(); + TI != TE; ++TI) { + MVT::SimpleValueType VT = TI->first; + const RetPredMap &RM = TI->second; + if (RM.size() != 1) { + for (RetPredMap::const_iterator RI = RM.begin(), RE = RM.end(); + RI != RE; ++RI) { + MVT::SimpleValueType RetVT = RI->first; + const PredMap &PM = RI->second; + bool HasPred = false; + + OS << "unsigned FastEmit_" + << getLegalCName(Opcode) + << "_" << getLegalCName(getName(VT)) + << "_" << getLegalCName(getName(RetVT)) << "_"; + Operands.PrintManglingSuffix(OS); + OS << "("; + Operands.PrintParameters(OS); + OS << ") {\n"; + + // Emit code for each possible instruction. There may be + // multiple if there are subtarget concerns. + for (PredMap::const_iterator PI = PM.begin(), PE = PM.end(); + PI != PE; ++PI) { + std::string PredicateCheck = PI->first; + const InstructionMemo &Memo = PI->second; + + if (PredicateCheck.empty()) { + assert(!HasPred && + "Multiple instructions match, at least one has " + "a predicate and at least one doesn't!"); + } else { + OS << " if (" + PredicateCheck + ") {\n"; + OS << " "; + HasPred = true; + } + + for (unsigned i = 0; i < Memo.PhysRegs->size(); ++i) { + if ((*Memo.PhysRegs)[i] != "") + OS << " TII.copyRegToReg(*MBB, MBB->end(), " + << (*Memo.PhysRegs)[i] << ", Op" << i << ", " + << "TM.getRegisterInfo()->getPhysicalRegisterRegClass(" + << (*Memo.PhysRegs)[i] << "), " + << "MRI.getRegClass(Op" << i << "));\n"; + } + + OS << " return FastEmitInst_"; + if (Memo.SubRegNo == (unsigned char)~0) { + Operands.PrintManglingSuffix(OS, *Memo.PhysRegs); + OS << "(" << InstNS << Memo.Name << ", "; + OS << InstNS << Memo.RC->getName() << "RegisterClass"; + if (!Operands.empty()) + OS << ", "; + Operands.PrintArguments(OS, *Memo.PhysRegs); + OS << ");\n"; + } else { + OS << "extractsubreg(" << getName(RetVT); + OS << ", Op0, "; + OS << (unsigned)Memo.SubRegNo; + OS << ");\n"; + } + + if (HasPred) + OS << " }\n"; + + } + // Return 0 if none of the predicates were satisfied. + if (HasPred) + OS << " return 0;\n"; + OS << "}\n"; + OS << "\n"; + } + + // Emit one function for the type that demultiplexes on return type. + OS << "unsigned FastEmit_" + << getLegalCName(Opcode) << "_" + << getLegalCName(getName(VT)) << "_"; + Operands.PrintManglingSuffix(OS); + OS << "(MVT::SimpleValueType RetVT"; + if (!Operands.empty()) + OS << ", "; + Operands.PrintParameters(OS); + OS << ") {\nswitch (RetVT) {\n"; + for (RetPredMap::const_iterator RI = RM.begin(), RE = RM.end(); + RI != RE; ++RI) { + MVT::SimpleValueType RetVT = RI->first; + OS << " case " << getName(RetVT) << ": return FastEmit_" + << getLegalCName(Opcode) << "_" << getLegalCName(getName(VT)) + << "_" << getLegalCName(getName(RetVT)) << "_"; + Operands.PrintManglingSuffix(OS); + OS << "("; + Operands.PrintArguments(OS); + OS << ");\n"; + } + OS << " default: return 0;\n}\n}\n\n"; + + } else { + // Non-variadic return type. + OS << "unsigned FastEmit_" + << getLegalCName(Opcode) << "_" + << getLegalCName(getName(VT)) << "_"; + Operands.PrintManglingSuffix(OS); + OS << "(MVT::SimpleValueType RetVT"; + if (!Operands.empty()) + OS << ", "; + Operands.PrintParameters(OS); + OS << ") {\n"; + + OS << " if (RetVT != " << getName(RM.begin()->first) + << ")\n return 0;\n"; + + const PredMap &PM = RM.begin()->second; + bool HasPred = false; + + // Emit code for each possible instruction. There may be + // multiple if there are subtarget concerns. + for (PredMap::const_iterator PI = PM.begin(), PE = PM.end(); PI != PE; + ++PI) { + std::string PredicateCheck = PI->first; + const InstructionMemo &Memo = PI->second; + + if (PredicateCheck.empty()) { + assert(!HasPred && + "Multiple instructions match, at least one has " + "a predicate and at least one doesn't!"); + } else { + OS << " if (" + PredicateCheck + ") {\n"; + OS << " "; + HasPred = true; + } + + for (unsigned i = 0; i < Memo.PhysRegs->size(); ++i) { + if ((*Memo.PhysRegs)[i] != "") + OS << " TII.copyRegToReg(*MBB, MBB->end(), " + << (*Memo.PhysRegs)[i] << ", Op" << i << ", " + << "TM.getRegisterInfo()->getPhysicalRegisterRegClass(" + << (*Memo.PhysRegs)[i] << "), " + << "MRI.getRegClass(Op" << i << "));\n"; + } + + OS << " return FastEmitInst_"; + + if (Memo.SubRegNo == (unsigned char)~0) { + Operands.PrintManglingSuffix(OS, *Memo.PhysRegs); + OS << "(" << InstNS << Memo.Name << ", "; + OS << InstNS << Memo.RC->getName() << "RegisterClass"; + if (!Operands.empty()) + OS << ", "; + Operands.PrintArguments(OS, *Memo.PhysRegs); + OS << ");\n"; + } else { + OS << "extractsubreg(RetVT, Op0, "; + OS << (unsigned)Memo.SubRegNo; + OS << ");\n"; + } + + if (HasPred) + OS << " }\n"; + } + + // Return 0 if none of the predicates were satisfied. + if (HasPred) + OS << " return 0;\n"; + OS << "}\n"; + OS << "\n"; + } + } + + // Emit one function for the opcode that demultiplexes based on the type. + OS << "unsigned FastEmit_" + << getLegalCName(Opcode) << "_"; + Operands.PrintManglingSuffix(OS); + OS << "(MVT::SimpleValueType VT, MVT::SimpleValueType RetVT"; + if (!Operands.empty()) + OS << ", "; + Operands.PrintParameters(OS); + OS << ") {\n"; + OS << " switch (VT) {\n"; + for (TypeRetPredMap::const_iterator TI = TM.begin(), TE = TM.end(); + TI != TE; ++TI) { + MVT::SimpleValueType VT = TI->first; + std::string TypeName = getName(VT); + OS << " case " << TypeName << ": return FastEmit_" + << getLegalCName(Opcode) << "_" << getLegalCName(TypeName) << "_"; + Operands.PrintManglingSuffix(OS); + OS << "(RetVT"; + if (!Operands.empty()) + OS << ", "; + Operands.PrintArguments(OS); + OS << ");\n"; + } + OS << " default: return 0;\n"; + OS << " }\n"; + OS << "}\n"; + OS << "\n"; + } + + OS << "// Top-level FastEmit function.\n"; + OS << "\n"; + + // Emit one function for the operand signature that demultiplexes based + // on opcode and type. + OS << "unsigned FastEmit_"; + Operands.PrintManglingSuffix(OS); + OS << "(MVT::SimpleValueType VT, MVT::SimpleValueType RetVT, ISD::NodeType Opcode"; + if (!Operands.empty()) + OS << ", "; + Operands.PrintParameters(OS); + OS << ") {\n"; + OS << " switch (Opcode) {\n"; + for (OpcodeTypeRetPredMap::const_iterator I = OTM.begin(), E = OTM.end(); + I != E; ++I) { + const std::string &Opcode = I->first; + + OS << " case " << Opcode << ": return FastEmit_" + << getLegalCName(Opcode) << "_"; + Operands.PrintManglingSuffix(OS); + OS << "(VT, RetVT"; + if (!Operands.empty()) + OS << ", "; + Operands.PrintArguments(OS); + OS << ");\n"; + } + OS << " default: return 0;\n"; + OS << " }\n"; + OS << "}\n"; + OS << "\n"; + } +} + +void FastISelEmitter::run(std::ostream &OS) { + const CodeGenTarget &Target = CGP.getTargetInfo(); + + // Determine the target's namespace name. + std::string InstNS = Target.getInstNamespace() + "::"; + assert(InstNS.size() > 2 && "Can't determine target-specific namespace!"); + + EmitSourceFileHeader("\"Fast\" Instruction Selector for the " + + Target.getName() + " target", OS); + + FastISelMap F(InstNS); + F.CollectPatterns(CGP); + F.PrintFunctionDefinitions(OS); +} + +FastISelEmitter::FastISelEmitter(RecordKeeper &R) + : Records(R), + CGP(R) { +} + diff --git a/utils/TableGen/FastISelEmitter.h b/utils/TableGen/FastISelEmitter.h new file mode 100644 index 0000000000000..4743ca9bfa01e --- /dev/null +++ b/utils/TableGen/FastISelEmitter.h @@ -0,0 +1,39 @@ +//===- FastISelEmitter.h - Generate an instruction selector -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend emits a "fast" instruction selector. +// +//===----------------------------------------------------------------------===// + +#ifndef FASTISEL_EMITTER_H +#define FASTISEL_EMITTER_H + +#include "TableGenBackend.h" +#include "CodeGenDAGPatterns.h" + +namespace llvm { + +class CodeGenTarget; + +/// FastISelEmitter - The top-level class which coordinates construction +/// and emission of the instruction selector. +/// +class FastISelEmitter : public TableGenBackend { + RecordKeeper &Records; + CodeGenDAGPatterns CGP; +public: + explicit FastISelEmitter(RecordKeeper &R); + + // run - Output the isel, returning true on failure. + void run(std::ostream &OS); +}; + +} // End llvm namespace + +#endif diff --git a/utils/TableGen/InstrEnumEmitter.cpp b/utils/TableGen/InstrEnumEmitter.cpp new file mode 100644 index 0000000000000..4b4791b614580 --- /dev/null +++ b/utils/TableGen/InstrEnumEmitter.cpp @@ -0,0 +1,55 @@ +//===- InstrEnumEmitter.cpp - Generate Instruction Set Enums --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend is responsible for emitting enums for each machine +// instruction. +// +//===----------------------------------------------------------------------===// + +#include "InstrEnumEmitter.h" +#include "CodeGenTarget.h" +#include "Record.h" +#include <cstdio> +using namespace llvm; + +// runEnums - Print out enum values for all of the instructions. +void InstrEnumEmitter::run(std::ostream &OS) { + EmitSourceFileHeader("Target Instruction Enum Values", OS); + OS << "namespace llvm {\n\n"; + + CodeGenTarget Target; + + // We must emit the PHI opcode first... + std::string Namespace; + for (CodeGenTarget::inst_iterator II = Target.inst_begin(), + E = Target.inst_end(); II != E; ++II) { + if (II->second.Namespace != "TargetInstrInfo") { + Namespace = II->second.Namespace; + break; + } + } + + if (Namespace.empty()) { + fprintf(stderr, "No instructions defined!\n"); + exit(1); + } + + std::vector<const CodeGenInstruction*> NumberedInstructions; + Target.getInstructionsByEnumValue(NumberedInstructions); + + OS << "namespace " << Namespace << " {\n"; + OS << " enum {\n"; + for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { + OS << " " << NumberedInstructions[i]->TheDef->getName() + << "\t= " << i << ",\n"; + } + OS << " INSTRUCTION_LIST_END = " << NumberedInstructions.size() << "\n"; + OS << " };\n}\n"; + OS << "} // End llvm namespace \n"; +} diff --git a/utils/TableGen/InstrEnumEmitter.h b/utils/TableGen/InstrEnumEmitter.h new file mode 100644 index 0000000000000..b39fef2d433c9 --- /dev/null +++ b/utils/TableGen/InstrEnumEmitter.h @@ -0,0 +1,33 @@ +//===- InstrEnumEmitter.h - Generate Instruction Set Enums ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend is responsible for emitting enums for each machine +// instruction. +// +//===----------------------------------------------------------------------===// + +#ifndef INSTRENUM_EMITTER_H +#define INSTRENUM_EMITTER_H + +#include "TableGenBackend.h" + +namespace llvm { + +class InstrEnumEmitter : public TableGenBackend { + RecordKeeper &Records; +public: + InstrEnumEmitter(RecordKeeper &R) : Records(R) {} + + // run - Output the instruction set description, returning true on failure. + void run(std::ostream &OS); +}; + +} // End llvm namespace + +#endif diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp new file mode 100644 index 0000000000000..61dbe64af8f39 --- /dev/null +++ b/utils/TableGen/InstrInfoEmitter.cpp @@ -0,0 +1,381 @@ +//===- InstrInfoEmitter.cpp - Generate a Instruction Set Desc. ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend is responsible for emitting a description of the target +// instruction set for the code generator. +// +//===----------------------------------------------------------------------===// + +#include "InstrInfoEmitter.h" +#include "CodeGenTarget.h" +#include "Record.h" +#include <algorithm> +#include <iostream> +using namespace llvm; + +static void PrintDefList(const std::vector<Record*> &Uses, + unsigned Num, std::ostream &OS) { + OS << "static const unsigned ImplicitList" << Num << "[] = { "; + for (unsigned i = 0, e = Uses.size(); i != e; ++i) + OS << getQualifiedName(Uses[i]) << ", "; + OS << "0 };\n"; +} + +static void PrintBarriers(std::vector<Record*> &Barriers, + unsigned Num, std::ostream &OS) { + OS << "static const TargetRegisterClass* Barriers" << Num << "[] = { "; + for (unsigned i = 0, e = Barriers.size(); i != e; ++i) + OS << "&" << getQualifiedName(Barriers[i]) << "RegClass, "; + OS << "NULL };\n"; +} + +//===----------------------------------------------------------------------===// +// Instruction Itinerary Information. +//===----------------------------------------------------------------------===// + +struct RecordNameComparator { + bool operator()(const Record *Rec1, const Record *Rec2) const { + return Rec1->getName() < Rec2->getName(); + } +}; + +void InstrInfoEmitter::GatherItinClasses() { + std::vector<Record*> DefList = + Records.getAllDerivedDefinitions("InstrItinClass"); + std::sort(DefList.begin(), DefList.end(), RecordNameComparator()); + + for (unsigned i = 0, N = DefList.size(); i < N; i++) + ItinClassMap[DefList[i]->getName()] = i; +} + +unsigned InstrInfoEmitter::getItinClassNumber(const Record *InstRec) { + return ItinClassMap[InstRec->getValueAsDef("Itinerary")->getName()]; +} + +//===----------------------------------------------------------------------===// +// Operand Info Emission. +//===----------------------------------------------------------------------===// + +std::vector<std::string> +InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) { + std::vector<std::string> Result; + + for (unsigned i = 0, e = Inst.OperandList.size(); i != e; ++i) { + // Handle aggregate operands and normal operands the same way by expanding + // either case into a list of operands for this op. + std::vector<CodeGenInstruction::OperandInfo> OperandList; + + // This might be a multiple operand thing. Targets like X86 have + // registers in their multi-operand operands. It may also be an anonymous + // operand, which has a single operand, but no declared class for the + // operand. + DagInit *MIOI = Inst.OperandList[i].MIOperandInfo; + + if (!MIOI || MIOI->getNumArgs() == 0) { + // Single, anonymous, operand. + OperandList.push_back(Inst.OperandList[i]); + } else { + for (unsigned j = 0, e = Inst.OperandList[i].MINumOperands; j != e; ++j) { + OperandList.push_back(Inst.OperandList[i]); + + Record *OpR = dynamic_cast<DefInit*>(MIOI->getArg(j))->getDef(); + OperandList.back().Rec = OpR; + } + } + + for (unsigned j = 0, e = OperandList.size(); j != e; ++j) { + Record *OpR = OperandList[j].Rec; + std::string Res; + + if (OpR->isSubClassOf("RegisterClass")) + Res += getQualifiedName(OpR) + "RegClassID, "; + else + Res += "0, "; + // Fill in applicable flags. + Res += "0"; + + // Ptr value whose register class is resolved via callback. + if (OpR->getName() == "ptr_rc") + Res += "|(1<<TOI::LookupPtrRegClass)"; + + // Predicate operands. Check to see if the original unexpanded operand + // was of type PredicateOperand. + if (Inst.OperandList[i].Rec->isSubClassOf("PredicateOperand")) + Res += "|(1<<TOI::Predicate)"; + + // Optional def operands. Check to see if the original unexpanded operand + // was of type OptionalDefOperand. + if (Inst.OperandList[i].Rec->isSubClassOf("OptionalDefOperand")) + Res += "|(1<<TOI::OptionalDef)"; + + // Fill in constraint info. + Res += ", " + Inst.OperandList[i].Constraints[j]; + Result.push_back(Res); + } + } + + return Result; +} + +void InstrInfoEmitter::EmitOperandInfo(std::ostream &OS, + OperandInfoMapTy &OperandInfoIDs) { + // ID #0 is for no operand info. + unsigned OperandListNum = 0; + OperandInfoIDs[std::vector<std::string>()] = ++OperandListNum; + + OS << "\n"; + const CodeGenTarget &Target = CDP.getTargetInfo(); + for (CodeGenTarget::inst_iterator II = Target.inst_begin(), + E = Target.inst_end(); II != E; ++II) { + std::vector<std::string> OperandInfo = GetOperandInfo(II->second); + unsigned &N = OperandInfoIDs[OperandInfo]; + if (N != 0) continue; + + N = ++OperandListNum; + OS << "static const TargetOperandInfo OperandInfo" << N << "[] = { "; + for (unsigned i = 0, e = OperandInfo.size(); i != e; ++i) + OS << "{ " << OperandInfo[i] << " }, "; + OS << "};\n"; + } +} + +void InstrInfoEmitter::DetectRegisterClassBarriers(std::vector<Record*> &Defs, + const std::vector<CodeGenRegisterClass> &RCs, + std::vector<Record*> &Barriers) { + std::set<Record*> DefSet; + unsigned NumDefs = Defs.size(); + for (unsigned i = 0; i < NumDefs; ++i) + DefSet.insert(Defs[i]); + + for (unsigned i = 0, e = RCs.size(); i != e; ++i) { + const CodeGenRegisterClass &RC = RCs[i]; + unsigned NumRegs = RC.Elements.size(); + if (NumRegs > NumDefs) + continue; // Can't possibly clobber this RC. + + bool Clobber = true; + for (unsigned j = 0; j < NumRegs; ++j) { + Record *Reg = RC.Elements[j]; + if (!DefSet.count(Reg)) { + Clobber = false; + break; + } + } + if (Clobber) + Barriers.push_back(RC.TheDef); + } +} + +//===----------------------------------------------------------------------===// +// Main Output. +//===----------------------------------------------------------------------===// + +// run - Emit the main instruction description records for the target... +void InstrInfoEmitter::run(std::ostream &OS) { + GatherItinClasses(); + + EmitSourceFileHeader("Target Instruction Descriptors", OS); + OS << "namespace llvm {\n\n"; + + CodeGenTarget &Target = CDP.getTargetInfo(); + const std::string &TargetName = Target.getName(); + Record *InstrInfo = Target.getInstructionSet(); + const std::vector<CodeGenRegisterClass> &RCs = Target.getRegisterClasses(); + + // Keep track of all of the def lists we have emitted already. + std::map<std::vector<Record*>, unsigned> EmittedLists; + unsigned ListNumber = 0; + std::map<std::vector<Record*>, unsigned> EmittedBarriers; + unsigned BarrierNumber = 0; + std::map<Record*, unsigned> BarriersMap; + + // Emit all of the instruction's implicit uses and defs. + for (CodeGenTarget::inst_iterator II = Target.inst_begin(), + E = Target.inst_end(); II != E; ++II) { + Record *Inst = II->second.TheDef; + std::vector<Record*> Uses = Inst->getValueAsListOfDefs("Uses"); + if (!Uses.empty()) { + unsigned &IL = EmittedLists[Uses]; + if (!IL) PrintDefList(Uses, IL = ++ListNumber, OS); + } + std::vector<Record*> Defs = Inst->getValueAsListOfDefs("Defs"); + if (!Defs.empty()) { + std::vector<Record*> RCBarriers; + DetectRegisterClassBarriers(Defs, RCs, RCBarriers); + if (!RCBarriers.empty()) { + unsigned &IB = EmittedBarriers[RCBarriers]; + if (!IB) PrintBarriers(RCBarriers, IB = ++BarrierNumber, OS); + BarriersMap.insert(std::make_pair(Inst, IB)); + } + + unsigned &IL = EmittedLists[Defs]; + if (!IL) PrintDefList(Defs, IL = ++ListNumber, OS); + } + } + + OperandInfoMapTy OperandInfoIDs; + + // Emit all of the operand info records. + EmitOperandInfo(OS, OperandInfoIDs); + + // Emit all of the TargetInstrDesc records in their ENUM ordering. + // + OS << "\nstatic const TargetInstrDesc " << TargetName + << "Insts[] = {\n"; + std::vector<const CodeGenInstruction*> NumberedInstructions; + Target.getInstructionsByEnumValue(NumberedInstructions); + + for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) + emitRecord(*NumberedInstructions[i], i, InstrInfo, EmittedLists, + BarriersMap, OperandInfoIDs, OS); + OS << "};\n"; + OS << "} // End llvm namespace \n"; +} + +void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, + Record *InstrInfo, + std::map<std::vector<Record*>, unsigned> &EmittedLists, + std::map<Record*, unsigned> &BarriersMap, + const OperandInfoMapTy &OpInfo, + std::ostream &OS) { + int MinOperands = 0; + if (!Inst.OperandList.empty()) + // Each logical operand can be multiple MI operands. + MinOperands = Inst.OperandList.back().MIOperandNo + + Inst.OperandList.back().MINumOperands; + + OS << " { "; + OS << Num << ",\t" << MinOperands << ",\t" + << Inst.NumDefs << ",\t" << getItinClassNumber(Inst.TheDef) + << ",\t\"" << Inst.TheDef->getName() << "\", 0"; + + // Emit all of the target indepedent flags... + if (Inst.isReturn) OS << "|(1<<TID::Return)"; + if (Inst.isBranch) OS << "|(1<<TID::Branch)"; + if (Inst.isIndirectBranch) OS << "|(1<<TID::IndirectBranch)"; + if (Inst.isBarrier) OS << "|(1<<TID::Barrier)"; + if (Inst.hasDelaySlot) OS << "|(1<<TID::DelaySlot)"; + if (Inst.isCall) OS << "|(1<<TID::Call)"; + if (Inst.canFoldAsLoad) OS << "|(1<<TID::FoldableAsLoad)"; + if (Inst.mayLoad) OS << "|(1<<TID::MayLoad)"; + if (Inst.mayStore) OS << "|(1<<TID::MayStore)"; + if (Inst.isPredicable) OS << "|(1<<TID::Predicable)"; + if (Inst.isConvertibleToThreeAddress) OS << "|(1<<TID::ConvertibleTo3Addr)"; + if (Inst.isCommutable) OS << "|(1<<TID::Commutable)"; + if (Inst.isTerminator) OS << "|(1<<TID::Terminator)"; + if (Inst.isReMaterializable) OS << "|(1<<TID::Rematerializable)"; + if (Inst.isNotDuplicable) OS << "|(1<<TID::NotDuplicable)"; + if (Inst.hasOptionalDef) OS << "|(1<<TID::HasOptionalDef)"; + if (Inst.usesCustomDAGSchedInserter) + OS << "|(1<<TID::UsesCustomDAGSchedInserter)"; + if (Inst.isVariadic) OS << "|(1<<TID::Variadic)"; + if (Inst.hasSideEffects) OS << "|(1<<TID::UnmodeledSideEffects)"; + if (Inst.isAsCheapAsAMove) OS << "|(1<<TID::CheapAsAMove)"; + OS << ", 0"; + + // Emit all of the target-specific flags... + ListInit *LI = InstrInfo->getValueAsListInit("TSFlagsFields"); + ListInit *Shift = InstrInfo->getValueAsListInit("TSFlagsShifts"); + if (LI->getSize() != Shift->getSize()) + throw "Lengths of " + InstrInfo->getName() + + ":(TargetInfoFields, TargetInfoPositions) must be equal!"; + + for (unsigned i = 0, e = LI->getSize(); i != e; ++i) + emitShiftedValue(Inst.TheDef, dynamic_cast<StringInit*>(LI->getElement(i)), + dynamic_cast<IntInit*>(Shift->getElement(i)), OS); + + OS << ", "; + + // Emit the implicit uses and defs lists... + std::vector<Record*> UseList = Inst.TheDef->getValueAsListOfDefs("Uses"); + if (UseList.empty()) + OS << "NULL, "; + else + OS << "ImplicitList" << EmittedLists[UseList] << ", "; + + std::vector<Record*> DefList = Inst.TheDef->getValueAsListOfDefs("Defs"); + if (DefList.empty()) + OS << "NULL, "; + else + OS << "ImplicitList" << EmittedLists[DefList] << ", "; + + std::map<Record*, unsigned>::iterator BI = BarriersMap.find(Inst.TheDef); + if (BI == BarriersMap.end()) + OS << "NULL, "; + else + OS << "Barriers" << BI->second << ", "; + + // Emit the operand info. + std::vector<std::string> OperandInfo = GetOperandInfo(Inst); + if (OperandInfo.empty()) + OS << "0"; + else + OS << "OperandInfo" << OpInfo.find(OperandInfo)->second; + + OS << " }, // Inst #" << Num << " = " << Inst.TheDef->getName() << "\n"; +} + + +void InstrInfoEmitter::emitShiftedValue(Record *R, StringInit *Val, + IntInit *ShiftInt, std::ostream &OS) { + if (Val == 0 || ShiftInt == 0) + throw std::string("Illegal value or shift amount in TargetInfo*!"); + RecordVal *RV = R->getValue(Val->getValue()); + int Shift = ShiftInt->getValue(); + + if (RV == 0 || RV->getValue() == 0) { + // This isn't an error if this is a builtin instruction. + if (R->getName() != "PHI" && + R->getName() != "INLINEASM" && + R->getName() != "DBG_LABEL" && + R->getName() != "EH_LABEL" && + R->getName() != "GC_LABEL" && + R->getName() != "DECLARE" && + R->getName() != "EXTRACT_SUBREG" && + R->getName() != "INSERT_SUBREG" && + R->getName() != "IMPLICIT_DEF" && + R->getName() != "SUBREG_TO_REG" && + R->getName() != "COPY_TO_REGCLASS") + throw R->getName() + " doesn't have a field named '" + + Val->getValue() + "'!"; + return; + } + + Init *Value = RV->getValue(); + if (BitInit *BI = dynamic_cast<BitInit*>(Value)) { + if (BI->getValue()) OS << "|(1<<" << Shift << ")"; + return; + } else if (BitsInit *BI = dynamic_cast<BitsInit*>(Value)) { + // Convert the Bits to an integer to print... + Init *I = BI->convertInitializerTo(new IntRecTy()); + if (I) + if (IntInit *II = dynamic_cast<IntInit*>(I)) { + if (II->getValue()) { + if (Shift) + OS << "|(" << II->getValue() << "<<" << Shift << ")"; + else + OS << "|" << II->getValue(); + } + return; + } + + } else if (IntInit *II = dynamic_cast<IntInit*>(Value)) { + if (II->getValue()) { + if (Shift) + OS << "|(" << II->getValue() << "<<" << Shift << ")"; + else + OS << II->getValue(); + } + return; + } + + std::cerr << "Unhandled initializer: " << *Val << "\n"; + throw "In record '" + R->getName() + "' for TSFlag emission."; +} + diff --git a/utils/TableGen/InstrInfoEmitter.h b/utils/TableGen/InstrInfoEmitter.h new file mode 100644 index 0000000000000..870ea0c587809 --- /dev/null +++ b/utils/TableGen/InstrInfoEmitter.h @@ -0,0 +1,68 @@ +//===- InstrInfoEmitter.h - Generate a Instruction Set Desc. ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend is responsible for emitting a description of the target +// instruction set for the code generator. +// +//===----------------------------------------------------------------------===// + +#ifndef INSTRINFO_EMITTER_H +#define INSTRINFO_EMITTER_H + +#include "TableGenBackend.h" +#include "CodeGenDAGPatterns.h" +#include <vector> +#include <map> + +namespace llvm { + +class StringInit; +class IntInit; +class ListInit; +class CodeGenInstruction; + +class InstrInfoEmitter : public TableGenBackend { + RecordKeeper &Records; + CodeGenDAGPatterns CDP; + std::map<std::string, unsigned> ItinClassMap; + +public: + InstrInfoEmitter(RecordKeeper &R) : Records(R), CDP(R) { } + + // run - Output the instruction set description, returning true on failure. + void run(std::ostream &OS); + +private: + typedef std::map<std::vector<std::string>, unsigned> OperandInfoMapTy; + + void emitRecord(const CodeGenInstruction &Inst, unsigned Num, + Record *InstrInfo, + std::map<std::vector<Record*>, unsigned> &EL, + std::map<Record*, unsigned> &BM, + const OperandInfoMapTy &OpInfo, + std::ostream &OS); + void emitShiftedValue(Record *R, StringInit *Val, IntInit *Shift, + std::ostream &OS); + + // Itinerary information. + void GatherItinClasses(); + unsigned getItinClassNumber(const Record *InstRec); + + // Operand information. + void EmitOperandInfo(std::ostream &OS, OperandInfoMapTy &OperandInfoIDs); + std::vector<std::string> GetOperandInfo(const CodeGenInstruction &Inst); + + void DetectRegisterClassBarriers(std::vector<Record*> &Defs, + const std::vector<CodeGenRegisterClass> &RCs, + std::vector<Record*> &Barriers); +}; + +} // End llvm namespace + +#endif diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp new file mode 100644 index 0000000000000..2d28fb72e343a --- /dev/null +++ b/utils/TableGen/IntrinsicEmitter.cpp @@ -0,0 +1,716 @@ +//===- IntrinsicEmitter.cpp - Generate intrinsic information --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend emits information about intrinsic functions. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenTarget.h" +#include "IntrinsicEmitter.h" +#include "Record.h" +#include "llvm/ADT/StringExtras.h" +#include <algorithm> +using namespace llvm; + +//===----------------------------------------------------------------------===// +// IntrinsicEmitter Implementation +//===----------------------------------------------------------------------===// + +void IntrinsicEmitter::run(std::ostream &OS) { + EmitSourceFileHeader("Intrinsic Function Source Fragment", OS); + + std::vector<CodeGenIntrinsic> Ints = LoadIntrinsics(Records, TargetOnly); + + if (TargetOnly && !Ints.empty()) + TargetPrefix = Ints[0].TargetPrefix; + + // Emit the enum information. + EmitEnumInfo(Ints, OS); + + // Emit the intrinsic ID -> name table. + EmitIntrinsicToNameTable(Ints, OS); + + // Emit the intrinsic ID -> overload table. + EmitIntrinsicToOverloadTable(Ints, OS); + + // Emit the function name recognizer. + EmitFnNameRecognizer(Ints, OS); + + // Emit the intrinsic verifier. + EmitVerifier(Ints, OS); + + // Emit the intrinsic declaration generator. + EmitGenerator(Ints, OS); + + // Emit the intrinsic parameter attributes. + EmitAttributes(Ints, OS); + + // Emit intrinsic alias analysis mod/ref behavior. + EmitModRefBehavior(Ints, OS); + + // Emit a list of intrinsics with corresponding GCC builtins. + EmitGCCBuiltinList(Ints, OS); + + // Emit code to translate GCC builtins into LLVM intrinsics. + EmitIntrinsicToGCCBuiltinMap(Ints, OS); +} + +void IntrinsicEmitter::EmitEnumInfo(const std::vector<CodeGenIntrinsic> &Ints, + std::ostream &OS) { + OS << "// Enum values for Intrinsics.h\n"; + OS << "#ifdef GET_INTRINSIC_ENUM_VALUES\n"; + for (unsigned i = 0, e = Ints.size(); i != e; ++i) { + OS << " " << Ints[i].EnumName; + OS << ((i != e-1) ? ", " : " "); + OS << std::string(40-Ints[i].EnumName.size(), ' ') + << "// " << Ints[i].Name << "\n"; + } + OS << "#endif\n\n"; +} + +void IntrinsicEmitter:: +EmitFnNameRecognizer(const std::vector<CodeGenIntrinsic> &Ints, + std::ostream &OS) { + // Build a function name -> intrinsic name mapping. + std::map<std::string, unsigned> IntMapping; + for (unsigned i = 0, e = Ints.size(); i != e; ++i) + IntMapping[Ints[i].Name] = i; + + OS << "// Function name -> enum value recognizer code.\n"; + OS << "#ifdef GET_FUNCTION_RECOGNIZER\n"; + OS << " switch (Name[5]) {\n"; + OS << " default:\n"; + // Emit the intrinsics in sorted order. + char LastChar = 0; + for (std::map<std::string, unsigned>::iterator I = IntMapping.begin(), + E = IntMapping.end(); I != E; ++I) { + if (I->first[5] != LastChar) { + LastChar = I->first[5]; + OS << " break;\n"; + OS << " case '" << LastChar << "':\n"; + } + + // For overloaded intrinsics, only the prefix needs to match + if (Ints[I->second].isOverloaded) + OS << " if (Len > " << I->first.size() + << " && !memcmp(Name, \"" << I->first << ".\", " + << (I->first.size() + 1) << ")) return " << TargetPrefix << "Intrinsic::" + << Ints[I->second].EnumName << ";\n"; + else + OS << " if (Len == " << I->first.size() + << " && !memcmp(Name, \"" << I->first << "\", " + << I->first.size() << ")) return " << TargetPrefix << "Intrinsic::" + << Ints[I->second].EnumName << ";\n"; + } + OS << " }\n"; + OS << "#endif\n\n"; +} + +void IntrinsicEmitter:: +EmitIntrinsicToNameTable(const std::vector<CodeGenIntrinsic> &Ints, + std::ostream &OS) { + OS << "// Intrinsic ID to name table\n"; + OS << "#ifdef GET_INTRINSIC_NAME_TABLE\n"; + OS << " // Note that entry #0 is the invalid intrinsic!\n"; + for (unsigned i = 0, e = Ints.size(); i != e; ++i) + OS << " \"" << Ints[i].Name << "\",\n"; + OS << "#endif\n\n"; +} + +void IntrinsicEmitter:: +EmitIntrinsicToOverloadTable(const std::vector<CodeGenIntrinsic> &Ints, + std::ostream &OS) { + OS << "// Intrinsic ID to overload table\n"; + OS << "#ifdef GET_INTRINSIC_OVERLOAD_TABLE\n"; + OS << " // Note that entry #0 is the invalid intrinsic!\n"; + for (unsigned i = 0, e = Ints.size(); i != e; ++i) { + OS << " "; + if (Ints[i].isOverloaded) + OS << "true"; + else + OS << "false"; + OS << ",\n"; + } + OS << "#endif\n\n"; +} + +static void EmitTypeForValueType(std::ostream &OS, MVT::SimpleValueType VT) { + if (MVT(VT).isInteger()) { + unsigned BitWidth = MVT(VT).getSizeInBits(); + OS << "IntegerType::get(" << BitWidth << ")"; + } else if (VT == MVT::Other) { + // MVT::OtherVT is used to mean the empty struct type here. + OS << "StructType::get(std::vector<const Type *>())"; + } else if (VT == MVT::f32) { + OS << "Type::FloatTy"; + } else if (VT == MVT::f64) { + OS << "Type::DoubleTy"; + } else if (VT == MVT::f80) { + OS << "Type::X86_FP80Ty"; + } else if (VT == MVT::f128) { + OS << "Type::FP128Ty"; + } else if (VT == MVT::ppcf128) { + OS << "Type::PPC_FP128Ty"; + } else if (VT == MVT::isVoid) { + OS << "Type::VoidTy"; + } else { + assert(false && "Unsupported ValueType!"); + } +} + +static void EmitTypeGenerate(std::ostream &OS, const Record *ArgType, + unsigned &ArgNo); + +static void EmitTypeGenerate(std::ostream &OS, + const std::vector<Record*> &ArgTypes, + unsigned &ArgNo) { + if (ArgTypes.size() == 1) { + EmitTypeGenerate(OS, ArgTypes.front(), ArgNo); + return; + } + + OS << "StructType::get("; + + for (std::vector<Record*>::const_iterator + I = ArgTypes.begin(), E = ArgTypes.end(); I != E; ++I) { + EmitTypeGenerate(OS, *I, ArgNo); + OS << ", "; + } + + OS << " NULL)"; +} + +static void EmitTypeGenerate(std::ostream &OS, const Record *ArgType, + unsigned &ArgNo) { + MVT::SimpleValueType VT = getValueType(ArgType->getValueAsDef("VT")); + + if (ArgType->isSubClassOf("LLVMMatchType")) { + unsigned Number = ArgType->getValueAsInt("Number"); + assert(Number < ArgNo && "Invalid matching number!"); + if (ArgType->isSubClassOf("LLVMExtendedElementVectorType")) + OS << "VectorType::getExtendedElementVectorType" + << "(dyn_cast<VectorType>(Tys[" << Number << "]))"; + else if (ArgType->isSubClassOf("LLVMTruncatedElementVectorType")) + OS << "VectorType::getTruncatedElementVectorType" + << "(dyn_cast<VectorType>(Tys[" << Number << "]))"; + else + OS << "Tys[" << Number << "]"; + } else if (VT == MVT::iAny || VT == MVT::fAny) { + // NOTE: The ArgNo variable here is not the absolute argument number, it is + // the index of the "arbitrary" type in the Tys array passed to the + // Intrinsic::getDeclaration function. Consequently, we only want to + // increment it when we actually hit an overloaded type. Getting this wrong + // leads to very subtle bugs! + OS << "Tys[" << ArgNo++ << "]"; + } else if (MVT(VT).isVector()) { + MVT VVT = VT; + OS << "VectorType::get("; + EmitTypeForValueType(OS, VVT.getVectorElementType().getSimpleVT()); + OS << ", " << VVT.getVectorNumElements() << ")"; + } else if (VT == MVT::iPTR) { + OS << "PointerType::getUnqual("; + EmitTypeGenerate(OS, ArgType->getValueAsDef("ElTy"), ArgNo); + OS << ")"; + } else if (VT == MVT::iPTRAny) { + // Make sure the user has passed us an argument type to overload. If not, + // treat it as an ordinary (not overloaded) intrinsic. + OS << "(" << ArgNo << " < numTys) ? Tys[" << ArgNo + << "] : PointerType::getUnqual("; + EmitTypeGenerate(OS, ArgType->getValueAsDef("ElTy"), ArgNo); + OS << ")"; + ++ArgNo; + } else if (VT == MVT::isVoid) { + if (ArgNo == 0) + OS << "Type::VoidTy"; + else + // MVT::isVoid is used to mean varargs here. + OS << "..."; + } else { + EmitTypeForValueType(OS, VT); + } +} + +/// RecordListComparator - Provide a deterministic comparator for lists of +/// records. +namespace { + typedef std::pair<std::vector<Record*>, std::vector<Record*> > RecPair; + struct RecordListComparator { + bool operator()(const RecPair &LHS, + const RecPair &RHS) const { + unsigned i = 0; + const std::vector<Record*> *LHSVec = &LHS.first; + const std::vector<Record*> *RHSVec = &RHS.first; + unsigned RHSSize = RHSVec->size(); + unsigned LHSSize = LHSVec->size(); + + do { + if (i == RHSSize) return false; // RHS is shorter than LHS. + if ((*LHSVec)[i] != (*RHSVec)[i]) + return (*LHSVec)[i]->getName() < (*RHSVec)[i]->getName(); + } while (++i != LHSSize); + + if (i != RHSSize) return true; + + i = 0; + LHSVec = &LHS.second; + RHSVec = &RHS.second; + RHSSize = RHSVec->size(); + LHSSize = LHSVec->size(); + + for (i = 0; i != LHSSize; ++i) { + if (i == RHSSize) return false; // RHS is shorter than LHS. + if ((*LHSVec)[i] != (*RHSVec)[i]) + return (*LHSVec)[i]->getName() < (*RHSVec)[i]->getName(); + } + + return i != RHSSize; + } + }; +} + +void IntrinsicEmitter::EmitVerifier(const std::vector<CodeGenIntrinsic> &Ints, + std::ostream &OS) { + OS << "// Verifier::visitIntrinsicFunctionCall code.\n"; + OS << "#ifdef GET_INTRINSIC_VERIFIER\n"; + OS << " switch (ID) {\n"; + OS << " default: assert(0 && \"Invalid intrinsic!\");\n"; + + // This checking can emit a lot of very common code. To reduce the amount of + // code that we emit, batch up cases that have identical types. This avoids + // problems where GCC can run out of memory compiling Verifier.cpp. + typedef std::map<RecPair, std::vector<unsigned>, RecordListComparator> MapTy; + MapTy UniqueArgInfos; + + // Compute the unique argument type info. + for (unsigned i = 0, e = Ints.size(); i != e; ++i) + UniqueArgInfos[make_pair(Ints[i].IS.RetTypeDefs, + Ints[i].IS.ParamTypeDefs)].push_back(i); + + // Loop through the array, emitting one comparison for each batch. + for (MapTy::iterator I = UniqueArgInfos.begin(), + E = UniqueArgInfos.end(); I != E; ++I) { + for (unsigned i = 0, e = I->second.size(); i != e; ++i) + OS << " case Intrinsic::" << Ints[I->second[i]].EnumName << ":\t\t// " + << Ints[I->second[i]].Name << "\n"; + + const RecPair &ArgTypes = I->first; + const std::vector<Record*> &RetTys = ArgTypes.first; + const std::vector<Record*> &ParamTys = ArgTypes.second; + + OS << " VerifyIntrinsicPrototype(ID, IF, " << RetTys.size() << ", " + << ParamTys.size(); + + // Emit return types. + for (unsigned j = 0, je = RetTys.size(); j != je; ++j) { + Record *ArgType = RetTys[j]; + OS << ", "; + + if (ArgType->isSubClassOf("LLVMMatchType")) { + unsigned Number = ArgType->getValueAsInt("Number"); + if (ArgType->isSubClassOf("LLVMExtendedElementVectorType")) + OS << "~(ExtendedElementVectorType | " << Number << ")"; + else if (ArgType->isSubClassOf("LLVMTruncatedElementVectorType")) + OS << "~(TruncatedElementVectorType | " << Number << ")"; + else + OS << "~" << Number; + } else { + MVT::SimpleValueType VT = getValueType(ArgType->getValueAsDef("VT")); + OS << getEnumName(VT); + + if (VT == MVT::isVoid && j != 0 && j != je - 1) + throw "Var arg type not last argument"; + } + } + + // Emit the parameter types. + for (unsigned j = 0, je = ParamTys.size(); j != je; ++j) { + Record *ArgType = ParamTys[j]; + OS << ", "; + + if (ArgType->isSubClassOf("LLVMMatchType")) { + unsigned Number = ArgType->getValueAsInt("Number"); + if (ArgType->isSubClassOf("LLVMExtendedElementVectorType")) + OS << "~(ExtendedElementVectorType | " << Number << ")"; + else if (ArgType->isSubClassOf("LLVMTruncatedElementVectorType")) + OS << "~(TruncatedElementVectorType | " << Number << ")"; + else + OS << "~" << Number; + } else { + MVT::SimpleValueType VT = getValueType(ArgType->getValueAsDef("VT")); + OS << getEnumName(VT); + + if (VT == MVT::isVoid && j != 0 && j != je - 1) + throw "Var arg type not last argument"; + } + } + + OS << ");\n"; + OS << " break;\n"; + } + OS << " }\n"; + OS << "#endif\n\n"; +} + +void IntrinsicEmitter::EmitGenerator(const std::vector<CodeGenIntrinsic> &Ints, + std::ostream &OS) { + OS << "// Code for generating Intrinsic function declarations.\n"; + OS << "#ifdef GET_INTRINSIC_GENERATOR\n"; + OS << " switch (id) {\n"; + OS << " default: assert(0 && \"Invalid intrinsic!\");\n"; + + // Similar to GET_INTRINSIC_VERIFIER, batch up cases that have identical + // types. + typedef std::map<RecPair, std::vector<unsigned>, RecordListComparator> MapTy; + MapTy UniqueArgInfos; + + // Compute the unique argument type info. + for (unsigned i = 0, e = Ints.size(); i != e; ++i) + UniqueArgInfos[make_pair(Ints[i].IS.RetTypeDefs, + Ints[i].IS.ParamTypeDefs)].push_back(i); + + // Loop through the array, emitting one generator for each batch. + std::string IntrinsicStr = TargetPrefix + "Intrinsic::"; + + for (MapTy::iterator I = UniqueArgInfos.begin(), + E = UniqueArgInfos.end(); I != E; ++I) { + for (unsigned i = 0, e = I->second.size(); i != e; ++i) + OS << " case " << IntrinsicStr << Ints[I->second[i]].EnumName + << ":\t\t// " << Ints[I->second[i]].Name << "\n"; + + const RecPair &ArgTypes = I->first; + const std::vector<Record*> &RetTys = ArgTypes.first; + const std::vector<Record*> &ParamTys = ArgTypes.second; + + unsigned N = ParamTys.size(); + + if (N > 1 && + getValueType(ParamTys[N - 1]->getValueAsDef("VT")) == MVT::isVoid) { + OS << " IsVarArg = true;\n"; + --N; + } + + unsigned ArgNo = 0; + OS << " ResultTy = "; + EmitTypeGenerate(OS, RetTys, ArgNo); + OS << ";\n"; + + for (unsigned j = 0; j != N; ++j) { + OS << " ArgTys.push_back("; + EmitTypeGenerate(OS, ParamTys[j], ArgNo); + OS << ");\n"; + } + + OS << " break;\n"; + } + + OS << " }\n"; + OS << "#endif\n\n"; +} + +/// EmitAttributes - This emits the Intrinsic::getAttributes method. +void IntrinsicEmitter:: +EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, std::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 + << "Intrinsic::ID id) {"; + else + OS << "AttrListPtr Intrinsic::getAttributes(ID id) {"; + OS << " // No intrinsic can throw exceptions.\n"; + OS << " Attributes Attr = Attribute::NoUnwind;\n"; + OS << " switch (id) {\n"; + OS << " default: break;\n"; + unsigned MaxArgAttrs = 0; + for (unsigned i = 0, e = Ints.size(); i != e; ++i) { + MaxArgAttrs = + std::max(MaxArgAttrs, unsigned(Ints[i].ArgumentAttributes.size())); + switch (Ints[i].ModRef) { + default: break; + case CodeGenIntrinsic::NoMem: + OS << " case " << TargetPrefix << "Intrinsic::" << Ints[i].EnumName + << ":\n"; + break; + } + } + OS << " Attr |= Attribute::ReadNone; // These do not access memory.\n"; + OS << " break;\n"; + for (unsigned i = 0, e = Ints.size(); i != e; ++i) { + switch (Ints[i].ModRef) { + default: break; + case CodeGenIntrinsic::ReadArgMem: + case CodeGenIntrinsic::ReadMem: + OS << " case " << TargetPrefix << "Intrinsic::" << Ints[i].EnumName + << ":\n"; + break; + } + } + OS << " Attr |= Attribute::ReadOnly; // These do not write memory.\n"; + OS << " break;\n"; + OS << " }\n"; + OS << " AttributeWithIndex AWI[" << MaxArgAttrs+1 << "];\n"; + OS << " unsigned NumAttrs = 0;\n"; + OS << " switch (id) {\n"; + OS << " default: break;\n"; + + // Add argument attributes for any intrinsics that have them. + for (unsigned i = 0, e = Ints.size(); i != e; ++i) { + if (Ints[i].ArgumentAttributes.empty()) continue; + + OS << " case " << TargetPrefix << "Intrinsic::" << Ints[i].EnumName + << ":\n"; + + std::vector<std::pair<unsigned, CodeGenIntrinsic::ArgAttribute> > ArgAttrs = + Ints[i].ArgumentAttributes; + // Sort by argument index. + std::sort(ArgAttrs.begin(), ArgAttrs.end()); + + unsigned NumArgsWithAttrs = 0; + + while (!ArgAttrs.empty()) { + unsigned ArgNo = ArgAttrs[0].first; + + OS << " AWI[" << NumArgsWithAttrs++ << "] = AttributeWithIndex::get(" + << ArgNo+1 << ", 0"; + + while (!ArgAttrs.empty() && ArgAttrs[0].first == ArgNo) { + switch (ArgAttrs[0].second) { + default: assert(0 && "Unknown arg attribute"); + case CodeGenIntrinsic::NoCapture: + OS << "|Attribute::NoCapture"; + break; + } + ArgAttrs.erase(ArgAttrs.begin()); + } + OS << ");\n"; + } + + OS << " NumAttrs = " << NumArgsWithAttrs << ";\n"; + OS << " break;\n"; + } + + OS << " }\n"; + OS << " AWI[NumAttrs] = AttributeWithIndex::get(~0, Attr);\n"; + OS << " return AttrListPtr::get(AWI, NumAttrs+1);\n"; + OS << "}\n"; + OS << "#endif // GET_INTRINSIC_ATTRIBUTES\n\n"; +} + +/// EmitModRefBehavior - Determine intrinsic alias analysis mod/ref behavior. +void IntrinsicEmitter:: +EmitModRefBehavior(const std::vector<CodeGenIntrinsic> &Ints, std::ostream &OS){ + OS << "// Determine intrinsic alias analysis mod/ref behavior.\n"; + OS << "#ifdef GET_INTRINSIC_MODREF_BEHAVIOR\n"; + OS << "switch (id) {\n"; + OS << "default:\n return UnknownModRefBehavior;\n"; + for (unsigned i = 0, e = Ints.size(); i != e; ++i) { + if (Ints[i].ModRef == CodeGenIntrinsic::WriteMem) + continue; + OS << "case " << TargetPrefix << "Intrinsic::" << Ints[i].EnumName + << ":\n"; + switch (Ints[i].ModRef) { + default: + assert(false && "Unknown Mod/Ref type!"); + case CodeGenIntrinsic::NoMem: + OS << " return DoesNotAccessMemory;\n"; + break; + case CodeGenIntrinsic::ReadArgMem: + case CodeGenIntrinsic::ReadMem: + OS << " return OnlyReadsMemory;\n"; + break; + case CodeGenIntrinsic::WriteArgMem: + OS << " return AccessesArguments;\n"; + break; + } + } + OS << "}\n"; + OS << "#endif // GET_INTRINSIC_MODREF_BEHAVIOR\n\n"; +} + +void IntrinsicEmitter:: +EmitGCCBuiltinList(const std::vector<CodeGenIntrinsic> &Ints, std::ostream &OS){ + OS << "// Get the GCC builtin that corresponds to an LLVM intrinsic.\n"; + OS << "#ifdef GET_GCC_BUILTIN_NAME\n"; + OS << " switch (F->getIntrinsicID()) {\n"; + OS << " default: BuiltinName = \"\"; break;\n"; + for (unsigned i = 0, e = Ints.size(); i != e; ++i) { + if (!Ints[i].GCCBuiltinName.empty()) { + OS << " case Intrinsic::" << Ints[i].EnumName << ": BuiltinName = \"" + << Ints[i].GCCBuiltinName << "\"; break;\n"; + } + } + OS << " }\n"; + OS << "#endif\n\n"; +} + +/// EmitBuiltinComparisons - Emit comparisons to determine whether the specified +/// sorted range of builtin names is equal to the current builtin. This breaks +/// it down into a simple tree. +/// +/// At this point, we know that all the builtins in the range have the same name +/// for the first 'CharStart' characters. Only the end of the name needs to be +/// discriminated. +typedef std::map<std::string, std::string>::const_iterator StrMapIterator; +static void EmitBuiltinComparisons(StrMapIterator Start, StrMapIterator End, + unsigned CharStart, unsigned Indent, + std::string TargetPrefix, std::ostream &OS) { + if (Start == End) return; // empty range. + + // Determine what, if anything, is the same about all these strings. + std::string CommonString = Start->first; + unsigned NumInRange = 0; + for (StrMapIterator I = Start; I != End; ++I, ++NumInRange) { + // Find the first character that doesn't match. + const std::string &ThisStr = I->first; + unsigned NonMatchChar = CharStart; + while (NonMatchChar < CommonString.size() && + NonMatchChar < ThisStr.size() && + CommonString[NonMatchChar] == ThisStr[NonMatchChar]) + ++NonMatchChar; + // Truncate off pieces that don't match. + CommonString.resize(NonMatchChar); + } + + // Just compare the rest of the string. + if (NumInRange == 1) { + if (CharStart != CommonString.size()) { + OS << std::string(Indent*2, ' ') << "if (!memcmp(BuiltinName"; + if (CharStart) OS << "+" << CharStart; + OS << ", \"" << (CommonString.c_str()+CharStart) << "\", "; + OS << CommonString.size() - CharStart << "))\n"; + ++Indent; + } + OS << std::string(Indent*2, ' ') << "IntrinsicID = " << TargetPrefix + << "Intrinsic::"; + OS << Start->second << ";\n"; + return; + } + + // At this point, we potentially have a common prefix for these builtins, emit + // a check for this common prefix. + if (CommonString.size() != CharStart) { + OS << std::string(Indent*2, ' ') << "if (!memcmp(BuiltinName"; + if (CharStart) OS << "+" << CharStart; + OS << ", \"" << (CommonString.c_str()+CharStart) << "\", "; + OS << CommonString.size()-CharStart << ")) {\n"; + + EmitBuiltinComparisons(Start, End, CommonString.size(), Indent+1, + TargetPrefix, OS); + OS << std::string(Indent*2, ' ') << "}\n"; + return; + } + + // Output a switch on the character that differs across the set. + OS << std::string(Indent*2, ' ') << "switch (BuiltinName[" << CharStart + << "]) {"; + if (CharStart) + OS << " // \"" << std::string(Start->first.begin(), + Start->first.begin()+CharStart) << "\""; + OS << "\n"; + + for (StrMapIterator I = Start; I != End; ) { + char ThisChar = I->first[CharStart]; + OS << std::string(Indent*2, ' ') << "case '" << ThisChar << "':\n"; + // Figure out the range that has this common character. + StrMapIterator NextChar = I; + for (++NextChar; NextChar != End && NextChar->first[CharStart] == ThisChar; + ++NextChar) + /*empty*/; + EmitBuiltinComparisons(I, NextChar, CharStart+1, Indent+1, TargetPrefix,OS); + OS << std::string(Indent*2, ' ') << " break;\n"; + I = NextChar; + } + OS << std::string(Indent*2, ' ') << "}\n"; +} + +/// EmitTargetBuiltins - All of the builtins in the specified map are for the +/// same target, and we already checked it. +static void EmitTargetBuiltins(const std::map<std::string, std::string> &BIM, + const std::string &TargetPrefix, + std::ostream &OS) { + // Rearrange the builtins by length. + std::vector<std::map<std::string, std::string> > BuiltinsByLen; + BuiltinsByLen.reserve(100); + + for (StrMapIterator I = BIM.begin(), E = BIM.end(); I != E; ++I) { + if (I->first.size() >= BuiltinsByLen.size()) + BuiltinsByLen.resize(I->first.size()+1); + BuiltinsByLen[I->first.size()].insert(*I); + } + + // Now that we have all the builtins by their length, emit a switch stmt. + OS << " switch (strlen(BuiltinName)) {\n"; + OS << " default: break;\n"; + for (unsigned i = 0, e = BuiltinsByLen.size(); i != e; ++i) { + if (BuiltinsByLen[i].empty()) continue; + OS << " case " << i << ":\n"; + EmitBuiltinComparisons(BuiltinsByLen[i].begin(), BuiltinsByLen[i].end(), + 0, 3, TargetPrefix, OS); + OS << " break;\n"; + } + OS << " }\n"; +} + + +void IntrinsicEmitter:: +EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints, + std::ostream &OS) { + typedef std::map<std::string, std::map<std::string, std::string> > BIMTy; + BIMTy BuiltinMap; + for (unsigned i = 0, e = Ints.size(); i != e; ++i) { + if (!Ints[i].GCCBuiltinName.empty()) { + // Get the map for this target prefix. + std::map<std::string, std::string> &BIM =BuiltinMap[Ints[i].TargetPrefix]; + + if (!BIM.insert(std::make_pair(Ints[i].GCCBuiltinName, + Ints[i].EnumName)).second) + throw "Intrinsic '" + Ints[i].TheDef->getName() + + "': duplicate GCC builtin name!"; + } + } + + OS << "// Get the LLVM intrinsic that corresponds to a GCC builtin.\n"; + OS << "// This is used by the C front-end. The GCC builtin name is passed\n"; + OS << "// in as BuiltinName, and a target prefix (e.g. 'ppc') is passed\n"; + OS << "// in as TargetPrefix. The result is assigned to 'IntrinsicID'.\n"; + OS << "#ifdef GET_LLVM_INTRINSIC_FOR_GCC_BUILTIN\n"; + + if (TargetOnly) { + OS << "static " << TargetPrefix << "Intrinsic::ID " + << "getIntrinsicForGCCBuiltin(const char " + << "*TargetPrefix, const char *BuiltinName) {\n"; + OS << " " << TargetPrefix << "Intrinsic::ID IntrinsicID = "; + } else { + OS << "Intrinsic::ID Intrinsic::getIntrinsicForGCCBuiltin(const char " + << "*TargetPrefix, const char *BuiltinName) {\n"; + OS << " Intrinsic::ID IntrinsicID = "; + } + + if (TargetOnly) + OS << "(" << TargetPrefix<< "Intrinsic::ID)"; + + OS << "Intrinsic::not_intrinsic;\n"; + + // Note: this could emit significantly better code if we cared. + for (BIMTy::iterator I = BuiltinMap.begin(), E = BuiltinMap.end();I != E;++I){ + OS << " "; + if (!I->first.empty()) + OS << "if (!strcmp(TargetPrefix, \"" << I->first << "\")) "; + else + OS << "/* Target Independent Builtins */ "; + OS << "{\n"; + + // Emit the comparisons for this target prefix. + EmitTargetBuiltins(I->second, TargetPrefix, OS); + OS << " }\n"; + } + OS << " return IntrinsicID;\n"; + OS << "}\n"; + OS << "#endif\n\n"; +} diff --git a/utils/TableGen/IntrinsicEmitter.h b/utils/TableGen/IntrinsicEmitter.h new file mode 100644 index 0000000000000..1619d02242929 --- /dev/null +++ b/utils/TableGen/IntrinsicEmitter.h @@ -0,0 +1,60 @@ +//===- IntrinsicEmitter.h - Generate intrinsic information ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend emits information about intrinsic functions. +// +//===----------------------------------------------------------------------===// + +#ifndef INTRINSIC_EMITTER_H +#define INTRINSIC_EMITTER_H + +#include "CodeGenIntrinsics.h" +#include "TableGenBackend.h" + +namespace llvm { + class IntrinsicEmitter : public TableGenBackend { + RecordKeeper &Records; + bool TargetOnly; + std::string TargetPrefix; + + public: + IntrinsicEmitter(RecordKeeper &R, bool T = false) + : Records(R), TargetOnly(T) {} + + void run(std::ostream &OS); + + void EmitEnumInfo(const std::vector<CodeGenIntrinsic> &Ints, + std::ostream &OS); + + void EmitFnNameRecognizer(const std::vector<CodeGenIntrinsic> &Ints, + std::ostream &OS); + void EmitIntrinsicToNameTable(const std::vector<CodeGenIntrinsic> &Ints, + std::ostream &OS); + void EmitIntrinsicToOverloadTable(const std::vector<CodeGenIntrinsic> &Ints, + std::ostream &OS); + void EmitVerifier(const std::vector<CodeGenIntrinsic> &Ints, + std::ostream &OS); + void EmitGenerator(const std::vector<CodeGenIntrinsic> &Ints, + std::ostream &OS); + void EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, + std::ostream &OS); + void EmitModRefBehavior(const std::vector<CodeGenIntrinsic> &Ints, + std::ostream &OS); + void EmitGCCBuiltinList(const std::vector<CodeGenIntrinsic> &Ints, + std::ostream &OS); + void EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints, + std::ostream &OS); + }; + +} // End llvm namespace + +#endif + + + diff --git a/utils/TableGen/LLVMCConfigurationEmitter.cpp b/utils/TableGen/LLVMCConfigurationEmitter.cpp new file mode 100644 index 0000000000000..d7e85507141e4 --- /dev/null +++ b/utils/TableGen/LLVMCConfigurationEmitter.cpp @@ -0,0 +1,2131 @@ +//===- LLVMCConfigurationEmitter.cpp - Generate LLVMC config ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open +// Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend is responsible for emitting LLVMC configuration code. +// +//===----------------------------------------------------------------------===// + +#include "LLVMCConfigurationEmitter.h" +#include "Record.h" + +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Support/Streams.h" + +#include <algorithm> +#include <cassert> +#include <functional> +#include <stdexcept> +#include <string> +#include <typeinfo> + +using namespace llvm; + +namespace { + +//===----------------------------------------------------------------------===// +/// Typedefs + +typedef std::vector<Record*> RecordVector; +typedef std::vector<std::string> StrVector; + +//===----------------------------------------------------------------------===// +/// Constants + +// Indentation strings. +const char * Indent1 = " "; +const char * Indent2 = " "; +const char * Indent3 = " "; + +// Default help string. +const char * DefaultHelpString = "NO HELP MESSAGE PROVIDED"; + +// Name for the "sink" option. +const char * SinkOptionName = "AutoGeneratedSinkOption"; + +//===----------------------------------------------------------------------===// +/// Helper functions + +/// Id - An 'identity' function object. +struct Id { + template<typename T> + void operator()(const T&) const { + } +}; + +int InitPtrToInt(const Init* ptr) { + const IntInit& val = dynamic_cast<const IntInit&>(*ptr); + return val.getValue(); +} + +const std::string& InitPtrToString(const Init* ptr) { + const StringInit& val = dynamic_cast<const StringInit&>(*ptr); + return val.getValue(); +} + +const ListInit& InitPtrToList(const Init* ptr) { + const ListInit& val = dynamic_cast<const ListInit&>(*ptr); + return val; +} + +const DagInit& InitPtrToDag(const Init* ptr) { + const DagInit& val = dynamic_cast<const DagInit&>(*ptr); + return val; +} + +// checkNumberOfArguments - Ensure that the number of args in d is +// less than or equal to min_arguments, otherwise throw an exception. +void checkNumberOfArguments (const DagInit* d, unsigned min_arguments) { + if (!d || d->getNumArgs() < min_arguments) + throw d->getOperator()->getAsString() + + ": too few arguments!"; +} + +// isDagEmpty - is this DAG marked with an empty marker? +bool isDagEmpty (const DagInit* d) { + return d->getOperator()->getAsString() == "empty"; +} + +// EscapeVariableName - Escape commas and other symbols not allowed +// in the C++ variable names. Makes it possible to use options named +// like "Wa," (useful for prefix options). +std::string EscapeVariableName(const std::string& Var) { + std::string ret; + for (unsigned i = 0; i != Var.size(); ++i) { + char cur_char = Var[i]; + if (cur_char == ',') { + ret += "_comma_"; + } + else if (cur_char == '+') { + ret += "_plus_"; + } + else if (cur_char == '-') { + ret += "_dash_"; + } + else { + ret.push_back(cur_char); + } + } + return ret; +} + +/// oneOf - Does the input string contain this character? +bool oneOf(const char* lst, char c) { + while (*lst) { + if (*lst++ == c) + return true; + } + return false; +} + +template <class I, class S> +void checkedIncrement(I& P, I E, S ErrorString) { + ++P; + if (P == E) + throw ErrorString; +} + +//===----------------------------------------------------------------------===// +/// Back-end specific code + + +/// OptionType - One of six different option types. See the +/// documentation for detailed description of differences. +namespace OptionType { + enum OptionType { Alias, Switch, Parameter, ParameterList, + Prefix, PrefixList}; + +bool IsList (OptionType t) { + return (t == ParameterList || t == PrefixList); +} + +bool IsSwitch (OptionType t) { + return (t == Switch); +} + +bool IsParameter (OptionType t) { + return (t == Parameter || t == Prefix); +} + +} + +OptionType::OptionType stringToOptionType(const std::string& T) { + if (T == "alias_option") + return OptionType::Alias; + else if (T == "switch_option") + return OptionType::Switch; + else if (T == "parameter_option") + return OptionType::Parameter; + else if (T == "parameter_list_option") + return OptionType::ParameterList; + else if (T == "prefix_option") + return OptionType::Prefix; + else if (T == "prefix_list_option") + return OptionType::PrefixList; + else + throw "Unknown option type: " + T + '!'; +} + +namespace OptionDescriptionFlags { + enum OptionDescriptionFlags { Required = 0x1, Hidden = 0x2, + ReallyHidden = 0x4, Extern = 0x8, + OneOrMore = 0x10, ZeroOrOne = 0x20 }; +} + +/// OptionDescription - Represents data contained in a single +/// OptionList entry. +struct OptionDescription { + OptionType::OptionType Type; + std::string Name; + unsigned Flags; + std::string Help; + unsigned MultiVal; + + OptionDescription(OptionType::OptionType t = OptionType::Switch, + const std::string& n = "", + const std::string& h = DefaultHelpString) + : Type(t), Name(n), Flags(0x0), Help(h), MultiVal(1) + {} + + /// GenTypeDeclaration - Returns the C++ variable type of this + /// option. + const char* GenTypeDeclaration() const; + + /// GenVariableName - Returns the variable name used in the + /// generated C++ code. + std::string GenVariableName() const; + + /// Merge - Merge two option descriptions. + void Merge (const OptionDescription& other); + + // Misc convenient getters/setters. + + bool isAlias() const; + + bool isMultiVal() const; + + bool isExtern() const; + void setExtern(); + + bool isRequired() const; + void setRequired(); + + bool isOneOrMore() const; + void setOneOrMore(); + + bool isZeroOrOne() const; + void setZeroOrOne(); + + bool isHidden() const; + void setHidden(); + + bool isReallyHidden() const; + void setReallyHidden(); + +}; + +void OptionDescription::Merge (const OptionDescription& other) +{ + if (other.Type != Type) + throw "Conflicting definitions for the option " + Name + "!"; + + if (Help == other.Help || Help == DefaultHelpString) + Help = other.Help; + else if (other.Help != DefaultHelpString) { + llvm::cerr << "Warning: several different help strings" + " defined for option " + Name + "\n"; + } + + Flags |= other.Flags; +} + +bool OptionDescription::isAlias() const { + return Type == OptionType::Alias; +} + +bool OptionDescription::isMultiVal() const { + return MultiVal > 1; +} + +bool OptionDescription::isExtern() const { + return Flags & OptionDescriptionFlags::Extern; +} +void OptionDescription::setExtern() { + Flags |= OptionDescriptionFlags::Extern; +} + +bool OptionDescription::isRequired() const { + return Flags & OptionDescriptionFlags::Required; +} +void OptionDescription::setRequired() { + Flags |= OptionDescriptionFlags::Required; +} + +bool OptionDescription::isOneOrMore() const { + return Flags & OptionDescriptionFlags::OneOrMore; +} +void OptionDescription::setOneOrMore() { + Flags |= OptionDescriptionFlags::OneOrMore; +} + +bool OptionDescription::isZeroOrOne() const { + return Flags & OptionDescriptionFlags::ZeroOrOne; +} +void OptionDescription::setZeroOrOne() { + Flags |= OptionDescriptionFlags::ZeroOrOne; +} + +bool OptionDescription::isHidden() const { + return Flags & OptionDescriptionFlags::Hidden; +} +void OptionDescription::setHidden() { + Flags |= OptionDescriptionFlags::Hidden; +} + +bool OptionDescription::isReallyHidden() const { + return Flags & OptionDescriptionFlags::ReallyHidden; +} +void OptionDescription::setReallyHidden() { + Flags |= OptionDescriptionFlags::ReallyHidden; +} + +const char* OptionDescription::GenTypeDeclaration() const { + switch (Type) { + case OptionType::Alias: + return "cl::alias"; + case OptionType::PrefixList: + case OptionType::ParameterList: + return "cl::list<std::string>"; + case OptionType::Switch: + return "cl::opt<bool>"; + case OptionType::Parameter: + case OptionType::Prefix: + default: + return "cl::opt<std::string>"; + } +} + +std::string OptionDescription::GenVariableName() const { + const std::string& EscapedName = EscapeVariableName(Name); + switch (Type) { + case OptionType::Alias: + return "AutoGeneratedAlias_" + EscapedName; + case OptionType::PrefixList: + case OptionType::ParameterList: + return "AutoGeneratedList_" + EscapedName; + case OptionType::Switch: + return "AutoGeneratedSwitch_" + EscapedName; + case OptionType::Prefix: + case OptionType::Parameter: + default: + return "AutoGeneratedParameter_" + EscapedName; + } +} + +/// OptionDescriptions - An OptionDescription array plus some helper +/// functions. +class OptionDescriptions { + typedef StringMap<OptionDescription> container_type; + + /// Descriptions - A list of OptionDescriptions. + container_type Descriptions; + +public: + /// FindOption - exception-throwing wrapper for find(). + const OptionDescription& FindOption(const std::string& OptName) const; + + /// insertDescription - Insert new OptionDescription into + /// OptionDescriptions list + void InsertDescription (const OptionDescription& o); + + // Support for STL-style iteration + typedef container_type::const_iterator const_iterator; + const_iterator begin() const { return Descriptions.begin(); } + const_iterator end() const { return Descriptions.end(); } +}; + +const OptionDescription& +OptionDescriptions::FindOption(const std::string& OptName) const +{ + const_iterator I = Descriptions.find(OptName); + if (I != Descriptions.end()) + return I->second; + else + throw OptName + ": no such option!"; +} + +void OptionDescriptions::InsertDescription (const OptionDescription& o) +{ + container_type::iterator I = Descriptions.find(o.Name); + if (I != Descriptions.end()) { + OptionDescription& D = I->second; + D.Merge(o); + } + else { + Descriptions[o.Name] = o; + } +} + +/// HandlerTable - A base class for function objects implemented as +/// 'tables of handlers'. +template <class T> +class HandlerTable { +protected: + // Implementation details. + + /// Handler - + typedef void (T::* Handler) (const DagInit*); + /// HandlerMap - A map from property names to property handlers + typedef StringMap<Handler> HandlerMap; + + static HandlerMap Handlers_; + static bool staticMembersInitialized_; + + T* childPtr; +public: + + HandlerTable(T* cp) : childPtr(cp) + {} + + /// operator() - Just forwards to the corresponding property + /// handler. + void operator() (Init* i) { + const DagInit& property = InitPtrToDag(i); + const std::string& property_name = property.getOperator()->getAsString(); + typename HandlerMap::iterator method = Handlers_.find(property_name); + + if (method != Handlers_.end()) { + Handler h = method->second; + (childPtr->*h)(&property); + } + else { + throw "No handler found for property " + property_name + "!"; + } + } + + void AddHandler(const char* Property, Handler Handl) { + Handlers_[Property] = Handl; + } +}; + +template <class T> typename HandlerTable<T>::HandlerMap +HandlerTable<T>::Handlers_; +template <class T> bool HandlerTable<T>::staticMembersInitialized_ = false; + + +/// CollectOptionProperties - Function object for iterating over an +/// option property list. +class CollectOptionProperties : public HandlerTable<CollectOptionProperties> { +private: + + /// optDescs_ - OptionDescriptions table. This is where the + /// information is stored. + OptionDescription& optDesc_; + +public: + + explicit CollectOptionProperties(OptionDescription& OD) + : HandlerTable<CollectOptionProperties>(this), optDesc_(OD) + { + if (!staticMembersInitialized_) { + AddHandler("extern", &CollectOptionProperties::onExtern); + AddHandler("help", &CollectOptionProperties::onHelp); + AddHandler("hidden", &CollectOptionProperties::onHidden); + AddHandler("multi_val", &CollectOptionProperties::onMultiVal); + AddHandler("one_or_more", &CollectOptionProperties::onOneOrMore); + AddHandler("really_hidden", &CollectOptionProperties::onReallyHidden); + AddHandler("required", &CollectOptionProperties::onRequired); + AddHandler("zero_or_one", &CollectOptionProperties::onZeroOrOne); + + staticMembersInitialized_ = true; + } + } + +private: + + /// Option property handlers -- + /// Methods that handle option properties such as (help) or (hidden). + + void onExtern (const DagInit* d) { + checkNumberOfArguments(d, 0); + optDesc_.setExtern(); + } + + void onHelp (const DagInit* d) { + checkNumberOfArguments(d, 1); + optDesc_.Help = InitPtrToString(d->getArg(0)); + } + + void onHidden (const DagInit* d) { + checkNumberOfArguments(d, 0); + optDesc_.setHidden(); + } + + void onReallyHidden (const DagInit* d) { + checkNumberOfArguments(d, 0); + optDesc_.setReallyHidden(); + } + + void onRequired (const DagInit* d) { + checkNumberOfArguments(d, 0); + if (optDesc_.isOneOrMore()) + throw std::string("An option can't have both (required) " + "and (one_or_more) properties!"); + optDesc_.setRequired(); + } + + void onOneOrMore (const DagInit* d) { + checkNumberOfArguments(d, 0); + if (optDesc_.isRequired() || optDesc_.isZeroOrOne()) + throw std::string("Only one of (required), (zero_or_one) or " + "(one_or_more) properties is allowed!"); + if (!OptionType::IsList(optDesc_.Type)) + llvm::cerr << "Warning: specifying the 'one_or_more' property " + "on a non-list option will have no effect.\n"; + optDesc_.setOneOrMore(); + } + + void onZeroOrOne (const DagInit* d) { + checkNumberOfArguments(d, 0); + if (optDesc_.isRequired() || optDesc_.isOneOrMore()) + throw std::string("Only one of (required), (zero_or_one) or " + "(one_or_more) properties is allowed!"); + if (!OptionType::IsList(optDesc_.Type)) + llvm::cerr << "Warning: specifying the 'zero_or_one' property" + "on a non-list option will have no effect.\n"; + optDesc_.setZeroOrOne(); + } + + void onMultiVal (const DagInit* d) { + checkNumberOfArguments(d, 1); + int val = InitPtrToInt(d->getArg(0)); + if (val < 2) + throw std::string("Error in the 'multi_val' property: " + "the value must be greater than 1!"); + if (!OptionType::IsList(optDesc_.Type)) + throw std::string("The multi_val property is valid only " + "on list options!"); + optDesc_.MultiVal = val; + } + +}; + +/// AddOption - A function object that is applied to every option +/// description. Used by CollectOptionDescriptions. +class AddOption { +private: + OptionDescriptions& OptDescs_; + +public: + explicit AddOption(OptionDescriptions& OD) : OptDescs_(OD) + {} + + void operator()(const Init* i) { + const DagInit& d = InitPtrToDag(i); + checkNumberOfArguments(&d, 1); + + const OptionType::OptionType Type = + stringToOptionType(d.getOperator()->getAsString()); + const std::string& Name = InitPtrToString(d.getArg(0)); + + OptionDescription OD(Type, Name); + + if (!OD.isExtern()) + checkNumberOfArguments(&d, 2); + + if (OD.isAlias()) { + // Aliases store the aliased option name in the 'Help' field. + OD.Help = InitPtrToString(d.getArg(1)); + } + else if (!OD.isExtern()) { + processOptionProperties(&d, OD); + } + OptDescs_.InsertDescription(OD); + } + +private: + /// processOptionProperties - Go through the list of option + /// properties and call a corresponding handler for each. + static void processOptionProperties (const DagInit* d, OptionDescription& o) { + checkNumberOfArguments(d, 2); + DagInit::const_arg_iterator B = d->arg_begin(); + // Skip the first argument: it's always the option name. + ++B; + std::for_each(B, d->arg_end(), CollectOptionProperties(o)); + } + +}; + +/// CollectOptionDescriptions - Collects option properties from all +/// OptionLists. +void CollectOptionDescriptions (RecordVector::const_iterator B, + RecordVector::const_iterator E, + OptionDescriptions& OptDescs) +{ + // For every OptionList: + for (; B!=E; ++B) { + RecordVector::value_type T = *B; + // Throws an exception if the value does not exist. + ListInit* PropList = T->getValueAsListInit("options"); + + // For every option description in this list: + // collect the information and + std::for_each(PropList->begin(), PropList->end(), AddOption(OptDescs)); + } +} + +// Tool information record + +namespace ToolFlags { + enum ToolFlags { Join = 0x1, Sink = 0x2 }; +} + +struct ToolDescription : public RefCountedBase<ToolDescription> { + std::string Name; + Init* CmdLine; + Init* Actions; + StrVector InLanguage; + std::string OutLanguage; + std::string OutputSuffix; + unsigned Flags; + + // Various boolean properties + void setSink() { Flags |= ToolFlags::Sink; } + bool isSink() const { return Flags & ToolFlags::Sink; } + void setJoin() { Flags |= ToolFlags::Join; } + bool isJoin() const { return Flags & ToolFlags::Join; } + + // Default ctor here is needed because StringMap can only store + // DefaultConstructible objects + ToolDescription() : CmdLine(0), Actions(0), Flags(0) {} + ToolDescription (const std::string& n) + : Name(n), CmdLine(0), Actions(0), Flags(0) + {} +}; + +/// ToolDescriptions - A list of Tool information records. +typedef std::vector<IntrusiveRefCntPtr<ToolDescription> > ToolDescriptions; + + +/// CollectToolProperties - Function object for iterating over a list of +/// tool property records. +class CollectToolProperties : public HandlerTable<CollectToolProperties> { +private: + + /// toolDesc_ - Properties of the current Tool. This is where the + /// information is stored. + ToolDescription& toolDesc_; + +public: + + explicit CollectToolProperties (ToolDescription& d) + : HandlerTable<CollectToolProperties>(this) , toolDesc_(d) + { + if (!staticMembersInitialized_) { + + AddHandler("actions", &CollectToolProperties::onActions); + AddHandler("cmd_line", &CollectToolProperties::onCmdLine); + AddHandler("in_language", &CollectToolProperties::onInLanguage); + AddHandler("join", &CollectToolProperties::onJoin); + AddHandler("out_language", &CollectToolProperties::onOutLanguage); + AddHandler("output_suffix", &CollectToolProperties::onOutputSuffix); + AddHandler("sink", &CollectToolProperties::onSink); + + staticMembersInitialized_ = true; + } + } + +private: + + /// Property handlers -- + /// Functions that extract information about tool properties from + /// DAG representation. + + void onActions (const DagInit* d) { + checkNumberOfArguments(d, 1); + Init* Case = d->getArg(0); + if (typeid(*Case) != typeid(DagInit) || + static_cast<DagInit*>(Case)->getOperator()->getAsString() != "case") + throw + std::string("The argument to (actions) should be a 'case' construct!"); + toolDesc_.Actions = Case; + } + + void onCmdLine (const DagInit* d) { + checkNumberOfArguments(d, 1); + toolDesc_.CmdLine = d->getArg(0); + } + + void onInLanguage (const DagInit* d) { + checkNumberOfArguments(d, 1); + Init* arg = d->getArg(0); + + // Find out the argument's type. + if (typeid(*arg) == typeid(StringInit)) { + // It's a string. + toolDesc_.InLanguage.push_back(InitPtrToString(arg)); + } + else { + // It's a list. + const ListInit& lst = InitPtrToList(arg); + StrVector& out = toolDesc_.InLanguage; + + // Copy strings to the output vector. + for (ListInit::const_iterator B = lst.begin(), E = lst.end(); + B != E; ++B) { + out.push_back(InitPtrToString(*B)); + } + + // Remove duplicates. + std::sort(out.begin(), out.end()); + StrVector::iterator newE = std::unique(out.begin(), out.end()); + out.erase(newE, out.end()); + } + } + + void onJoin (const DagInit* d) { + checkNumberOfArguments(d, 0); + toolDesc_.setJoin(); + } + + void onOutLanguage (const DagInit* d) { + checkNumberOfArguments(d, 1); + toolDesc_.OutLanguage = InitPtrToString(d->getArg(0)); + } + + void onOutputSuffix (const DagInit* d) { + checkNumberOfArguments(d, 1); + toolDesc_.OutputSuffix = InitPtrToString(d->getArg(0)); + } + + void onSink (const DagInit* d) { + checkNumberOfArguments(d, 0); + toolDesc_.setSink(); + } + +}; + +/// CollectToolDescriptions - Gather information about tool properties +/// from the parsed TableGen data (basically a wrapper for the +/// CollectToolProperties function object). +void CollectToolDescriptions (RecordVector::const_iterator B, + RecordVector::const_iterator E, + ToolDescriptions& ToolDescs) +{ + // Iterate over a properties list of every Tool definition + for (;B!=E;++B) { + const Record* T = *B; + // Throws an exception if the value does not exist. + ListInit* PropList = T->getValueAsListInit("properties"); + + IntrusiveRefCntPtr<ToolDescription> + ToolDesc(new ToolDescription(T->getName())); + + std::for_each(PropList->begin(), PropList->end(), + CollectToolProperties(*ToolDesc)); + ToolDescs.push_back(ToolDesc); + } +} + +/// FillInEdgeVector - Merge all compilation graph definitions into +/// one single edge list. +void FillInEdgeVector(RecordVector::const_iterator B, + RecordVector::const_iterator E, RecordVector& Out) { + for (; B != E; ++B) { + const ListInit* edges = (*B)->getValueAsListInit("edges"); + + for (unsigned i = 0; i < edges->size(); ++i) + Out.push_back(edges->getElementAsRecord(i)); + } +} + +/// CalculatePriority - Calculate the priority of this plugin. +int CalculatePriority(RecordVector::const_iterator B, + RecordVector::const_iterator E) { + int total = 0; + for (; B!=E; ++B) { + total += static_cast<int>((*B)->getValueAsInt("priority")); + } + return total; +} + +/// NotInGraph - Helper function object for FilterNotInGraph. +struct NotInGraph { +private: + const llvm::StringSet<>& ToolsInGraph_; + +public: + NotInGraph(const llvm::StringSet<>& ToolsInGraph) + : ToolsInGraph_(ToolsInGraph) + {} + + bool operator()(const IntrusiveRefCntPtr<ToolDescription>& x) { + return (ToolsInGraph_.count(x->Name) == 0); + } +}; + +/// FilterNotInGraph - Filter out from ToolDescs all Tools not +/// mentioned in the compilation graph definition. +void FilterNotInGraph (const RecordVector& EdgeVector, + ToolDescriptions& ToolDescs) { + + // List all tools mentioned in the graph. + llvm::StringSet<> ToolsInGraph; + + for (RecordVector::const_iterator B = EdgeVector.begin(), + E = EdgeVector.end(); B != E; ++B) { + + const Record* Edge = *B; + const std::string& NodeA = Edge->getValueAsString("a"); + const std::string& NodeB = Edge->getValueAsString("b"); + + if (NodeA != "root") + ToolsInGraph.insert(NodeA); + ToolsInGraph.insert(NodeB); + } + + // Filter ToolPropertiesList. + ToolDescriptions::iterator new_end = + std::remove_if(ToolDescs.begin(), ToolDescs.end(), + NotInGraph(ToolsInGraph)); + ToolDescs.erase(new_end, ToolDescs.end()); +} + +/// FillInToolToLang - Fills in two tables that map tool names to +/// (input, output) languages. Helper function used by TypecheckGraph(). +void FillInToolToLang (const ToolDescriptions& ToolDescs, + StringMap<StringSet<> >& ToolToInLang, + StringMap<std::string>& ToolToOutLang) { + for (ToolDescriptions::const_iterator B = ToolDescs.begin(), + E = ToolDescs.end(); B != E; ++B) { + const ToolDescription& D = *(*B); + for (StrVector::const_iterator B = D.InLanguage.begin(), + E = D.InLanguage.end(); B != E; ++B) + ToolToInLang[D.Name].insert(*B); + ToolToOutLang[D.Name] = D.OutLanguage; + } +} + +/// TypecheckGraph - Check that names for output and input languages +/// on all edges do match. This doesn't do much when the information +/// about the whole graph is not available (i.e. when compiling most +/// plugins). +void TypecheckGraph (const RecordVector& EdgeVector, + const ToolDescriptions& ToolDescs) { + StringMap<StringSet<> > ToolToInLang; + StringMap<std::string> ToolToOutLang; + + FillInToolToLang(ToolDescs, ToolToInLang, ToolToOutLang); + StringMap<std::string>::iterator IAE = ToolToOutLang.end(); + StringMap<StringSet<> >::iterator IBE = ToolToInLang.end(); + + for (RecordVector::const_iterator B = EdgeVector.begin(), + E = EdgeVector.end(); B != E; ++B) { + const Record* Edge = *B; + const std::string& NodeA = Edge->getValueAsString("a"); + const std::string& NodeB = Edge->getValueAsString("b"); + StringMap<std::string>::iterator IA = ToolToOutLang.find(NodeA); + StringMap<StringSet<> >::iterator IB = ToolToInLang.find(NodeB); + + if (NodeA != "root") { + if (IA != IAE && IB != IBE && IB->second.count(IA->second) == 0) + throw "Edge " + NodeA + "->" + NodeB + + ": output->input language mismatch"; + } + + if (NodeB == "root") + throw std::string("Edges back to the root are not allowed!"); + } +} + +/// WalkCase - Walks the 'case' expression DAG and invokes +/// TestCallback on every test, and StatementCallback on every +/// statement. Handles 'case' nesting, but not the 'and' and 'or' +/// combinators. +// TODO: Re-implement EmitCaseConstructHandler on top of this function? +template <typename F1, typename F2> +void WalkCase(Init* Case, F1 TestCallback, F2 StatementCallback) { + const DagInit& d = InitPtrToDag(Case); + bool even = false; + for (DagInit::const_arg_iterator B = d.arg_begin(), E = d.arg_end(); + B != E; ++B) { + Init* arg = *B; + if (even && dynamic_cast<DagInit*>(arg) + && static_cast<DagInit*>(arg)->getOperator()->getAsString() == "case") + WalkCase(arg, TestCallback, StatementCallback); + else if (!even) + TestCallback(arg); + else + StatementCallback(arg); + even = !even; + } +} + +/// ExtractOptionNames - A helper function object used by +/// CheckForSuperfluousOptions() to walk the 'case' DAG. +class ExtractOptionNames { + llvm::StringSet<>& OptionNames_; + + void processDag(const Init* Statement) { + const DagInit& Stmt = InitPtrToDag(Statement); + const std::string& ActionName = Stmt.getOperator()->getAsString(); + if (ActionName == "forward" || ActionName == "forward_as" || + ActionName == "unpack_values" || ActionName == "switch_on" || + ActionName == "parameter_equals" || ActionName == "element_in_list" || + ActionName == "not_empty" || ActionName == "empty") { + checkNumberOfArguments(&Stmt, 1); + const std::string& Name = InitPtrToString(Stmt.getArg(0)); + OptionNames_.insert(Name); + } + else if (ActionName == "and" || ActionName == "or") { + for (unsigned i = 0, NumArgs = Stmt.getNumArgs(); i < NumArgs; ++i) { + this->processDag(Stmt.getArg(i)); + } + } + } + +public: + ExtractOptionNames(llvm::StringSet<>& OptionNames) : OptionNames_(OptionNames) + {} + + void operator()(const Init* Statement) { + if (typeid(*Statement) == typeid(ListInit)) { + const ListInit& DagList = *static_cast<const ListInit*>(Statement); + for (ListInit::const_iterator B = DagList.begin(), E = DagList.end(); + B != E; ++B) + this->processDag(*B); + } + else { + this->processDag(Statement); + } + } +}; + +/// CheckForSuperfluousOptions - Check that there are no side +/// effect-free options (specified only in the OptionList). Otherwise, +/// output a warning. +void CheckForSuperfluousOptions (const RecordVector& Edges, + const ToolDescriptions& ToolDescs, + const OptionDescriptions& OptDescs) { + llvm::StringSet<> nonSuperfluousOptions; + + // Add all options mentioned in the ToolDesc.Actions to the set of + // non-superfluous options. + for (ToolDescriptions::const_iterator B = ToolDescs.begin(), + E = ToolDescs.end(); B != E; ++B) { + const ToolDescription& TD = *(*B); + ExtractOptionNames Callback(nonSuperfluousOptions); + if (TD.Actions) + WalkCase(TD.Actions, Callback, Callback); + } + + // Add all options mentioned in the 'case' clauses of the + // OptionalEdges of the compilation graph to the set of + // non-superfluous options. + for (RecordVector::const_iterator B = Edges.begin(), E = Edges.end(); + B != E; ++B) { + const Record* Edge = *B; + DagInit* Weight = Edge->getValueAsDag("weight"); + + if (!isDagEmpty(Weight)) + WalkCase(Weight, ExtractOptionNames(nonSuperfluousOptions), Id()); + } + + // Check that all options in OptDescs belong to the set of + // non-superfluous options. + for (OptionDescriptions::const_iterator B = OptDescs.begin(), + E = OptDescs.end(); B != E; ++B) { + const OptionDescription& Val = B->second; + if (!nonSuperfluousOptions.count(Val.Name) + && Val.Type != OptionType::Alias) + llvm::cerr << "Warning: option '-" << Val.Name << "' has no effect! " + "Probable cause: this option is specified only in the OptionList.\n"; + } +} + +/// EmitCaseTest1Arg - Helper function used by +/// EmitCaseConstructHandler. +bool EmitCaseTest1Arg(const std::string& TestName, + const DagInit& d, + const OptionDescriptions& OptDescs, + std::ostream& O) { + checkNumberOfArguments(&d, 1); + const std::string& OptName = InitPtrToString(d.getArg(0)); + + if (TestName == "switch_on") { + const OptionDescription& OptDesc = OptDescs.FindOption(OptName); + if (!OptionType::IsSwitch(OptDesc.Type)) + throw OptName + ": incorrect option type - should be a switch!"; + O << OptDesc.GenVariableName(); + return true; + } else if (TestName == "input_languages_contain") { + O << "InLangs.count(\"" << OptName << "\") != 0"; + return true; + } else if (TestName == "in_language") { + // This works only for single-argument Tool::GenerateAction. Join + // tools can process several files in different languages simultaneously. + + // TODO: make this work with Edge::Weight (if possible). + O << "LangMap.GetLanguage(inFile) == \"" << OptName << '\"'; + return true; + } else if (TestName == "not_empty" || TestName == "empty") { + const char* Test = (TestName == "empty") ? "" : "!"; + + if (OptName == "o") { + O << Test << "OutputFilename.empty()"; + return true; + } + else { + const OptionDescription& OptDesc = OptDescs.FindOption(OptName); + if (OptionType::IsSwitch(OptDesc.Type)) + throw OptName + + ": incorrect option type - should be a list or parameter!"; + O << Test << OptDesc.GenVariableName() << ".empty()"; + return true; + } + } + + return false; +} + +/// EmitCaseTest2Args - Helper function used by +/// EmitCaseConstructHandler. +bool EmitCaseTest2Args(const std::string& TestName, + const DagInit& d, + const char* IndentLevel, + const OptionDescriptions& OptDescs, + std::ostream& O) { + checkNumberOfArguments(&d, 2); + const std::string& OptName = InitPtrToString(d.getArg(0)); + const std::string& OptArg = InitPtrToString(d.getArg(1)); + const OptionDescription& OptDesc = OptDescs.FindOption(OptName); + + if (TestName == "parameter_equals") { + if (!OptionType::IsParameter(OptDesc.Type)) + throw OptName + ": incorrect option type - should be a parameter!"; + O << OptDesc.GenVariableName() << " == \"" << OptArg << "\""; + return true; + } + else if (TestName == "element_in_list") { + if (!OptionType::IsList(OptDesc.Type)) + throw OptName + ": incorrect option type - should be a list!"; + const std::string& VarName = OptDesc.GenVariableName(); + O << "std::find(" << VarName << ".begin(),\n" + << IndentLevel << Indent1 << VarName << ".end(), \"" + << OptArg << "\") != " << VarName << ".end()"; + return true; + } + + return false; +} + +// Forward declaration. +// EmitLogicalOperationTest and EmitCaseTest are mutually recursive. +void EmitCaseTest(const DagInit& d, const char* IndentLevel, + const OptionDescriptions& OptDescs, + std::ostream& O); + +/// EmitLogicalOperationTest - Helper function used by +/// EmitCaseConstructHandler. +void EmitLogicalOperationTest(const DagInit& d, const char* LogicOp, + const char* IndentLevel, + const OptionDescriptions& OptDescs, + std::ostream& O) { + O << '('; + for (unsigned j = 0, NumArgs = d.getNumArgs(); j < NumArgs; ++j) { + const DagInit& InnerTest = InitPtrToDag(d.getArg(j)); + EmitCaseTest(InnerTest, IndentLevel, OptDescs, O); + if (j != NumArgs - 1) + O << ")\n" << IndentLevel << Indent1 << ' ' << LogicOp << " ("; + else + O << ')'; + } +} + +/// EmitCaseTest - Helper function used by EmitCaseConstructHandler. +void EmitCaseTest(const DagInit& d, const char* IndentLevel, + const OptionDescriptions& OptDescs, + std::ostream& O) { + const std::string& TestName = d.getOperator()->getAsString(); + + if (TestName == "and") + EmitLogicalOperationTest(d, "&&", IndentLevel, OptDescs, O); + else if (TestName == "or") + EmitLogicalOperationTest(d, "||", IndentLevel, OptDescs, O); + else if (EmitCaseTest1Arg(TestName, d, OptDescs, O)) + return; + else if (EmitCaseTest2Args(TestName, d, IndentLevel, OptDescs, O)) + return; + else + throw TestName + ": unknown edge property!"; +} + +// Emit code that handles the 'case' construct. +// Takes a function object that should emit code for every case clause. +// Callback's type is +// void F(Init* Statement, const char* IndentLevel, std::ostream& O). +template <typename F> +void EmitCaseConstructHandler(const Init* Dag, const char* IndentLevel, + F Callback, bool EmitElseIf, + const OptionDescriptions& OptDescs, + std::ostream& O) { + const DagInit* d = &InitPtrToDag(Dag); + if (d->getOperator()->getAsString() != "case") + throw std::string("EmitCaseConstructHandler should be invoked" + " only on 'case' expressions!"); + + unsigned numArgs = d->getNumArgs(); + if (d->getNumArgs() < 2) + throw "There should be at least one clause in the 'case' expression:\n" + + d->getAsString(); + + for (unsigned i = 0; i != numArgs; ++i) { + const DagInit& Test = InitPtrToDag(d->getArg(i)); + + // Emit the test. + if (Test.getOperator()->getAsString() == "default") { + if (i+2 != numArgs) + throw std::string("The 'default' clause should be the last in the" + "'case' construct!"); + O << IndentLevel << "else {\n"; + } + else { + O << IndentLevel << ((i != 0 && EmitElseIf) ? "else if (" : "if ("); + EmitCaseTest(Test, IndentLevel, OptDescs, O); + O << ") {\n"; + } + + // Emit the corresponding statement. + ++i; + if (i == numArgs) + throw "Case construct handler: no corresponding action " + "found for the test " + Test.getAsString() + '!'; + + Init* arg = d->getArg(i); + const DagInit* nd = dynamic_cast<DagInit*>(arg); + if (nd && (nd->getOperator()->getAsString() == "case")) { + // Handle the nested 'case'. + EmitCaseConstructHandler(nd, (std::string(IndentLevel) + Indent1).c_str(), + Callback, EmitElseIf, OptDescs, O); + } + else { + Callback(arg, (std::string(IndentLevel) + Indent1).c_str(), O); + } + O << IndentLevel << "}\n"; + } +} + +/// TokenizeCmdline - converts from "$CALL(HookName, 'Arg1', 'Arg2')/path" to +/// ["$CALL(", "HookName", "Arg1", "Arg2", ")/path"] . +/// Helper function used by EmitCmdLineVecFill and. +void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) { + const char* Delimiters = " \t\n\v\f\r"; + enum TokenizerState + { Normal, SpecialCommand, InsideSpecialCommand, InsideQuotationMarks } + cur_st = Normal; + Out.push_back(""); + + std::string::size_type B = CmdLine.find_first_not_of(Delimiters), + E = CmdLine.size(); + if (B == std::string::npos) + throw "Empty command-line string!"; + for (; B != E; ++B) { + char cur_ch = CmdLine[B]; + + switch (cur_st) { + case Normal: + if (cur_ch == '$') { + cur_st = SpecialCommand; + break; + } + if (oneOf(Delimiters, cur_ch)) { + // Skip whitespace + B = CmdLine.find_first_not_of(Delimiters, B); + if (B == std::string::npos) { + B = E-1; + continue; + } + --B; + Out.push_back(""); + continue; + } + break; + + + case SpecialCommand: + if (oneOf(Delimiters, cur_ch)) { + cur_st = Normal; + Out.push_back(""); + continue; + } + if (cur_ch == '(') { + Out.push_back(""); + cur_st = InsideSpecialCommand; + continue; + } + break; + + case InsideSpecialCommand: + if (oneOf(Delimiters, cur_ch)) { + continue; + } + if (cur_ch == '\'') { + cur_st = InsideQuotationMarks; + Out.push_back(""); + continue; + } + if (cur_ch == ')') { + cur_st = Normal; + Out.push_back(""); + } + if (cur_ch == ',') { + continue; + } + + break; + + case InsideQuotationMarks: + if (cur_ch == '\'') { + cur_st = InsideSpecialCommand; + continue; + } + break; + } + + Out.back().push_back(cur_ch); + } +} + +/// SubstituteSpecialCommands - Perform string substitution for $CALL +/// and $ENV. Helper function used by EmitCmdLineVecFill(). +StrVector::const_iterator SubstituteSpecialCommands +(StrVector::const_iterator Pos, StrVector::const_iterator End, std::ostream& O) +{ + + const std::string& cmd = *Pos; + + if (cmd == "$CALL") { + checkedIncrement(Pos, End, "Syntax error in $CALL invocation!"); + const std::string& CmdName = *Pos; + + if (CmdName == ")") + throw std::string("$CALL invocation: empty argument list!"); + + O << "hooks::"; + O << CmdName << "("; + + + bool firstIteration = true; + while (true) { + checkedIncrement(Pos, End, "Syntax error in $CALL invocation!"); + const std::string& Arg = *Pos; + assert(Arg.size() != 0); + + if (Arg[0] == ')') + break; + + if (firstIteration) + firstIteration = false; + else + O << ", "; + + O << '"' << Arg << '"'; + } + + O << ')'; + + } + else if (cmd == "$ENV") { + checkedIncrement(Pos, End, "Syntax error in $ENV invocation!"); + const std::string& EnvName = *Pos; + + if (EnvName == ")") + throw "$ENV invocation: empty argument list!"; + + O << "checkCString(std::getenv(\""; + O << EnvName; + O << "\"))"; + + checkedIncrement(Pos, End, "Syntax error in $ENV invocation!"); + } + else { + throw "Unknown special command: " + cmd; + } + + const std::string& Leftover = *Pos; + assert(Leftover.at(0) == ')'); + if (Leftover.size() != 1) + O << " + std::string(\"" << (Leftover.c_str() + 1) << "\")"; + + return Pos; +} + +/// EmitCmdLineVecFill - Emit code that fills in the command line +/// vector. Helper function used by EmitGenerateActionMethod(). +void EmitCmdLineVecFill(const Init* CmdLine, const std::string& ToolName, + bool IsJoin, const char* IndentLevel, + std::ostream& O) { + StrVector StrVec; + TokenizeCmdline(InitPtrToString(CmdLine), StrVec); + + if (StrVec.empty()) + throw "Tool " + ToolName + " has empty command line!"; + + StrVector::const_iterator I = StrVec.begin(), E = StrVec.end(); + + // If there is a hook invocation on the place of the first command, skip it. + assert(!StrVec[0].empty()); + if (StrVec[0][0] == '$') { + while (I != E && (*I)[0] != ')' ) + ++I; + + // Skip the ')' symbol. + ++I; + } + else { + ++I; + } + + for (; I != E; ++I) { + const std::string& cmd = *I; + assert(!cmd.empty()); + O << IndentLevel; + if (cmd.at(0) == '$') { + if (cmd == "$INFILE") { + if (IsJoin) + O << "for (PathVector::const_iterator B = inFiles.begin()" + << ", E = inFiles.end();\n" + << IndentLevel << "B != E; ++B)\n" + << IndentLevel << Indent1 << "vec.push_back(B->toString());\n"; + else + O << "vec.push_back(inFile.toString());\n"; + } + else if (cmd == "$OUTFILE") { + O << "vec.push_back(out_file);\n"; + } + else { + O << "vec.push_back("; + I = SubstituteSpecialCommands(I, E, O); + O << ");\n"; + } + } + else { + O << "vec.push_back(\"" << cmd << "\");\n"; + } + } + O << IndentLevel << "cmd = "; + + if (StrVec[0][0] == '$') + SubstituteSpecialCommands(StrVec.begin(), StrVec.end(), O); + else + O << '"' << StrVec[0] << '"'; + O << ";\n"; +} + +/// EmitCmdLineVecFillCallback - A function object wrapper around +/// EmitCmdLineVecFill(). Used by EmitGenerateActionMethod() as an +/// argument to EmitCaseConstructHandler(). +class EmitCmdLineVecFillCallback { + bool IsJoin; + const std::string& ToolName; + public: + EmitCmdLineVecFillCallback(bool J, const std::string& TN) + : IsJoin(J), ToolName(TN) {} + + void operator()(const Init* Statement, const char* IndentLevel, + std::ostream& O) const + { + EmitCmdLineVecFill(Statement, ToolName, IsJoin, + IndentLevel, O); + } +}; + +/// EmitForwardOptionPropertyHandlingCode - Helper function used to +/// implement EmitActionHandler. Emits code for +/// handling the (forward) and (forward_as) option properties. +void EmitForwardOptionPropertyHandlingCode (const OptionDescription& D, + const char* Indent, + const std::string& NewName, + std::ostream& O) { + const std::string& Name = NewName.empty() + ? ("-" + D.Name) + : NewName; + + switch (D.Type) { + case OptionType::Switch: + O << Indent << "vec.push_back(\"" << Name << "\");\n"; + break; + case OptionType::Parameter: + O << Indent << "vec.push_back(\"" << Name << "\");\n"; + O << Indent << "vec.push_back(" << D.GenVariableName() << ");\n"; + break; + case OptionType::Prefix: + O << Indent << "vec.push_back(\"" << Name << "\" + " + << D.GenVariableName() << ");\n"; + break; + case OptionType::PrefixList: + O << Indent << "for (" << D.GenTypeDeclaration() + << "::iterator B = " << D.GenVariableName() << ".begin(),\n" + << Indent << "E = " << D.GenVariableName() << ".end(); B != E;) {\n" + << Indent << Indent1 << "vec.push_back(\"" << Name << "\" + " + << "*B);\n" + << Indent << Indent1 << "++B;\n"; + + for (int i = 1, j = D.MultiVal; i < j; ++i) { + O << Indent << Indent1 << "vec.push_back(*B);\n" + << Indent << Indent1 << "++B;\n"; + } + + O << Indent << "}\n"; + break; + case OptionType::ParameterList: + O << Indent << "for (" << D.GenTypeDeclaration() + << "::iterator B = " << D.GenVariableName() << ".begin(),\n" + << Indent << "E = " << D.GenVariableName() + << ".end() ; B != E;) {\n" + << Indent << Indent1 << "vec.push_back(\"" << Name << "\");\n"; + + for (int i = 0, j = D.MultiVal; i < j; ++i) { + O << Indent << Indent1 << "vec.push_back(*B);\n" + << Indent << Indent1 << "++B;\n"; + } + + O << Indent << "}\n"; + break; + case OptionType::Alias: + default: + throw std::string("Aliases are not allowed in tool option descriptions!"); + } +} + +/// EmitActionHandler - Emit code that handles actions. Used by +/// EmitGenerateActionMethod() as an argument to +/// EmitCaseConstructHandler(). +class EmitActionHandler { + const OptionDescriptions& OptDescs; + + void processActionDag(const Init* Statement, const char* IndentLevel, + std::ostream& O) const + { + const DagInit& Dag = InitPtrToDag(Statement); + const std::string& ActionName = Dag.getOperator()->getAsString(); + + if (ActionName == "append_cmd") { + checkNumberOfArguments(&Dag, 1); + const std::string& Cmd = InitPtrToString(Dag.getArg(0)); + StrVector Out; + llvm::SplitString(Cmd, Out); + + for (StrVector::const_iterator B = Out.begin(), E = Out.end(); + B != E; ++B) + O << IndentLevel << "vec.push_back(\"" << *B << "\");\n"; + } + else if (ActionName == "error") { + O << IndentLevel << "throw std::runtime_error(\"" << + (Dag.getNumArgs() >= 1 ? InitPtrToString(Dag.getArg(0)) + : "Unknown error!") + << "\");\n"; + } + else if (ActionName == "forward") { + checkNumberOfArguments(&Dag, 1); + const std::string& Name = InitPtrToString(Dag.getArg(0)); + EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name), + IndentLevel, "", O); + } + else if (ActionName == "forward_as") { + checkNumberOfArguments(&Dag, 2); + const std::string& Name = InitPtrToString(Dag.getArg(0)); + const std::string& NewName = InitPtrToString(Dag.getArg(1)); + EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name), + IndentLevel, NewName, O); + } + else if (ActionName == "output_suffix") { + checkNumberOfArguments(&Dag, 1); + const std::string& OutSuf = InitPtrToString(Dag.getArg(0)); + O << IndentLevel << "output_suffix = \"" << OutSuf << "\";\n"; + } + else if (ActionName == "stop_compilation") { + O << IndentLevel << "stop_compilation = true;\n"; + } + else if (ActionName == "unpack_values") { + checkNumberOfArguments(&Dag, 1); + const std::string& Name = InitPtrToString(Dag.getArg(0)); + const OptionDescription& D = OptDescs.FindOption(Name); + + if (D.isMultiVal()) + throw std::string("Can't use unpack_values with multi-valued options!"); + + if (OptionType::IsList(D.Type)) { + O << IndentLevel << "for (" << D.GenTypeDeclaration() + << "::iterator B = " << D.GenVariableName() << ".begin(),\n" + << IndentLevel << "E = " << D.GenVariableName() + << ".end(); B != E; ++B)\n" + << IndentLevel << Indent1 << "llvm::SplitString(*B, vec, \",\");\n"; + } + else if (OptionType::IsParameter(D.Type)){ + O << Indent3 << "llvm::SplitString(" + << D.GenVariableName() << ", vec, \",\");\n"; + } + else { + throw "Option '" + D.Name + + "': switches can't have the 'unpack_values' property!"; + } + } + else { + throw "Unknown action name: " + ActionName + "!"; + } + } + public: + EmitActionHandler(const OptionDescriptions& OD) + : OptDescs(OD) {} + + void operator()(const Init* Statement, const char* IndentLevel, + std::ostream& O) const + { + if (typeid(*Statement) == typeid(ListInit)) { + const ListInit& DagList = *static_cast<const ListInit*>(Statement); + for (ListInit::const_iterator B = DagList.begin(), E = DagList.end(); + B != E; ++B) + this->processActionDag(*B, IndentLevel, O); + } + else { + this->processActionDag(Statement, IndentLevel, O); + } + } +}; + +// EmitGenerateActionMethod - Emit one of two versions of the +// Tool::GenerateAction() method. +void EmitGenerateActionMethod (const ToolDescription& D, + const OptionDescriptions& OptDescs, + bool IsJoin, std::ostream& O) { + if (IsJoin) + O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n"; + else + O << Indent1 << "Action GenerateAction(const sys::Path& inFile,\n"; + + O << Indent2 << "bool HasChildren,\n" + << Indent2 << "const llvm::sys::Path& TempDir,\n" + << Indent2 << "const InputLanguagesSet& InLangs,\n" + << Indent2 << "const LanguageMap& LangMap) const\n" + << Indent1 << "{\n" + << Indent2 << "std::string cmd;\n" + << Indent2 << "std::vector<std::string> vec;\n" + << Indent2 << "bool stop_compilation = !HasChildren;\n" + << Indent2 << "const char* output_suffix = \"" << D.OutputSuffix << "\";\n" + << Indent2 << "std::string out_file;\n\n"; + + // For every understood option, emit handling code. + if (D.Actions) + EmitCaseConstructHandler(D.Actions, Indent2, EmitActionHandler(OptDescs), + false, OptDescs, O); + + O << '\n' << Indent2 + << "out_file = OutFilename(" << (IsJoin ? "sys::Path(),\n" : "inFile,\n") + << Indent3 << "TempDir, stop_compilation, output_suffix).toString();\n\n"; + + // cmd_line is either a string or a 'case' construct. + if (!D.CmdLine) + throw "Tool " + D.Name + " has no cmd_line property!"; + else if (typeid(*D.CmdLine) == typeid(StringInit)) + EmitCmdLineVecFill(D.CmdLine, D.Name, IsJoin, Indent2, O); + else + EmitCaseConstructHandler(D.CmdLine, Indent2, + EmitCmdLineVecFillCallback(IsJoin, D.Name), + true, OptDescs, O); + + // Handle the Sink property. + if (D.isSink()) { + O << Indent2 << "if (!" << SinkOptionName << ".empty()) {\n" + << Indent3 << "vec.insert(vec.end(), " + << SinkOptionName << ".begin(), " << SinkOptionName << ".end());\n" + << Indent2 << "}\n"; + } + + O << Indent2 << "return Action(cmd, vec, stop_compilation, out_file);\n" + << Indent1 << "}\n\n"; +} + +/// EmitGenerateActionMethods - Emit two GenerateAction() methods for +/// a given Tool class. +void EmitGenerateActionMethods (const ToolDescription& ToolDesc, + const OptionDescriptions& OptDescs, + std::ostream& O) { + if (!ToolDesc.isJoin()) + O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n" + << Indent2 << "bool HasChildren,\n" + << Indent2 << "const llvm::sys::Path& TempDir,\n" + << Indent2 << "const InputLanguagesSet& InLangs,\n" + << Indent2 << "const LanguageMap& LangMap) const\n" + << Indent1 << "{\n" + << Indent2 << "throw std::runtime_error(\"" << ToolDesc.Name + << " is not a Join tool!\");\n" + << Indent1 << "}\n\n"; + else + EmitGenerateActionMethod(ToolDesc, OptDescs, true, O); + + EmitGenerateActionMethod(ToolDesc, OptDescs, false, O); +} + +/// EmitInOutLanguageMethods - Emit the [Input,Output]Language() +/// methods for a given Tool class. +void EmitInOutLanguageMethods (const ToolDescription& D, std::ostream& O) { + O << Indent1 << "const char** InputLanguages() const {\n" + << Indent2 << "return InputLanguages_;\n" + << Indent1 << "}\n\n"; + + if (D.OutLanguage.empty()) + throw "Tool " + D.Name + " has no 'out_language' property!"; + + O << Indent1 << "const char* OutputLanguage() const {\n" + << Indent2 << "return \"" << D.OutLanguage << "\";\n" + << Indent1 << "}\n\n"; +} + +/// EmitNameMethod - Emit the Name() method for a given Tool class. +void EmitNameMethod (const ToolDescription& D, std::ostream& O) { + O << Indent1 << "const char* Name() const {\n" + << Indent2 << "return \"" << D.Name << "\";\n" + << Indent1 << "}\n\n"; +} + +/// EmitIsJoinMethod - Emit the IsJoin() method for a given Tool +/// class. +void EmitIsJoinMethod (const ToolDescription& D, std::ostream& O) { + O << Indent1 << "bool IsJoin() const {\n"; + if (D.isJoin()) + O << Indent2 << "return true;\n"; + else + O << Indent2 << "return false;\n"; + O << Indent1 << "}\n\n"; +} + +/// EmitStaticMemberDefinitions - Emit static member definitions for a +/// given Tool class. +void EmitStaticMemberDefinitions(const ToolDescription& D, std::ostream& O) { + if (D.InLanguage.empty()) + throw "Tool " + D.Name + " has no 'in_language' property!"; + + O << "const char* " << D.Name << "::InputLanguages_[] = {"; + for (StrVector::const_iterator B = D.InLanguage.begin(), + E = D.InLanguage.end(); B != E; ++B) + O << '\"' << *B << "\", "; + O << "0};\n\n"; +} + +/// EmitToolClassDefinition - Emit a Tool class definition. +void EmitToolClassDefinition (const ToolDescription& D, + const OptionDescriptions& OptDescs, + std::ostream& O) { + if (D.Name == "root") + return; + + // Header + O << "class " << D.Name << " : public "; + if (D.isJoin()) + O << "JoinTool"; + else + O << "Tool"; + + O << "{\nprivate:\n" + << Indent1 << "static const char* InputLanguages_[];\n\n"; + + O << "public:\n"; + EmitNameMethod(D, O); + EmitInOutLanguageMethods(D, O); + EmitIsJoinMethod(D, O); + EmitGenerateActionMethods(D, OptDescs, O); + + // Close class definition + O << "};\n"; + + EmitStaticMemberDefinitions(D, O); + +} + +/// EmitOptionDefintions - Iterate over a list of option descriptions +/// and emit registration code. +void EmitOptionDefintions (const OptionDescriptions& descs, + bool HasSink, bool HasExterns, + std::ostream& O) +{ + std::vector<OptionDescription> Aliases; + + // Emit static cl::Option variables. + for (OptionDescriptions::const_iterator B = descs.begin(), + E = descs.end(); B!=E; ++B) { + const OptionDescription& val = B->second; + + if (val.Type == OptionType::Alias) { + Aliases.push_back(val); + continue; + } + + if (val.isExtern()) + O << "extern "; + + O << val.GenTypeDeclaration() << ' ' + << val.GenVariableName(); + + if (val.isExtern()) { + O << ";\n"; + continue; + } + + O << "(\"" << val.Name << '\"'; + + if (val.Type == OptionType::Prefix || val.Type == OptionType::PrefixList) + O << ", cl::Prefix"; + + if (val.isRequired()) { + if (OptionType::IsList(val.Type) && !val.isMultiVal()) + O << ", cl::OneOrMore"; + else + O << ", cl::Required"; + } + else if (val.isOneOrMore() && OptionType::IsList(val.Type)) { + O << ", cl::OneOrMore"; + } + else if (val.isZeroOrOne() && OptionType::IsList(val.Type)) { + O << ", cl::ZeroOrOne"; + } + + if (val.isReallyHidden()) { + O << ", cl::ReallyHidden"; + } + else if (val.isHidden()) { + O << ", cl::Hidden"; + } + + if (val.MultiVal > 1) + O << ", cl::multi_val(" << val.MultiVal << ")"; + + if (!val.Help.empty()) + O << ", cl::desc(\"" << val.Help << "\")"; + + O << ");\n"; + } + + // Emit the aliases (they should go after all the 'proper' options). + for (std::vector<OptionDescription>::const_iterator + B = Aliases.begin(), E = Aliases.end(); B != E; ++B) { + const OptionDescription& val = *B; + + O << val.GenTypeDeclaration() << ' ' + << val.GenVariableName() + << "(\"" << val.Name << '\"'; + + const OptionDescription& D = descs.FindOption(val.Help); + O << ", cl::aliasopt(" << D.GenVariableName() << ")"; + + O << ", cl::desc(\"" << "An alias for -" + val.Help << "\"));\n"; + } + + // Emit the sink option. + if (HasSink) + O << (HasExterns ? "extern cl" : "cl") + << "::list<std::string> " << SinkOptionName + << (HasExterns ? ";\n" : "(cl::Sink);\n"); + + O << '\n'; +} + +/// EmitPopulateLanguageMap - Emit the PopulateLanguageMap() function. +void EmitPopulateLanguageMap (const RecordKeeper& Records, std::ostream& O) +{ + // Generate code + O << "void PopulateLanguageMapLocal(LanguageMap& langMap) {\n"; + + // Get the relevant field out of RecordKeeper + const Record* LangMapRecord = Records.getDef("LanguageMap"); + + // It is allowed for a plugin to have no language map. + if (LangMapRecord) { + + ListInit* LangsToSuffixesList = LangMapRecord->getValueAsListInit("map"); + if (!LangsToSuffixesList) + throw std::string("Error in the language map definition!"); + + for (unsigned i = 0; i < LangsToSuffixesList->size(); ++i) { + const Record* LangToSuffixes = LangsToSuffixesList->getElementAsRecord(i); + + const std::string& Lang = LangToSuffixes->getValueAsString("lang"); + const ListInit* Suffixes = LangToSuffixes->getValueAsListInit("suffixes"); + + for (unsigned i = 0; i < Suffixes->size(); ++i) + O << Indent1 << "langMap[\"" + << InitPtrToString(Suffixes->getElement(i)) + << "\"] = \"" << Lang << "\";\n"; + } + } + + O << "}\n\n"; +} + +/// IncDecWeight - Helper function passed to EmitCaseConstructHandler() +/// by EmitEdgeClass(). +void IncDecWeight (const Init* i, const char* IndentLevel, + std::ostream& O) { + const DagInit& d = InitPtrToDag(i); + const std::string& OpName = d.getOperator()->getAsString(); + + if (OpName == "inc_weight") { + O << IndentLevel << "ret += "; + } + else if (OpName == "dec_weight") { + O << IndentLevel << "ret -= "; + } + else if (OpName == "error") { + O << IndentLevel << "throw std::runtime_error(\"" << + (d.getNumArgs() >= 1 ? InitPtrToString(d.getArg(0)) + : "Unknown error!") + << "\");\n"; + return; + } + + else + throw "Unknown operator in edge properties list: " + OpName + '!' + + "\nOnly 'inc_weight', 'dec_weight' and 'error' are allowed."; + + if (d.getNumArgs() > 0) + O << InitPtrToInt(d.getArg(0)) << ";\n"; + else + O << "2;\n"; + +} + +/// EmitEdgeClass - Emit a single Edge# class. +void EmitEdgeClass (unsigned N, const std::string& Target, + DagInit* Case, const OptionDescriptions& OptDescs, + std::ostream& O) { + + // Class constructor. + O << "class Edge" << N << ": public Edge {\n" + << "public:\n" + << Indent1 << "Edge" << N << "() : Edge(\"" << Target + << "\") {}\n\n" + + // Function Weight(). + << Indent1 << "unsigned Weight(const InputLanguagesSet& InLangs) const {\n" + << Indent2 << "unsigned ret = 0;\n"; + + // Handle the 'case' construct. + EmitCaseConstructHandler(Case, Indent2, IncDecWeight, false, OptDescs, O); + + O << Indent2 << "return ret;\n" + << Indent1 << "};\n\n};\n\n"; +} + +/// EmitEdgeClasses - Emit Edge* classes that represent graph edges. +void EmitEdgeClasses (const RecordVector& EdgeVector, + const OptionDescriptions& OptDescs, + std::ostream& O) { + int i = 0; + for (RecordVector::const_iterator B = EdgeVector.begin(), + E = EdgeVector.end(); B != E; ++B) { + const Record* Edge = *B; + const std::string& NodeB = Edge->getValueAsString("b"); + DagInit* Weight = Edge->getValueAsDag("weight"); + + if (!isDagEmpty(Weight)) + EmitEdgeClass(i, NodeB, Weight, OptDescs, O); + ++i; + } +} + +/// EmitPopulateCompilationGraph - Emit the PopulateCompilationGraph() +/// function. +void EmitPopulateCompilationGraph (const RecordVector& EdgeVector, + const ToolDescriptions& ToolDescs, + std::ostream& O) +{ + O << "void PopulateCompilationGraphLocal(CompilationGraph& G) {\n"; + + for (ToolDescriptions::const_iterator B = ToolDescs.begin(), + E = ToolDescs.end(); B != E; ++B) + O << Indent1 << "G.insertNode(new " << (*B)->Name << "());\n"; + + O << '\n'; + + // Insert edges. + + int i = 0; + for (RecordVector::const_iterator B = EdgeVector.begin(), + E = EdgeVector.end(); B != E; ++B) { + const Record* Edge = *B; + const std::string& NodeA = Edge->getValueAsString("a"); + const std::string& NodeB = Edge->getValueAsString("b"); + DagInit* Weight = Edge->getValueAsDag("weight"); + + O << Indent1 << "G.insertEdge(\"" << NodeA << "\", "; + + if (isDagEmpty(Weight)) + O << "new SimpleEdge(\"" << NodeB << "\")"; + else + O << "new Edge" << i << "()"; + + O << ");\n"; + ++i; + } + + O << "}\n\n"; +} + +/// ExtractHookNames - Extract the hook names from all instances of +/// $CALL(HookName) in the provided command line string. Helper +/// function used by FillInHookNames(). +class ExtractHookNames { + llvm::StringMap<unsigned>& HookNames_; +public: + ExtractHookNames(llvm::StringMap<unsigned>& HookNames) + : HookNames_(HookNames) {} + + void operator()(const Init* CmdLine) { + StrVector cmds; + TokenizeCmdline(InitPtrToString(CmdLine), cmds); + for (StrVector::const_iterator B = cmds.begin(), E = cmds.end(); + B != E; ++B) { + const std::string& cmd = *B; + + if (cmd == "$CALL") { + unsigned NumArgs = 0; + checkedIncrement(B, E, "Syntax error in $CALL invocation!"); + const std::string& HookName = *B; + + + if (HookName.at(0) == ')') + throw "$CALL invoked with no arguments!"; + + while (++B != E && B->at(0) != ')') { + ++NumArgs; + } + + StringMap<unsigned>::const_iterator H = HookNames_.find(HookName); + + if (H != HookNames_.end() && H->second != NumArgs) + throw "Overloading of hooks is not allowed. Overloaded hook: " + + HookName; + else + HookNames_[HookName] = NumArgs; + + } + } + } +}; + +/// FillInHookNames - Actually extract the hook names from all command +/// line strings. Helper function used by EmitHookDeclarations(). +void FillInHookNames(const ToolDescriptions& ToolDescs, + llvm::StringMap<unsigned>& HookNames) +{ + // For all command lines: + for (ToolDescriptions::const_iterator B = ToolDescs.begin(), + E = ToolDescs.end(); B != E; ++B) { + const ToolDescription& D = *(*B); + if (!D.CmdLine) + continue; + if (dynamic_cast<StringInit*>(D.CmdLine)) + // This is a string. + ExtractHookNames(HookNames).operator()(D.CmdLine); + else + // This is a 'case' construct. + WalkCase(D.CmdLine, Id(), ExtractHookNames(HookNames)); + } +} + +/// EmitHookDeclarations - Parse CmdLine fields of all the tool +/// property records and emit hook function declaration for each +/// instance of $CALL(HookName). +void EmitHookDeclarations(const ToolDescriptions& ToolDescs, std::ostream& O) { + llvm::StringMap<unsigned> HookNames; + + FillInHookNames(ToolDescs, HookNames); + if (HookNames.empty()) + return; + + O << "namespace hooks {\n"; + for (StringMap<unsigned>::const_iterator B = HookNames.begin(), + E = HookNames.end(); B != E; ++B) { + O << Indent1 << "std::string " << B->first() << "("; + + for (unsigned i = 0, j = B->second; i < j; ++i) { + O << "const char* Arg" << i << (i+1 == j ? "" : ", "); + } + + O <<");\n"; + } + O << "}\n\n"; +} + +/// EmitRegisterPlugin - Emit code to register this plugin. +void EmitRegisterPlugin(int Priority, std::ostream& O) { + O << "struct Plugin : public llvmc::BasePlugin {\n\n" + << Indent1 << "int Priority() const { return " << Priority << "; }\n\n" + << Indent1 << "void PopulateLanguageMap(LanguageMap& langMap) const\n" + << Indent1 << "{ PopulateLanguageMapLocal(langMap); }\n\n" + << Indent1 + << "void PopulateCompilationGraph(CompilationGraph& graph) const\n" + << Indent1 << "{ PopulateCompilationGraphLocal(graph); }\n" + << "};\n\n" + + << "static llvmc::RegisterPlugin<Plugin> RP;\n\n"; +} + +/// EmitIncludes - Emit necessary #include directives and some +/// additional declarations. +void EmitIncludes(std::ostream& O) { + O << "#include \"llvm/CompilerDriver/CompilationGraph.h\"\n" + << "#include \"llvm/CompilerDriver/Plugin.h\"\n" + << "#include \"llvm/CompilerDriver/Tool.h\"\n\n" + + << "#include \"llvm/ADT/StringExtras.h\"\n" + << "#include \"llvm/Support/CommandLine.h\"\n\n" + + << "#include <cstdlib>\n" + << "#include <stdexcept>\n\n" + + << "using namespace llvm;\n" + << "using namespace llvmc;\n\n" + + << "extern cl::opt<std::string> OutputFilename;\n\n" + + << "inline const char* checkCString(const char* s)\n" + << "{ return s == NULL ? \"\" : s; }\n\n"; +} + + +/// PluginData - Holds all information about a plugin. +struct PluginData { + OptionDescriptions OptDescs; + bool HasSink; + bool HasExterns; + ToolDescriptions ToolDescs; + RecordVector Edges; + int Priority; +}; + +/// HasSink - Go through the list of tool descriptions and check if +/// there are any with the 'sink' property set. +bool HasSink(const ToolDescriptions& ToolDescs) { + for (ToolDescriptions::const_iterator B = ToolDescs.begin(), + E = ToolDescs.end(); B != E; ++B) + if ((*B)->isSink()) + return true; + + return false; +} + +/// HasExterns - Go through the list of option descriptions and check +/// if there are any external options. +bool HasExterns(const OptionDescriptions& OptDescs) { + for (OptionDescriptions::const_iterator B = OptDescs.begin(), + E = OptDescs.end(); B != E; ++B) + if (B->second.isExtern()) + return true; + + return false; +} + +/// CollectPluginData - Collect tool and option properties, +/// compilation graph edges and plugin priority from the parse tree. +void CollectPluginData (const RecordKeeper& Records, PluginData& Data) { + // Collect option properties. + const RecordVector& OptionLists = + Records.getAllDerivedDefinitions("OptionList"); + CollectOptionDescriptions(OptionLists.begin(), OptionLists.end(), + Data.OptDescs); + + // Collect tool properties. + const RecordVector& Tools = Records.getAllDerivedDefinitions("Tool"); + CollectToolDescriptions(Tools.begin(), Tools.end(), Data.ToolDescs); + Data.HasSink = HasSink(Data.ToolDescs); + Data.HasExterns = HasExterns(Data.OptDescs); + + // Collect compilation graph edges. + const RecordVector& CompilationGraphs = + Records.getAllDerivedDefinitions("CompilationGraph"); + FillInEdgeVector(CompilationGraphs.begin(), CompilationGraphs.end(), + Data.Edges); + + // Calculate the priority of this plugin. + const RecordVector& Priorities = + Records.getAllDerivedDefinitions("PluginPriority"); + Data.Priority = CalculatePriority(Priorities.begin(), Priorities.end()); +} + +/// CheckPluginData - Perform some sanity checks on the collected data. +void CheckPluginData(PluginData& Data) { + // Filter out all tools not mentioned in the compilation graph. + FilterNotInGraph(Data.Edges, Data.ToolDescs); + + // Typecheck the compilation graph. + TypecheckGraph(Data.Edges, Data.ToolDescs); + + // Check that there are no options without side effects (specified + // only in the OptionList). + CheckForSuperfluousOptions(Data.Edges, Data.ToolDescs, Data.OptDescs); + +} + +void EmitPluginCode(const PluginData& Data, std::ostream& O) { + // Emit file header. + EmitIncludes(O); + + // Emit global option registration code. + EmitOptionDefintions(Data.OptDescs, Data.HasSink, Data.HasExterns, O); + + // Emit hook declarations. + EmitHookDeclarations(Data.ToolDescs, O); + + O << "namespace {\n\n"; + + // Emit PopulateLanguageMap() function + // (a language map maps from file extensions to language names). + EmitPopulateLanguageMap(Records, O); + + // Emit Tool classes. + for (ToolDescriptions::const_iterator B = Data.ToolDescs.begin(), + E = Data.ToolDescs.end(); B!=E; ++B) + EmitToolClassDefinition(*(*B), Data.OptDescs, O); + + // Emit Edge# classes. + EmitEdgeClasses(Data.Edges, Data.OptDescs, O); + + // Emit PopulateCompilationGraph() function. + EmitPopulateCompilationGraph(Data.Edges, Data.ToolDescs, O); + + // Emit code for plugin registration. + EmitRegisterPlugin(Data.Priority, O); + + O << "} // End anonymous namespace.\n"; + // EOF +} + + +// End of anonymous namespace +} + +/// run - The back-end entry point. +void LLVMCConfigurationEmitter::run (std::ostream &O) { + try { + PluginData Data; + + CollectPluginData(Records, Data); + CheckPluginData(Data); + + EmitSourceFileHeader("LLVMC Configuration Library", O); + EmitPluginCode(Data, O); + + } catch (std::exception& Error) { + throw Error.what() + std::string(" - usually this means a syntax error."); + } +} diff --git a/utils/TableGen/LLVMCConfigurationEmitter.h b/utils/TableGen/LLVMCConfigurationEmitter.h new file mode 100644 index 0000000000000..98c4bc0695606 --- /dev/null +++ b/utils/TableGen/LLVMCConfigurationEmitter.h @@ -0,0 +1,33 @@ +//===- LLVMCConfigurationEmitter.cpp - Generate LLVMCC config ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open +// Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend is responsible for emitting LLVMCC configuration code. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_UTILS_TABLEGEN_LLVMCCONF_EMITTER_H +#define LLVM_UTILS_TABLEGEN_LLVMCCONF_EMITTER_H + +#include "TableGenBackend.h" + +namespace llvm { + + /// LLVMCConfigurationEmitter - TableGen backend that generates + /// configuration code for LLVMC. + class LLVMCConfigurationEmitter : public TableGenBackend { + RecordKeeper &Records; + public: + explicit LLVMCConfigurationEmitter(RecordKeeper &R) : Records(R) {} + + // run - Output the asmwriter, returning true on failure. + void run(std::ostream &o); + }; +} + +#endif //LLVM_UTILS_TABLEGEN_LLVMCCONF_EMITTER_H diff --git a/utils/TableGen/Makefile b/utils/TableGen/Makefile new file mode 100644 index 0000000000000..7ea88de05591d --- /dev/null +++ b/utils/TableGen/Makefile @@ -0,0 +1,20 @@ +##===- utils/TableGen/Makefile -----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../.. +TOOLNAME = tblgen +USEDLIBS = LLVMSupport.a LLVMSystem.a +REQUIRES_EH := 1 +REQUIRES_RTTI := 1 + +# This tool has no plugins, optimize startup time. +TOOL_NO_EXPORTS = 1 + +include $(LEVEL)/Makefile.common + diff --git a/utils/TableGen/Record.cpp b/utils/TableGen/Record.cpp new file mode 100644 index 0000000000000..45804b938cb20 --- /dev/null +++ b/utils/TableGen/Record.cpp @@ -0,0 +1,1485 @@ +//===- Record.cpp - Record implementation ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implement the tablegen record classes. +// +//===----------------------------------------------------------------------===// + +#include "Record.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Streams.h" +#include "llvm/ADT/StringExtras.h" +#include <ios> + +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Type implementations +//===----------------------------------------------------------------------===// + +void RecTy::dump() const { print(*cerr.stream()); } + +Init *BitRecTy::convertValue(BitsInit *BI) { + if (BI->getNumBits() != 1) return 0; // Only accept if just one bit! + return BI->getBit(0); +} + +bool BitRecTy::baseClassOf(const BitsRecTy *RHS) const { + return RHS->getNumBits() == 1; +} + +Init *BitRecTy::convertValue(IntInit *II) { + int64_t Val = II->getValue(); + if (Val != 0 && Val != 1) return 0; // Only accept 0 or 1 for a bit! + + return new BitInit(Val != 0); +} + +Init *BitRecTy::convertValue(TypedInit *VI) { + if (dynamic_cast<BitRecTy*>(VI->getType())) + return VI; // Accept variable if it is already of bit type! + return 0; +} + +std::string BitsRecTy::getAsString() const { + return "bits<" + utostr(Size) + ">"; +} + +Init *BitsRecTy::convertValue(UnsetInit *UI) { + BitsInit *Ret = new BitsInit(Size); + + for (unsigned i = 0; i != Size; ++i) + Ret->setBit(i, new UnsetInit()); + return Ret; +} + +Init *BitsRecTy::convertValue(BitInit *UI) { + if (Size != 1) return 0; // Can only convert single bit... + BitsInit *Ret = new BitsInit(1); + Ret->setBit(0, UI); + return Ret; +} + +// convertValue from Int initializer to bits type: Split the integer up into the +// appropriate bits... +// +Init *BitsRecTy::convertValue(IntInit *II) { + int64_t Value = II->getValue(); + // Make sure this bitfield is large enough to hold the integer value... + if (Value >= 0) { + if (Value & ~((1LL << Size)-1)) + return 0; + } else { + if ((Value >> Size) != -1 || ((Value & (1LL << (Size-1))) == 0)) + return 0; + } + + BitsInit *Ret = new BitsInit(Size); + for (unsigned i = 0; i != Size; ++i) + Ret->setBit(i, new BitInit(Value & (1LL << i))); + + return Ret; +} + +Init *BitsRecTy::convertValue(BitsInit *BI) { + // If the number of bits is right, return it. Otherwise we need to expand or + // truncate... + if (BI->getNumBits() == Size) return BI; + return 0; +} + +Init *BitsRecTy::convertValue(TypedInit *VI) { + if (BitsRecTy *BRT = dynamic_cast<BitsRecTy*>(VI->getType())) + if (BRT->Size == Size) { + BitsInit *Ret = new BitsInit(Size); + for (unsigned i = 0; i != Size; ++i) + Ret->setBit(i, new VarBitInit(VI, i)); + return Ret; + } + if (Size == 1 && dynamic_cast<BitRecTy*>(VI->getType())) { + BitsInit *Ret = new BitsInit(1); + Ret->setBit(0, VI); + return Ret; + } + + return 0; +} + +Init *IntRecTy::convertValue(BitInit *BI) { + return new IntInit(BI->getValue()); +} + +Init *IntRecTy::convertValue(BitsInit *BI) { + int64_t Result = 0; + for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i) + if (BitInit *Bit = dynamic_cast<BitInit*>(BI->getBit(i))) { + Result |= Bit->getValue() << i; + } else { + return 0; + } + return new IntInit(Result); +} + +Init *IntRecTy::convertValue(TypedInit *TI) { + if (TI->getType()->typeIsConvertibleTo(this)) + return TI; // Accept variable if already of the right type! + return 0; +} + +Init *StringRecTy::convertValue(UnOpInit *BO) { + if (BO->getOpcode() == UnOpInit::CAST) { + Init *L = BO->getOperand()->convertInitializerTo(this); + if (L == 0) return 0; + if (L != BO->getOperand()) + return new UnOpInit(UnOpInit::CAST, L, new StringRecTy); + return BO; + } + + return convertValue((TypedInit*)BO); +} + +Init *StringRecTy::convertValue(BinOpInit *BO) { + if (BO->getOpcode() == BinOpInit::STRCONCAT) { + Init *L = BO->getLHS()->convertInitializerTo(this); + Init *R = BO->getRHS()->convertInitializerTo(this); + if (L == 0 || R == 0) return 0; + if (L != BO->getLHS() || R != BO->getRHS()) + return new BinOpInit(BinOpInit::STRCONCAT, L, R, new StringRecTy); + return BO; + } + if (BO->getOpcode() == BinOpInit::NAMECONCAT) { + if (BO->getType()->getAsString() == getAsString()) { + Init *L = BO->getLHS()->convertInitializerTo(this); + Init *R = BO->getRHS()->convertInitializerTo(this); + if (L == 0 || R == 0) return 0; + if (L != BO->getLHS() || R != BO->getRHS()) + return new BinOpInit(BinOpInit::NAMECONCAT, L, R, new StringRecTy); + return BO; + } + } + + return convertValue((TypedInit*)BO); +} + + +Init *StringRecTy::convertValue(TypedInit *TI) { + if (dynamic_cast<StringRecTy*>(TI->getType())) + return TI; // Accept variable if already of the right type! + return 0; +} + +std::string ListRecTy::getAsString() const { + return "list<" + Ty->getAsString() + ">"; +} + +Init *ListRecTy::convertValue(ListInit *LI) { + std::vector<Init*> Elements; + + // Verify that all of the elements of the list are subclasses of the + // appropriate class! + for (unsigned i = 0, e = LI->getSize(); i != e; ++i) + if (Init *CI = LI->getElement(i)->convertInitializerTo(Ty)) + Elements.push_back(CI); + else + return 0; + + return new ListInit(Elements); +} + +Init *ListRecTy::convertValue(TypedInit *TI) { + // Ensure that TI is compatible with our class. + if (ListRecTy *LRT = dynamic_cast<ListRecTy*>(TI->getType())) + if (LRT->getElementType()->typeIsConvertibleTo(getElementType())) + return TI; + return 0; +} + +Init *CodeRecTy::convertValue(TypedInit *TI) { + if (TI->getType()->typeIsConvertibleTo(this)) + return TI; + return 0; +} + +Init *DagRecTy::convertValue(TypedInit *TI) { + if (TI->getType()->typeIsConvertibleTo(this)) + return TI; + return 0; +} + +Init *DagRecTy::convertValue(UnOpInit *BO) { + if (BO->getOpcode() == UnOpInit::CAST) { + Init *L = BO->getOperand()->convertInitializerTo(this); + if (L == 0) return 0; + if (L != BO->getOperand()) + return new UnOpInit(UnOpInit::CAST, L, new DagRecTy); + return BO; + } + return 0; +} + +Init *DagRecTy::convertValue(BinOpInit *BO) { + if (BO->getOpcode() == BinOpInit::CONCAT) { + Init *L = BO->getLHS()->convertInitializerTo(this); + Init *R = BO->getRHS()->convertInitializerTo(this); + if (L == 0 || R == 0) return 0; + if (L != BO->getLHS() || R != BO->getRHS()) + return new BinOpInit(BinOpInit::CONCAT, L, R, new DagRecTy); + return BO; + } + if (BO->getOpcode() == BinOpInit::NAMECONCAT) { + if (BO->getType()->getAsString() == getAsString()) { + Init *L = BO->getLHS()->convertInitializerTo(this); + Init *R = BO->getRHS()->convertInitializerTo(this); + if (L == 0 || R == 0) return 0; + if (L != BO->getLHS() || R != BO->getRHS()) + return new BinOpInit(BinOpInit::CONCAT, L, R, new DagRecTy); + return BO; + } + } + return 0; +} + +std::string RecordRecTy::getAsString() const { + return Rec->getName(); +} + +Init *RecordRecTy::convertValue(DefInit *DI) { + // Ensure that DI is a subclass of Rec. + if (!DI->getDef()->isSubClassOf(Rec)) + return 0; + return DI; +} + +Init *RecordRecTy::convertValue(TypedInit *TI) { + // Ensure that TI is compatible with Rec. + if (RecordRecTy *RRT = dynamic_cast<RecordRecTy*>(TI->getType())) + if (RRT->getRecord()->isSubClassOf(getRecord()) || + RRT->getRecord() == getRecord()) + return TI; + return 0; +} + +bool RecordRecTy::baseClassOf(const RecordRecTy *RHS) const { + return Rec == RHS->getRecord() || RHS->getRecord()->isSubClassOf(Rec); +} + + +//===----------------------------------------------------------------------===// +// Initializer implementations +//===----------------------------------------------------------------------===// + +void Init::dump() const { return print(*cerr.stream()); } + +Init *BitsInit::convertInitializerBitRange(const std::vector<unsigned> &Bits) { + BitsInit *BI = new BitsInit(Bits.size()); + for (unsigned i = 0, e = Bits.size(); i != e; ++i) { + if (Bits[i] >= getNumBits()) { + delete BI; + return 0; + } + BI->setBit(i, getBit(Bits[i])); + } + return BI; +} + +std::string BitsInit::getAsString() const { + //if (!printInHex(OS)) return; + //if (!printAsVariable(OS)) return; + //if (!printAsUnset(OS)) return; + + std::string Result = "{ "; + for (unsigned i = 0, e = getNumBits(); i != e; ++i) { + if (i) Result += ", "; + if (Init *Bit = getBit(e-i-1)) + Result += Bit->getAsString(); + else + Result += "*"; + } + return Result + " }"; +} + +bool BitsInit::printInHex(std::ostream &OS) const { + // First, attempt to convert the value into an integer value... + int64_t Result = 0; + for (unsigned i = 0, e = getNumBits(); i != e; ++i) + if (BitInit *Bit = dynamic_cast<BitInit*>(getBit(i))) { + Result |= Bit->getValue() << i; + } else { + return true; + } + + OS << "0x" << std::hex << Result << std::dec; + return false; +} + +bool BitsInit::printAsVariable(std::ostream &OS) const { + // Get the variable that we may be set equal to... + assert(getNumBits() != 0); + VarBitInit *FirstBit = dynamic_cast<VarBitInit*>(getBit(0)); + if (FirstBit == 0) return true; + TypedInit *Var = FirstBit->getVariable(); + + // Check to make sure the types are compatible. + BitsRecTy *Ty = dynamic_cast<BitsRecTy*>(FirstBit->getVariable()->getType()); + if (Ty == 0) return true; + if (Ty->getNumBits() != getNumBits()) return true; // Incompatible types! + + // Check to make sure all bits are referring to the right bits in the variable + for (unsigned i = 0, e = getNumBits(); i != e; ++i) { + VarBitInit *Bit = dynamic_cast<VarBitInit*>(getBit(i)); + if (Bit == 0 || Bit->getVariable() != Var || Bit->getBitNum() != i) + return true; + } + + Var->print(OS); + return false; +} + +bool BitsInit::printAsUnset(std::ostream &OS) const { + for (unsigned i = 0, e = getNumBits(); i != e; ++i) + if (!dynamic_cast<UnsetInit*>(getBit(i))) + return true; + OS << "?"; + return false; +} + +// resolveReferences - If there are any field references that refer to fields +// that have been filled in, we can propagate the values now. +// +Init *BitsInit::resolveReferences(Record &R, const RecordVal *RV) { + bool Changed = false; + BitsInit *New = new BitsInit(getNumBits()); + + for (unsigned i = 0, e = Bits.size(); i != e; ++i) { + Init *B; + Init *CurBit = getBit(i); + + do { + B = CurBit; + CurBit = CurBit->resolveReferences(R, RV); + Changed |= B != CurBit; + } while (B != CurBit); + New->setBit(i, CurBit); + } + + if (Changed) + return New; + delete New; + return this; +} + +std::string IntInit::getAsString() const { + return itostr(Value); +} + +Init *IntInit::convertInitializerBitRange(const std::vector<unsigned> &Bits) { + BitsInit *BI = new BitsInit(Bits.size()); + + for (unsigned i = 0, e = Bits.size(); i != e; ++i) { + if (Bits[i] >= 64) { + delete BI; + return 0; + } + BI->setBit(i, new BitInit(Value & (INT64_C(1) << Bits[i]))); + } + return BI; +} + +Init *ListInit::convertInitListSlice(const std::vector<unsigned> &Elements) { + std::vector<Init*> Vals; + for (unsigned i = 0, e = Elements.size(); i != e; ++i) { + if (Elements[i] >= getSize()) + return 0; + Vals.push_back(getElement(Elements[i])); + } + return new ListInit(Vals); +} + +Record *ListInit::getElementAsRecord(unsigned i) const { + assert(i < Values.size() && "List element index out of range!"); + DefInit *DI = dynamic_cast<DefInit*>(Values[i]); + if (DI == 0) throw "Expected record in list!"; + return DI->getDef(); +} + +Init *ListInit::resolveReferences(Record &R, const RecordVal *RV) { + std::vector<Init*> Resolved; + Resolved.reserve(getSize()); + bool Changed = false; + + for (unsigned i = 0, e = getSize(); i != e; ++i) { + Init *E; + Init *CurElt = getElement(i); + + do { + E = CurElt; + CurElt = CurElt->resolveReferences(R, RV); + Changed |= E != CurElt; + } while (E != CurElt); + Resolved.push_back(E); + } + + if (Changed) + return new ListInit(Resolved); + return this; +} + +std::string ListInit::getAsString() const { + std::string Result = "["; + for (unsigned i = 0, e = Values.size(); i != e; ++i) { + if (i) Result += ", "; + Result += Values[i]->getAsString(); + } + return Result + "]"; +} + +Init *OpInit::resolveBitReference(Record &R, const RecordVal *IRV, + unsigned Bit) { + Init *Folded = Fold(&R, 0); + + if (Folded != this) { + TypedInit *Typed = dynamic_cast<TypedInit *>(Folded); + if (Typed) { + return Typed->resolveBitReference(R, IRV, Bit); + } + } + + return 0; +} + +Init *OpInit::resolveListElementReference(Record &R, const RecordVal *IRV, + unsigned Elt) { + Init *Folded = Fold(&R, 0); + + if (Folded != this) { + TypedInit *Typed = dynamic_cast<TypedInit *>(Folded); + if (Typed) { + return Typed->resolveListElementReference(R, IRV, Elt); + } + } + + return 0; +} + +Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) { + switch (getOpcode()) { + default: assert(0 && "Unknown unop"); + case CAST: { + StringInit *LHSs = dynamic_cast<StringInit*>(LHS); + if (LHSs) { + std::string Name = LHSs->getValue(); + + // From TGParser::ParseIDValue + if (CurRec) { + if (const RecordVal *RV = CurRec->getValue(Name)) { + if (RV->getType() != getType()) { + throw "type mismatch in nameconcat"; + } + return new VarInit(Name, RV->getType()); + } + + std::string TemplateArgName = CurRec->getName()+":"+Name; + if (CurRec->isTemplateArg(TemplateArgName)) { + const RecordVal *RV = CurRec->getValue(TemplateArgName); + assert(RV && "Template arg doesn't exist??"); + + if (RV->getType() != getType()) { + throw "type mismatch in nameconcat"; + } + + return new VarInit(TemplateArgName, RV->getType()); + } + } + + if (CurMultiClass) { + std::string MCName = CurMultiClass->Rec.getName()+"::"+Name; + if (CurMultiClass->Rec.isTemplateArg(MCName)) { + const RecordVal *RV = CurMultiClass->Rec.getValue(MCName); + assert(RV && "Template arg doesn't exist??"); + + if (RV->getType() != getType()) { + throw "type mismatch in nameconcat"; + } + + return new VarInit(MCName, RV->getType()); + } + } + + if (Record *D = Records.getDef(Name)) + return new DefInit(D); + + cerr << "Variable not defined: '" + Name + "'\n"; + assert(0 && "Variable not found"); + return 0; + } + break; + } + case CAR: { + ListInit *LHSl = dynamic_cast<ListInit*>(LHS); + if (LHSl) { + if (LHSl->getSize() == 0) { + assert(0 && "Empty list in car"); + return 0; + } + return LHSl->getElement(0); + } + break; + } + case CDR: { + ListInit *LHSl = dynamic_cast<ListInit*>(LHS); + if (LHSl) { + if (LHSl->getSize() == 0) { + assert(0 && "Empty list in cdr"); + return 0; + } + ListInit *Result = new ListInit(LHSl->begin()+1, LHSl->end()); + return Result; + } + break; + } + case LNULL: { + ListInit *LHSl = dynamic_cast<ListInit*>(LHS); + if (LHSl) { + if (LHSl->getSize() == 0) { + return new IntInit(1); + } + else { + return new IntInit(0); + } + } + break; + } + } + return this; +} + +Init *UnOpInit::resolveReferences(Record &R, const RecordVal *RV) { + Init *lhs = LHS->resolveReferences(R, RV); + + if (LHS != lhs) + return (new UnOpInit(getOpcode(), lhs, getType()))->Fold(&R, 0); + return Fold(&R, 0); +} + +std::string UnOpInit::getAsString() const { + std::string Result; + switch (Opc) { + case CAST: Result = "!cast<" + getType()->getAsString() + ">"; break; + case CAR: Result = "!car"; break; + case CDR: Result = "!cdr"; break; + case LNULL: Result = "!null"; break; + } + return Result + "(" + LHS->getAsString() + ")"; +} + +Init *BinOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) { + switch (getOpcode()) { + default: assert(0 && "Unknown binop"); + case CONCAT: { + DagInit *LHSs = dynamic_cast<DagInit*>(LHS); + DagInit *RHSs = dynamic_cast<DagInit*>(RHS); + if (LHSs && RHSs) { + DefInit *LOp = dynamic_cast<DefInit*>(LHSs->getOperator()); + DefInit *ROp = dynamic_cast<DefInit*>(RHSs->getOperator()); + if (LOp->getDef() != ROp->getDef()) { + bool LIsOps = + LOp->getDef()->getName() == "outs" || + LOp->getDef()->getName() != "ins" || + LOp->getDef()->getName() != "defs"; + bool RIsOps = + ROp->getDef()->getName() == "outs" || + ROp->getDef()->getName() != "ins" || + ROp->getDef()->getName() != "defs"; + if (!LIsOps || !RIsOps) + throw "Concated Dag operators do not match!"; + } + std::vector<Init*> Args; + std::vector<std::string> ArgNames; + for (unsigned i = 0, e = LHSs->getNumArgs(); i != e; ++i) { + Args.push_back(LHSs->getArg(i)); + ArgNames.push_back(LHSs->getArgName(i)); + } + for (unsigned i = 0, e = RHSs->getNumArgs(); i != e; ++i) { + Args.push_back(RHSs->getArg(i)); + ArgNames.push_back(RHSs->getArgName(i)); + } + return new DagInit(LHSs->getOperator(), "", Args, ArgNames); + } + break; + } + case STRCONCAT: { + StringInit *LHSs = dynamic_cast<StringInit*>(LHS); + StringInit *RHSs = dynamic_cast<StringInit*>(RHS); + if (LHSs && RHSs) + return new StringInit(LHSs->getValue() + RHSs->getValue()); + break; + } + case NAMECONCAT: { + StringInit *LHSs = dynamic_cast<StringInit*>(LHS); + StringInit *RHSs = dynamic_cast<StringInit*>(RHS); + if (LHSs && RHSs) { + std::string Name(LHSs->getValue() + RHSs->getValue()); + + // From TGParser::ParseIDValue + if (CurRec) { + if (const RecordVal *RV = CurRec->getValue(Name)) { + if (RV->getType() != getType()) { + throw "type mismatch in nameconcat"; + } + return new VarInit(Name, RV->getType()); + } + + std::string TemplateArgName = CurRec->getName()+":"+Name; + if (CurRec->isTemplateArg(TemplateArgName)) { + const RecordVal *RV = CurRec->getValue(TemplateArgName); + assert(RV && "Template arg doesn't exist??"); + + if (RV->getType() != getType()) { + throw "type mismatch in nameconcat"; + } + + return new VarInit(TemplateArgName, RV->getType()); + } + } + + if (CurMultiClass) { + std::string MCName = CurMultiClass->Rec.getName()+"::"+Name; + if (CurMultiClass->Rec.isTemplateArg(MCName)) { + const RecordVal *RV = CurMultiClass->Rec.getValue(MCName); + assert(RV && "Template arg doesn't exist??"); + + if (RV->getType() != getType()) { + throw "type mismatch in nameconcat"; + } + + return new VarInit(MCName, RV->getType()); + } + } + + if (Record *D = Records.getDef(Name)) + return new DefInit(D); + + cerr << "Variable not defined: '" + Name + "'\n"; + assert(0 && "Variable not found"); + return 0; + } + break; + } + case SHL: + case SRA: + case SRL: { + IntInit *LHSi = dynamic_cast<IntInit*>(LHS); + IntInit *RHSi = dynamic_cast<IntInit*>(RHS); + if (LHSi && RHSi) { + int64_t LHSv = LHSi->getValue(), RHSv = RHSi->getValue(); + int64_t Result; + switch (getOpcode()) { + default: assert(0 && "Bad opcode!"); + case SHL: Result = LHSv << RHSv; break; + case SRA: Result = LHSv >> RHSv; break; + case SRL: Result = (uint64_t)LHSv >> (uint64_t)RHSv; break; + } + return new IntInit(Result); + } + break; + } + } + return this; +} + +Init *BinOpInit::resolveReferences(Record &R, const RecordVal *RV) { + Init *lhs = LHS->resolveReferences(R, RV); + Init *rhs = RHS->resolveReferences(R, RV); + + if (LHS != lhs || RHS != rhs) + return (new BinOpInit(getOpcode(), lhs, rhs, getType()))->Fold(&R, 0); + return Fold(&R, 0); +} + +std::string BinOpInit::getAsString() const { + std::string Result; + switch (Opc) { + case CONCAT: Result = "!con"; break; + case SHL: Result = "!shl"; break; + case SRA: Result = "!sra"; break; + case SRL: Result = "!srl"; break; + case STRCONCAT: Result = "!strconcat"; break; + case NAMECONCAT: + Result = "!nameconcat<" + getType()->getAsString() + ">"; break; + } + return Result + "(" + LHS->getAsString() + ", " + RHS->getAsString() + ")"; +} + +static Init *ForeachHelper(Init *LHS, Init *MHS, Init *RHS, RecTy *Type, + Record *CurRec, MultiClass *CurMultiClass); + +static Init *EvaluateOperation(OpInit *RHSo, Init *LHS, Init *Arg, + RecTy *Type, Record *CurRec, + MultiClass *CurMultiClass) { + std::vector<Init *> NewOperands; + + TypedInit *TArg = dynamic_cast<TypedInit*>(Arg); + + // If this is a dag, recurse + if (TArg && TArg->getType()->getAsString() == "dag") { + Init *Result = ForeachHelper(LHS, Arg, RHSo, Type, + CurRec, CurMultiClass); + if (Result != 0) { + return Result; + } + else { + return 0; + } + } + + for (int i = 0; i < RHSo->getNumOperands(); ++i) { + OpInit *RHSoo = dynamic_cast<OpInit*>(RHSo->getOperand(i)); + + if (RHSoo) { + Init *Result = EvaluateOperation(RHSoo, LHS, Arg, + Type, CurRec, CurMultiClass); + if (Result != 0) { + NewOperands.push_back(Result); + } + else { + NewOperands.push_back(Arg); + } + } + else if (LHS->getAsString() == RHSo->getOperand(i)->getAsString()) { + NewOperands.push_back(Arg); + } + else { + NewOperands.push_back(RHSo->getOperand(i)); + } + } + + // Now run the operator and use its result as the new leaf + OpInit *NewOp = RHSo->clone(NewOperands); + Init *NewVal = NewOp->Fold(CurRec, CurMultiClass); + if (NewVal != NewOp) { + delete NewOp; + return NewVal; + } + return 0; +} + +static Init *ForeachHelper(Init *LHS, Init *MHS, Init *RHS, RecTy *Type, + Record *CurRec, MultiClass *CurMultiClass) { + DagInit *MHSd = dynamic_cast<DagInit*>(MHS); + ListInit *MHSl = dynamic_cast<ListInit*>(MHS); + + DagRecTy *DagType = dynamic_cast<DagRecTy*>(Type); + ListRecTy *ListType = dynamic_cast<ListRecTy*>(Type); + + OpInit *RHSo = dynamic_cast<OpInit*>(RHS); + + if (!RHSo) { + cerr << "!foreach requires an operator\n"; + assert(0 && "No operator for !foreach"); + } + + TypedInit *LHSt = dynamic_cast<TypedInit*>(LHS); + + if (!LHSt) { + cerr << "!foreach requires typed variable\n"; + assert(0 && "No typed variable for !foreach"); + } + + if ((MHSd && DagType) || (MHSl && ListType)) { + if (MHSd) { + Init *Val = MHSd->getOperator(); + Init *Result = EvaluateOperation(RHSo, LHS, Val, + Type, CurRec, CurMultiClass); + if (Result != 0) { + Val = Result; + } + + std::vector<std::pair<Init *, std::string> > args; + for (unsigned int i = 0; i < MHSd->getNumArgs(); ++i) { + Init *Arg; + std::string ArgName; + Arg = MHSd->getArg(i); + ArgName = MHSd->getArgName(i); + + // Process args + Init *Result = EvaluateOperation(RHSo, LHS, Arg, Type, + CurRec, CurMultiClass); + if (Result != 0) { + Arg = Result; + } + + // TODO: Process arg names + args.push_back(std::make_pair(Arg, ArgName)); + } + + return new DagInit(Val, "", args); + } + if (MHSl) { + std::vector<Init *> NewOperands; + std::vector<Init *> NewList(MHSl->begin(), MHSl->end()); + + for (ListInit::iterator li = NewList.begin(), + liend = NewList.end(); + li != liend; + ++li) { + Init *Item = *li; + NewOperands.clear(); + for(int i = 0; i < RHSo->getNumOperands(); ++i) { + // First, replace the foreach variable with the list item + if (LHS->getAsString() == RHSo->getOperand(i)->getAsString()) { + NewOperands.push_back(Item); + } + else { + NewOperands.push_back(RHSo->getOperand(i)); + } + } + + // Now run the operator and use its result as the new list item + OpInit *NewOp = RHSo->clone(NewOperands); + Init *NewItem = NewOp->Fold(CurRec, CurMultiClass); + if (NewItem != NewOp) { + *li = NewItem; + delete NewOp; + } + } + return new ListInit(NewList); + } + } + return 0; +} + +Init *TernOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) { + switch (getOpcode()) { + default: assert(0 && "Unknown binop"); + case SUBST: { + DefInit *LHSd = dynamic_cast<DefInit*>(LHS); + VarInit *LHSv = dynamic_cast<VarInit*>(LHS); + StringInit *LHSs = dynamic_cast<StringInit*>(LHS); + + DefInit *MHSd = dynamic_cast<DefInit*>(MHS); + VarInit *MHSv = dynamic_cast<VarInit*>(MHS); + StringInit *MHSs = dynamic_cast<StringInit*>(MHS); + + DefInit *RHSd = dynamic_cast<DefInit*>(RHS); + VarInit *RHSv = dynamic_cast<VarInit*>(RHS); + StringInit *RHSs = dynamic_cast<StringInit*>(RHS); + + if ((LHSd && MHSd && RHSd) + || (LHSv && MHSv && RHSv) + || (LHSs && MHSs && RHSs)) { + if (RHSd) { + Record *Val = RHSd->getDef(); + if (LHSd->getAsString() == RHSd->getAsString()) { + Val = MHSd->getDef(); + } + return new DefInit(Val); + } + if (RHSv) { + std::string Val = RHSv->getName(); + if (LHSv->getAsString() == RHSv->getAsString()) { + Val = MHSv->getName(); + } + return new VarInit(Val, getType()); + } + if (RHSs) { + std::string Val = RHSs->getValue(); + + std::string::size_type found; + do { + found = Val.find(LHSs->getValue()); + if (found != std::string::npos) { + Val.replace(found, LHSs->getValue().size(), MHSs->getValue()); + } + } while (found != std::string::npos); + + return new StringInit(Val); + } + } + break; + } + + case FOREACH: { + Init *Result = ForeachHelper(LHS, MHS, RHS, getType(), + CurRec, CurMultiClass); + if (Result != 0) { + return Result; + } + break; + } + + case IF: { + IntInit *LHSi = dynamic_cast<IntInit*>(LHS); + if (LHSi) { + if (LHSi->getValue()) { + return MHS; + } + else { + return RHS; + } + } + break; + } + } + + return this; +} + +Init *TernOpInit::resolveReferences(Record &R, const RecordVal *RV) { + Init *lhs = LHS->resolveReferences(R, RV); + Init *mhs = MHS->resolveReferences(R, RV); + Init *rhs = RHS->resolveReferences(R, RV); + + if (LHS != lhs || MHS != mhs || RHS != rhs) + return (new TernOpInit(getOpcode(), lhs, mhs, rhs, getType()))->Fold(&R, 0); + return Fold(&R, 0); +} + +std::string TernOpInit::getAsString() const { + std::string Result; + switch (Opc) { + case SUBST: Result = "!subst"; break; + case FOREACH: Result = "!foreach"; break; + case IF: Result = "!if"; break; + } + return Result + "(" + LHS->getAsString() + ", " + MHS->getAsString() + ", " + + RHS->getAsString() + ")"; +} + +Init *TypedInit::convertInitializerBitRange(const std::vector<unsigned> &Bits) { + BitsRecTy *T = dynamic_cast<BitsRecTy*>(getType()); + if (T == 0) return 0; // Cannot subscript a non-bits variable... + unsigned NumBits = T->getNumBits(); + + BitsInit *BI = new BitsInit(Bits.size()); + for (unsigned i = 0, e = Bits.size(); i != e; ++i) { + if (Bits[i] >= NumBits) { + delete BI; + return 0; + } + BI->setBit(i, new VarBitInit(this, Bits[i])); + } + return BI; +} + +Init *TypedInit::convertInitListSlice(const std::vector<unsigned> &Elements) { + ListRecTy *T = dynamic_cast<ListRecTy*>(getType()); + if (T == 0) return 0; // Cannot subscript a non-list variable... + + if (Elements.size() == 1) + return new VarListElementInit(this, Elements[0]); + + std::vector<Init*> ListInits; + ListInits.reserve(Elements.size()); + for (unsigned i = 0, e = Elements.size(); i != e; ++i) + ListInits.push_back(new VarListElementInit(this, Elements[i])); + return new ListInit(ListInits); +} + + +Init *VarInit::resolveBitReference(Record &R, const RecordVal *IRV, + unsigned Bit) { + if (R.isTemplateArg(getName())) return 0; + if (IRV && IRV->getName() != getName()) return 0; + + RecordVal *RV = R.getValue(getName()); + assert(RV && "Reference to a non-existant variable?"); + assert(dynamic_cast<BitsInit*>(RV->getValue())); + BitsInit *BI = (BitsInit*)RV->getValue(); + + assert(Bit < BI->getNumBits() && "Bit reference out of range!"); + Init *B = BI->getBit(Bit); + + if (!dynamic_cast<UnsetInit*>(B)) // If the bit is not set... + return B; // Replace the VarBitInit with it. + return 0; +} + +Init *VarInit::resolveListElementReference(Record &R, const RecordVal *IRV, + unsigned Elt) { + if (R.isTemplateArg(getName())) return 0; + if (IRV && IRV->getName() != getName()) return 0; + + RecordVal *RV = R.getValue(getName()); + assert(RV && "Reference to a non-existant variable?"); + ListInit *LI = dynamic_cast<ListInit*>(RV->getValue()); + if (!LI) { + VarInit *VI = dynamic_cast<VarInit*>(RV->getValue()); + assert(VI && "Invalid list element!"); + return new VarListElementInit(VI, Elt); + } + + if (Elt >= LI->getSize()) + return 0; // Out of range reference. + Init *E = LI->getElement(Elt); + if (!dynamic_cast<UnsetInit*>(E)) // If the element is set + return E; // Replace the VarListElementInit with it. + return 0; +} + + +RecTy *VarInit::getFieldType(const std::string &FieldName) const { + if (RecordRecTy *RTy = dynamic_cast<RecordRecTy*>(getType())) + if (const RecordVal *RV = RTy->getRecord()->getValue(FieldName)) + return RV->getType(); + return 0; +} + +Init *VarInit::getFieldInit(Record &R, const std::string &FieldName) const { + if (dynamic_cast<RecordRecTy*>(getType())) + if (const RecordVal *RV = R.getValue(VarName)) { + Init *TheInit = RV->getValue(); + assert(TheInit != this && "Infinite loop detected!"); + if (Init *I = TheInit->getFieldInit(R, FieldName)) + return I; + else + return 0; + } + return 0; +} + +/// resolveReferences - This method is used by classes that refer to other +/// variables which may not be defined at the time they expression is formed. +/// If a value is set for the variable later, this method will be called on +/// users of the value to allow the value to propagate out. +/// +Init *VarInit::resolveReferences(Record &R, const RecordVal *RV) { + if (RecordVal *Val = R.getValue(VarName)) + if (RV == Val || (RV == 0 && !dynamic_cast<UnsetInit*>(Val->getValue()))) + return Val->getValue(); + return this; +} + +std::string VarBitInit::getAsString() const { + return TI->getAsString() + "{" + utostr(Bit) + "}"; +} + +Init *VarBitInit::resolveReferences(Record &R, const RecordVal *RV) { + if (Init *I = getVariable()->resolveBitReference(R, RV, getBitNum())) + return I; + return this; +} + +std::string VarListElementInit::getAsString() const { + return TI->getAsString() + "[" + utostr(Element) + "]"; +} + +Init *VarListElementInit::resolveReferences(Record &R, const RecordVal *RV) { + if (Init *I = getVariable()->resolveListElementReference(R, RV, + getElementNum())) + return I; + return this; +} + +Init *VarListElementInit::resolveBitReference(Record &R, const RecordVal *RV, + unsigned Bit) { + // FIXME: This should be implemented, to support references like: + // bit B = AA[0]{1}; + return 0; +} + +Init *VarListElementInit:: +resolveListElementReference(Record &R, const RecordVal *RV, unsigned Elt) { + // FIXME: This should be implemented, to support references like: + // int B = AA[0][1]; + return 0; +} + +RecTy *DefInit::getFieldType(const std::string &FieldName) const { + if (const RecordVal *RV = Def->getValue(FieldName)) + return RV->getType(); + return 0; +} + +Init *DefInit::getFieldInit(Record &R, const std::string &FieldName) const { + return Def->getValue(FieldName)->getValue(); +} + + +std::string DefInit::getAsString() const { + return Def->getName(); +} + +Init *FieldInit::resolveBitReference(Record &R, const RecordVal *RV, + unsigned Bit) { + if (Init *BitsVal = Rec->getFieldInit(R, FieldName)) + if (BitsInit *BI = dynamic_cast<BitsInit*>(BitsVal)) { + assert(Bit < BI->getNumBits() && "Bit reference out of range!"); + Init *B = BI->getBit(Bit); + + if (dynamic_cast<BitInit*>(B)) // If the bit is set... + return B; // Replace the VarBitInit with it. + } + return 0; +} + +Init *FieldInit::resolveListElementReference(Record &R, const RecordVal *RV, + unsigned Elt) { + if (Init *ListVal = Rec->getFieldInit(R, FieldName)) + if (ListInit *LI = dynamic_cast<ListInit*>(ListVal)) { + if (Elt >= LI->getSize()) return 0; + Init *E = LI->getElement(Elt); + + if (!dynamic_cast<UnsetInit*>(E)) // If the bit is set... + return E; // Replace the VarListElementInit with it. + } + return 0; +} + +Init *FieldInit::resolveReferences(Record &R, const RecordVal *RV) { + Init *NewRec = RV ? Rec->resolveReferences(R, RV) : Rec; + + Init *BitsVal = NewRec->getFieldInit(R, FieldName); + if (BitsVal) { + Init *BVR = BitsVal->resolveReferences(R, RV); + return BVR->isComplete() ? BVR : this; + } + + if (NewRec != Rec) { + return new FieldInit(NewRec, FieldName); + } + return this; +} + +Init *DagInit::resolveReferences(Record &R, const RecordVal *RV) { + std::vector<Init*> NewArgs; + for (unsigned i = 0, e = Args.size(); i != e; ++i) + NewArgs.push_back(Args[i]->resolveReferences(R, RV)); + + Init *Op = Val->resolveReferences(R, RV); + + if (Args != NewArgs || Op != Val) + return new DagInit(Op, "", NewArgs, ArgNames); + + return this; +} + + +std::string DagInit::getAsString() const { + std::string Result = "(" + Val->getAsString(); + if (!ValName.empty()) + Result += ":" + ValName; + if (Args.size()) { + Result += " " + Args[0]->getAsString(); + if (!ArgNames[0].empty()) Result += ":$" + ArgNames[0]; + for (unsigned i = 1, e = Args.size(); i != e; ++i) { + Result += ", " + Args[i]->getAsString(); + if (!ArgNames[i].empty()) Result += ":$" + ArgNames[i]; + } + } + return Result + ")"; +} + + +//===----------------------------------------------------------------------===// +// Other implementations +//===----------------------------------------------------------------------===// + +RecordVal::RecordVal(const std::string &N, RecTy *T, unsigned P) + : Name(N), Ty(T), Prefix(P) { + Value = Ty->convertValue(new UnsetInit()); + assert(Value && "Cannot create unset value for current type!"); +} + +void RecordVal::dump() const { cerr << *this; } + +void RecordVal::print(std::ostream &OS, bool PrintSem) const { + if (getPrefix()) OS << "field "; + OS << *getType() << " " << getName(); + + if (getValue()) + OS << " = " << *getValue(); + + if (PrintSem) OS << ";\n"; +} + +void Record::setName(const std::string &Name) { + if (Records.getDef(getName()) == this) { + Records.removeDef(getName()); + this->Name = Name; + Records.addDef(this); + } else { + Records.removeClass(getName()); + this->Name = Name; + Records.addClass(this); + } +} + +/// resolveReferencesTo - If anything in this record refers to RV, replace the +/// reference to RV with the RHS of RV. If RV is null, we resolve all possible +/// references. +void Record::resolveReferencesTo(const RecordVal *RV) { + for (unsigned i = 0, e = Values.size(); i != e; ++i) { + if (Init *V = Values[i].getValue()) + Values[i].setValue(V->resolveReferences(*this, RV)); + } +} + + +void Record::dump() const { cerr << *this; } + +std::ostream &llvm::operator<<(std::ostream &OS, const Record &R) { + OS << R.getName(); + + const std::vector<std::string> &TArgs = R.getTemplateArgs(); + if (!TArgs.empty()) { + OS << "<"; + for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { + if (i) OS << ", "; + const RecordVal *RV = R.getValue(TArgs[i]); + assert(RV && "Template argument record not found??"); + RV->print(OS, false); + } + OS << ">"; + } + + OS << " {"; + const std::vector<Record*> &SC = R.getSuperClasses(); + if (!SC.empty()) { + OS << "\t//"; + for (unsigned i = 0, e = SC.size(); i != e; ++i) + OS << " " << SC[i]->getName(); + } + OS << "\n"; + + const std::vector<RecordVal> &Vals = R.getValues(); + for (unsigned i = 0, e = Vals.size(); i != e; ++i) + if (Vals[i].getPrefix() && !R.isTemplateArg(Vals[i].getName())) + OS << Vals[i]; + for (unsigned i = 0, e = Vals.size(); i != e; ++i) + if (!Vals[i].getPrefix() && !R.isTemplateArg(Vals[i].getName())) + OS << Vals[i]; + + return OS << "}\n"; +} + +/// getValueInit - Return the initializer for a value with the specified name, +/// or throw an exception if the field does not exist. +/// +Init *Record::getValueInit(const std::string &FieldName) const { + const RecordVal *R = getValue(FieldName); + if (R == 0 || R->getValue() == 0) + throw "Record `" + getName() + "' does not have a field named `" + + FieldName + "'!\n"; + return R->getValue(); +} + + +/// getValueAsString - This method looks up the specified field and returns its +/// value as a string, throwing an exception if the field does not exist or if +/// the value is not a string. +/// +std::string Record::getValueAsString(const std::string &FieldName) const { + const RecordVal *R = getValue(FieldName); + if (R == 0 || R->getValue() == 0) + throw "Record `" + getName() + "' does not have a field named `" + + FieldName + "'!\n"; + + if (const StringInit *SI = dynamic_cast<const StringInit*>(R->getValue())) + return SI->getValue(); + throw "Record `" + getName() + "', field `" + FieldName + + "' does not have a string initializer!"; +} + +/// getValueAsBitsInit - This method looks up the specified field and returns +/// its value as a BitsInit, throwing an exception if the field does not exist +/// or if the value is not the right type. +/// +BitsInit *Record::getValueAsBitsInit(const std::string &FieldName) const { + const RecordVal *R = getValue(FieldName); + if (R == 0 || R->getValue() == 0) + throw "Record `" + getName() + "' does not have a field named `" + + FieldName + "'!\n"; + + if (BitsInit *BI = dynamic_cast<BitsInit*>(R->getValue())) + return BI; + throw "Record `" + getName() + "', field `" + FieldName + + "' does not have a BitsInit initializer!"; +} + +/// getValueAsListInit - This method looks up the specified field and returns +/// its value as a ListInit, throwing an exception if the field does not exist +/// or if the value is not the right type. +/// +ListInit *Record::getValueAsListInit(const std::string &FieldName) const { + const RecordVal *R = getValue(FieldName); + if (R == 0 || R->getValue() == 0) + throw "Record `" + getName() + "' does not have a field named `" + + FieldName + "'!\n"; + + if (ListInit *LI = dynamic_cast<ListInit*>(R->getValue())) + return LI; + throw "Record `" + getName() + "', field `" + FieldName + + "' does not have a list initializer!"; +} + +/// getValueAsListOfDefs - This method looks up the specified field and returns +/// its value as a vector of records, throwing an exception if the field does +/// not exist or if the value is not the right type. +/// +std::vector<Record*> +Record::getValueAsListOfDefs(const std::string &FieldName) const { + ListInit *List = getValueAsListInit(FieldName); + std::vector<Record*> Defs; + for (unsigned i = 0; i < List->getSize(); i++) { + if (DefInit *DI = dynamic_cast<DefInit*>(List->getElement(i))) { + Defs.push_back(DI->getDef()); + } else { + throw "Record `" + getName() + "', field `" + FieldName + + "' list is not entirely DefInit!"; + } + } + return Defs; +} + +/// getValueAsInt - This method looks up the specified field and returns its +/// value as an int64_t, throwing an exception if the field does not exist or if +/// the value is not the right type. +/// +int64_t Record::getValueAsInt(const std::string &FieldName) const { + const RecordVal *R = getValue(FieldName); + if (R == 0 || R->getValue() == 0) + throw "Record `" + getName() + "' does not have a field named `" + + FieldName + "'!\n"; + + if (IntInit *II = dynamic_cast<IntInit*>(R->getValue())) + return II->getValue(); + throw "Record `" + getName() + "', field `" + FieldName + + "' does not have an int initializer!"; +} + +/// getValueAsListOfInts - This method looks up the specified field and returns +/// its value as a vector of integers, throwing an exception if the field does +/// not exist or if the value is not the right type. +/// +std::vector<int64_t> +Record::getValueAsListOfInts(const std::string &FieldName) const { + ListInit *List = getValueAsListInit(FieldName); + std::vector<int64_t> Ints; + for (unsigned i = 0; i < List->getSize(); i++) { + if (IntInit *II = dynamic_cast<IntInit*>(List->getElement(i))) { + Ints.push_back(II->getValue()); + } else { + throw "Record `" + getName() + "', field `" + FieldName + + "' does not have a list of ints initializer!"; + } + } + return Ints; +} + +/// getValueAsDef - This method looks up the specified field and returns its +/// value as a Record, throwing an exception if the field does not exist or if +/// the value is not the right type. +/// +Record *Record::getValueAsDef(const std::string &FieldName) const { + const RecordVal *R = getValue(FieldName); + if (R == 0 || R->getValue() == 0) + throw "Record `" + getName() + "' does not have a field named `" + + FieldName + "'!\n"; + + if (DefInit *DI = dynamic_cast<DefInit*>(R->getValue())) + return DI->getDef(); + throw "Record `" + getName() + "', field `" + FieldName + + "' does not have a def initializer!"; +} + +/// getValueAsBit - This method looks up the specified field and returns its +/// value as a bit, throwing an exception if the field does not exist or if +/// the value is not the right type. +/// +bool Record::getValueAsBit(const std::string &FieldName) const { + const RecordVal *R = getValue(FieldName); + if (R == 0 || R->getValue() == 0) + throw "Record `" + getName() + "' does not have a field named `" + + FieldName + "'!\n"; + + if (BitInit *BI = dynamic_cast<BitInit*>(R->getValue())) + return BI->getValue(); + throw "Record `" + getName() + "', field `" + FieldName + + "' does not have a bit initializer!"; +} + +/// getValueAsDag - This method looks up the specified field and returns its +/// value as an Dag, throwing an exception if the field does not exist or if +/// the value is not the right type. +/// +DagInit *Record::getValueAsDag(const std::string &FieldName) const { + const RecordVal *R = getValue(FieldName); + if (R == 0 || R->getValue() == 0) + throw "Record `" + getName() + "' does not have a field named `" + + FieldName + "'!\n"; + + if (DagInit *DI = dynamic_cast<DagInit*>(R->getValue())) + return DI; + throw "Record `" + getName() + "', field `" + FieldName + + "' does not have a dag initializer!"; +} + +std::string Record::getValueAsCode(const std::string &FieldName) const { + const RecordVal *R = getValue(FieldName); + if (R == 0 || R->getValue() == 0) + throw "Record `" + getName() + "' does not have a field named `" + + FieldName + "'!\n"; + + if (const CodeInit *CI = dynamic_cast<const CodeInit*>(R->getValue())) + return CI->getValue(); + throw "Record `" + getName() + "', field `" + FieldName + + "' does not have a code initializer!"; +} + + +void MultiClass::dump() const { + cerr << "Record:\n"; + Rec.dump(); + + cerr << "Defs:\n"; + for (RecordVector::const_iterator r = DefPrototypes.begin(), + rend = DefPrototypes.end(); + r != rend; + ++r) { + (*r)->dump(); + } +} + + +void RecordKeeper::dump() const { cerr << *this; } + +std::ostream &llvm::operator<<(std::ostream &OS, const RecordKeeper &RK) { + OS << "------------- Classes -----------------\n"; + const std::map<std::string, Record*> &Classes = RK.getClasses(); + for (std::map<std::string, Record*>::const_iterator I = Classes.begin(), + E = Classes.end(); I != E; ++I) + OS << "class " << *I->second; + + OS << "------------- Defs -----------------\n"; + const std::map<std::string, Record*> &Defs = RK.getDefs(); + for (std::map<std::string, Record*>::const_iterator I = Defs.begin(), + E = Defs.end(); I != E; ++I) + OS << "def " << *I->second; + return OS; +} + + +/// getAllDerivedDefinitions - This method returns all concrete definitions +/// that derive from the specified class name. If a class with the specified +/// name does not exist, an error is printed and true is returned. +std::vector<Record*> +RecordKeeper::getAllDerivedDefinitions(const std::string &ClassName) const { + Record *Class = Records.getClass(ClassName); + if (!Class) + throw "ERROR: Couldn't find the `" + ClassName + "' class!\n"; + + std::vector<Record*> Defs; + for (std::map<std::string, Record*>::const_iterator I = getDefs().begin(), + E = getDefs().end(); I != E; ++I) + if (I->second->isSubClassOf(Class)) + Defs.push_back(I->second); + + return Defs; +} + diff --git a/utils/TableGen/Record.h b/utils/TableGen/Record.h new file mode 100644 index 0000000000000..4284cabf85579 --- /dev/null +++ b/utils/TableGen/Record.h @@ -0,0 +1,1444 @@ +//===- Record.h - Classes to represent Table Records ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the main TableGen data structures, including the TableGen +// types, values, and high-level data structures. +// +//===----------------------------------------------------------------------===// + +#ifndef RECORD_H +#define RECORD_H + +#include "TGSourceMgr.h" +#include "llvm/Support/DataTypes.h" +#include <map> +#include <ostream> + +namespace llvm { + +// RecTy subclasses. +class BitRecTy; +class BitsRecTy; +class IntRecTy; +class StringRecTy; +class ListRecTy; +class CodeRecTy; +class DagRecTy; +class RecordRecTy; + +// Init subclasses. +struct Init; +class UnsetInit; +class BitInit; +class BitsInit; +class IntInit; +class StringInit; +class CodeInit; +class ListInit; +class UnOpInit; +class BinOpInit; +class TernOpInit; +class DefInit; +class DagInit; +class TypedInit; +class VarInit; +class FieldInit; +class VarBitInit; +class VarListElementInit; + +// Other classes. +class Record; +class RecordVal; +struct MultiClass; + +//===----------------------------------------------------------------------===// +// Type Classes +//===----------------------------------------------------------------------===// + +struct RecTy { + virtual ~RecTy() {} + + virtual std::string getAsString() const = 0; + void print(std::ostream &OS) const { OS << getAsString(); } + void dump() const; + + /// typeIsConvertibleTo - Return true if all values of 'this' type can be + /// converted to the specified type. + virtual bool typeIsConvertibleTo(const RecTy *RHS) const = 0; + +public: // These methods should only be called from subclasses of Init + virtual Init *convertValue( UnsetInit *UI) { return 0; } + virtual Init *convertValue( BitInit *BI) { return 0; } + virtual Init *convertValue( BitsInit *BI) { return 0; } + virtual Init *convertValue( IntInit *II) { return 0; } + virtual Init *convertValue(StringInit *SI) { return 0; } + virtual Init *convertValue( ListInit *LI) { return 0; } + virtual Init *convertValue( UnOpInit *UI) { + return convertValue((TypedInit*)UI); + } + virtual Init *convertValue( BinOpInit *UI) { + return convertValue((TypedInit*)UI); + } + virtual Init *convertValue( TernOpInit *UI) { + return convertValue((TypedInit*)UI); + } + virtual Init *convertValue( CodeInit *CI) { return 0; } + virtual Init *convertValue(VarBitInit *VB) { return 0; } + virtual Init *convertValue( DefInit *DI) { return 0; } + virtual Init *convertValue( DagInit *DI) { return 0; } + virtual Init *convertValue( TypedInit *TI) { return 0; } + virtual Init *convertValue( VarInit *VI) { + return convertValue((TypedInit*)VI); + } + virtual Init *convertValue( FieldInit *FI) { + return convertValue((TypedInit*)FI); + } + +public: // These methods should only be called by subclasses of RecTy. + // baseClassOf - These virtual methods should be overloaded to return true iff + // all values of type 'RHS' can be converted to the 'this' type. + virtual bool baseClassOf(const BitRecTy *RHS) const { return false; } + virtual bool baseClassOf(const BitsRecTy *RHS) const { return false; } + virtual bool baseClassOf(const IntRecTy *RHS) const { return false; } + virtual bool baseClassOf(const StringRecTy *RHS) const { return false; } + virtual bool baseClassOf(const ListRecTy *RHS) const { return false; } + virtual bool baseClassOf(const CodeRecTy *RHS) const { return false; } + virtual bool baseClassOf(const DagRecTy *RHS) const { return false; } + virtual bool baseClassOf(const RecordRecTy *RHS) const { return false; } +}; + +inline std::ostream &operator<<(std::ostream &OS, const RecTy &Ty) { + Ty.print(OS); + return OS; +} + + +/// BitRecTy - 'bit' - Represent a single bit +/// +class BitRecTy : public RecTy { +public: + virtual Init *convertValue( UnsetInit *UI) { return (Init*)UI; } + virtual Init *convertValue( BitInit *BI) { return (Init*)BI; } + virtual Init *convertValue( BitsInit *BI); + virtual Init *convertValue( IntInit *II); + virtual Init *convertValue(StringInit *SI) { return 0; } + virtual Init *convertValue( ListInit *LI) { return 0; } + virtual Init *convertValue( CodeInit *CI) { return 0; } + virtual Init *convertValue(VarBitInit *VB) { return (Init*)VB; } + virtual Init *convertValue( DefInit *DI) { return 0; } + virtual Init *convertValue( DagInit *DI) { return 0; } + virtual Init *convertValue( UnOpInit *UI) { return RecTy::convertValue(UI);} + virtual Init *convertValue( BinOpInit *UI) { return RecTy::convertValue(UI);} + virtual Init *convertValue( TernOpInit *UI) { return RecTy::convertValue(UI);} + virtual Init *convertValue( TypedInit *TI); + virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);} + virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);} + + std::string getAsString() const { return "bit"; } + + bool typeIsConvertibleTo(const RecTy *RHS) const { + return RHS->baseClassOf(this); + } + virtual bool baseClassOf(const BitRecTy *RHS) const { return true; } + virtual bool baseClassOf(const BitsRecTy *RHS) const; + virtual bool baseClassOf(const IntRecTy *RHS) const { return true; } + virtual bool baseClassOf(const StringRecTy *RHS) const { return false; } + virtual bool baseClassOf(const ListRecTy *RHS) const { return false; } + virtual bool baseClassOf(const CodeRecTy *RHS) const { return false; } + virtual bool baseClassOf(const DagRecTy *RHS) const { return false; } + virtual bool baseClassOf(const RecordRecTy *RHS) const { return false; } + +}; + + +// BitsRecTy - 'bits<n>' - Represent a fixed number of bits +/// BitsRecTy - 'bits<n>' - Represent a fixed number of bits +/// +class BitsRecTy : public RecTy { + unsigned Size; +public: + explicit BitsRecTy(unsigned Sz) : Size(Sz) {} + + unsigned getNumBits() const { return Size; } + + virtual Init *convertValue( UnsetInit *UI); + virtual Init *convertValue( BitInit *UI); + virtual Init *convertValue( BitsInit *BI); + virtual Init *convertValue( IntInit *II); + virtual Init *convertValue(StringInit *SI) { return 0; } + virtual Init *convertValue( ListInit *LI) { return 0; } + virtual Init *convertValue( CodeInit *CI) { return 0; } + virtual Init *convertValue(VarBitInit *VB) { return 0; } + virtual Init *convertValue( DefInit *DI) { return 0; } + virtual Init *convertValue( DagInit *DI) { return 0; } + virtual Init *convertValue( UnOpInit *UI) { return RecTy::convertValue(UI);} + virtual Init *convertValue( BinOpInit *UI) { return RecTy::convertValue(UI);} + virtual Init *convertValue( TernOpInit *UI) { return RecTy::convertValue(UI);} + virtual Init *convertValue( TypedInit *TI); + virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);} + virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);} + + std::string getAsString() const; + + bool typeIsConvertibleTo(const RecTy *RHS) const { + return RHS->baseClassOf(this); + } + virtual bool baseClassOf(const BitRecTy *RHS) const { return Size == 1; } + virtual bool baseClassOf(const BitsRecTy *RHS) const { + return RHS->Size == Size; + } + virtual bool baseClassOf(const IntRecTy *RHS) const { return true; } + virtual bool baseClassOf(const StringRecTy *RHS) const { return false; } + virtual bool baseClassOf(const ListRecTy *RHS) const { return false; } + virtual bool baseClassOf(const CodeRecTy *RHS) const { return false; } + virtual bool baseClassOf(const DagRecTy *RHS) const { return false; } + virtual bool baseClassOf(const RecordRecTy *RHS) const { return false; } + +}; + + +/// IntRecTy - 'int' - Represent an integer value of no particular size +/// +class IntRecTy : public RecTy { +public: + virtual Init *convertValue( UnsetInit *UI) { return (Init*)UI; } + virtual Init *convertValue( BitInit *BI); + virtual Init *convertValue( BitsInit *BI); + virtual Init *convertValue( IntInit *II) { return (Init*)II; } + virtual Init *convertValue(StringInit *SI) { return 0; } + virtual Init *convertValue( ListInit *LI) { return 0; } + virtual Init *convertValue( CodeInit *CI) { return 0; } + virtual Init *convertValue(VarBitInit *VB) { return 0; } + virtual Init *convertValue( DefInit *DI) { return 0; } + virtual Init *convertValue( DagInit *DI) { return 0; } + virtual Init *convertValue( UnOpInit *UI) { return RecTy::convertValue(UI);} + virtual Init *convertValue( BinOpInit *UI) { return RecTy::convertValue(UI);} + virtual Init *convertValue( TernOpInit *UI) { return RecTy::convertValue(UI);} + virtual Init *convertValue( TypedInit *TI); + virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);} + virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);} + + std::string getAsString() const { return "int"; } + + bool typeIsConvertibleTo(const RecTy *RHS) const { + return RHS->baseClassOf(this); + } + + virtual bool baseClassOf(const BitRecTy *RHS) const { return true; } + virtual bool baseClassOf(const BitsRecTy *RHS) const { return true; } + virtual bool baseClassOf(const IntRecTy *RHS) const { return true; } + virtual bool baseClassOf(const StringRecTy *RHS) const { return false; } + virtual bool baseClassOf(const ListRecTy *RHS) const { return false; } + virtual bool baseClassOf(const CodeRecTy *RHS) const { return false; } + virtual bool baseClassOf(const DagRecTy *RHS) const { return false; } + virtual bool baseClassOf(const RecordRecTy *RHS) const { return false; } + +}; + +/// StringRecTy - 'string' - Represent an string value +/// +class StringRecTy : public RecTy { +public: + virtual Init *convertValue( UnsetInit *UI) { return (Init*)UI; } + virtual Init *convertValue( BitInit *BI) { return 0; } + virtual Init *convertValue( BitsInit *BI) { return 0; } + virtual Init *convertValue( IntInit *II) { return 0; } + virtual Init *convertValue(StringInit *SI) { return (Init*)SI; } + virtual Init *convertValue( ListInit *LI) { return 0; } + virtual Init *convertValue( UnOpInit *BO); + virtual Init *convertValue( BinOpInit *BO); + virtual Init *convertValue( TernOpInit *BO) { return RecTy::convertValue(BO);} + + virtual Init *convertValue( CodeInit *CI) { return 0; } + virtual Init *convertValue(VarBitInit *VB) { return 0; } + virtual Init *convertValue( DefInit *DI) { return 0; } + virtual Init *convertValue( DagInit *DI) { return 0; } + virtual Init *convertValue( TypedInit *TI); + virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);} + virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);} + + std::string getAsString() const { return "string"; } + + bool typeIsConvertibleTo(const RecTy *RHS) const { + return RHS->baseClassOf(this); + } + + virtual bool baseClassOf(const BitRecTy *RHS) const { return false; } + virtual bool baseClassOf(const BitsRecTy *RHS) const { return false; } + virtual bool baseClassOf(const IntRecTy *RHS) const { return false; } + virtual bool baseClassOf(const StringRecTy *RHS) const { return true; } + virtual bool baseClassOf(const ListRecTy *RHS) const { return false; } + virtual bool baseClassOf(const CodeRecTy *RHS) const { return false; } + virtual bool baseClassOf(const DagRecTy *RHS) const { return false; } + virtual bool baseClassOf(const RecordRecTy *RHS) const { return false; } +}; + +// ListRecTy - 'list<Ty>' - Represent a list of values, all of which must be of +// the specified type. +/// ListRecTy - 'list<Ty>' - Represent a list of values, all of which must +/// be of the specified type. +/// +class ListRecTy : public RecTy { + RecTy *Ty; +public: + explicit ListRecTy(RecTy *T) : Ty(T) {} + + RecTy *getElementType() const { return Ty; } + + virtual Init *convertValue( UnsetInit *UI) { return (Init*)UI; } + virtual Init *convertValue( BitInit *BI) { return 0; } + virtual Init *convertValue( BitsInit *BI) { return 0; } + virtual Init *convertValue( IntInit *II) { return 0; } + virtual Init *convertValue(StringInit *SI) { return 0; } + virtual Init *convertValue( ListInit *LI); + virtual Init *convertValue( CodeInit *CI) { return 0; } + virtual Init *convertValue(VarBitInit *VB) { return 0; } + virtual Init *convertValue( DefInit *DI) { return 0; } + virtual Init *convertValue( DagInit *DI) { return 0; } + virtual Init *convertValue( UnOpInit *UI) { return RecTy::convertValue(UI);} + virtual Init *convertValue( BinOpInit *UI) { return RecTy::convertValue(UI);} + virtual Init *convertValue( TernOpInit *UI) { return RecTy::convertValue(UI);} + virtual Init *convertValue( TypedInit *TI); + virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);} + virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);} + + std::string getAsString() const; + + bool typeIsConvertibleTo(const RecTy *RHS) const { + return RHS->baseClassOf(this); + } + + virtual bool baseClassOf(const BitRecTy *RHS) const { return false; } + virtual bool baseClassOf(const BitsRecTy *RHS) const { return false; } + virtual bool baseClassOf(const IntRecTy *RHS) const { return false; } + virtual bool baseClassOf(const StringRecTy *RHS) const { return false; } + virtual bool baseClassOf(const ListRecTy *RHS) const { + return RHS->getElementType()->typeIsConvertibleTo(Ty); + } + virtual bool baseClassOf(const CodeRecTy *RHS) const { return false; } + virtual bool baseClassOf(const DagRecTy *RHS) const { return false; } + virtual bool baseClassOf(const RecordRecTy *RHS) const { return false; } +}; + +/// CodeRecTy - 'code' - Represent an code fragment, function or method. +/// +class CodeRecTy : public RecTy { +public: + virtual Init *convertValue( UnsetInit *UI) { return (Init*)UI; } + virtual Init *convertValue( BitInit *BI) { return 0; } + virtual Init *convertValue( BitsInit *BI) { return 0; } + virtual Init *convertValue( IntInit *II) { return 0; } + virtual Init *convertValue(StringInit *SI) { return 0; } + virtual Init *convertValue( ListInit *LI) { return 0; } + virtual Init *convertValue( CodeInit *CI) { return (Init*)CI; } + virtual Init *convertValue(VarBitInit *VB) { return 0; } + virtual Init *convertValue( DefInit *DI) { return 0; } + virtual Init *convertValue( DagInit *DI) { return 0; } + virtual Init *convertValue( UnOpInit *UI) { return RecTy::convertValue(UI);} + virtual Init *convertValue( BinOpInit *UI) { return RecTy::convertValue(UI);} + virtual Init *convertValue( TernOpInit *UI) { return RecTy::convertValue(UI);} + virtual Init *convertValue( TypedInit *TI); + virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);} + virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);} + + std::string getAsString() const { return "code"; } + + bool typeIsConvertibleTo(const RecTy *RHS) const { + return RHS->baseClassOf(this); + } + virtual bool baseClassOf(const BitRecTy *RHS) const { return false; } + virtual bool baseClassOf(const BitsRecTy *RHS) const { return false; } + virtual bool baseClassOf(const IntRecTy *RHS) const { return false; } + virtual bool baseClassOf(const StringRecTy *RHS) const { return false; } + virtual bool baseClassOf(const ListRecTy *RHS) const { return false; } + virtual bool baseClassOf(const CodeRecTy *RHS) const { return true; } + virtual bool baseClassOf(const DagRecTy *RHS) const { return false; } + virtual bool baseClassOf(const RecordRecTy *RHS) const { return false; } +}; + +/// DagRecTy - 'dag' - Represent a dag fragment +/// +class DagRecTy : public RecTy { +public: + virtual Init *convertValue( UnsetInit *UI) { return (Init*)UI; } + virtual Init *convertValue( BitInit *BI) { return 0; } + virtual Init *convertValue( BitsInit *BI) { return 0; } + virtual Init *convertValue( IntInit *II) { return 0; } + virtual Init *convertValue(StringInit *SI) { return 0; } + virtual Init *convertValue( ListInit *LI) { return 0; } + virtual Init *convertValue( CodeInit *CI) { return 0; } + virtual Init *convertValue(VarBitInit *VB) { return 0; } + virtual Init *convertValue( DefInit *DI) { return 0; } + virtual Init *convertValue( UnOpInit *BO); + virtual Init *convertValue( BinOpInit *BO); + virtual Init *convertValue( TernOpInit *BO) { return RecTy::convertValue(BO);} + virtual Init *convertValue( DagInit *CI) { return (Init*)CI; } + virtual Init *convertValue( TypedInit *TI); + virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);} + virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);} + + std::string getAsString() const { return "dag"; } + + bool typeIsConvertibleTo(const RecTy *RHS) const { + return RHS->baseClassOf(this); + } + + virtual bool baseClassOf(const BitRecTy *RHS) const { return false; } + virtual bool baseClassOf(const BitsRecTy *RHS) const { return false; } + virtual bool baseClassOf(const IntRecTy *RHS) const { return false; } + virtual bool baseClassOf(const StringRecTy *RHS) const { return false; } + virtual bool baseClassOf(const ListRecTy *RHS) const { return false; } + virtual bool baseClassOf(const CodeRecTy *RHS) const { return false; } + virtual bool baseClassOf(const DagRecTy *RHS) const { return true; } + virtual bool baseClassOf(const RecordRecTy *RHS) const { return false; } +}; + + +/// RecordRecTy - '[classname]' - Represent an instance of a class, such as: +/// (R32 X = EAX). +/// +class RecordRecTy : public RecTy { + Record *Rec; +public: + explicit RecordRecTy(Record *R) : Rec(R) {} + + Record *getRecord() const { return Rec; } + + virtual Init *convertValue( UnsetInit *UI) { return (Init*)UI; } + virtual Init *convertValue( BitInit *BI) { return 0; } + virtual Init *convertValue( BitsInit *BI) { return 0; } + virtual Init *convertValue( IntInit *II) { return 0; } + virtual Init *convertValue(StringInit *SI) { return 0; } + virtual Init *convertValue( ListInit *LI) { return 0; } + virtual Init *convertValue( CodeInit *CI) { return 0; } + virtual Init *convertValue(VarBitInit *VB) { return 0; } + virtual Init *convertValue( UnOpInit *UI) { return RecTy::convertValue(UI);} + virtual Init *convertValue( BinOpInit *UI) { return RecTy::convertValue(UI);} + virtual Init *convertValue( TernOpInit *UI) { return RecTy::convertValue(UI);} + virtual Init *convertValue( DefInit *DI); + virtual Init *convertValue( DagInit *DI) { return 0; } + virtual Init *convertValue( TypedInit *VI); + virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);} + virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);} + + std::string getAsString() const; + + bool typeIsConvertibleTo(const RecTy *RHS) const { + return RHS->baseClassOf(this); + } + virtual bool baseClassOf(const BitRecTy *RHS) const { return false; } + virtual bool baseClassOf(const BitsRecTy *RHS) const { return false; } + virtual bool baseClassOf(const IntRecTy *RHS) const { return false; } + virtual bool baseClassOf(const StringRecTy *RHS) const { return false; } + virtual bool baseClassOf(const ListRecTy *RHS) const { return false; } + virtual bool baseClassOf(const CodeRecTy *RHS) const { return false; } + virtual bool baseClassOf(const DagRecTy *RHS) const { return false; } + virtual bool baseClassOf(const RecordRecTy *RHS) const; +}; + + + +//===----------------------------------------------------------------------===// +// Initializer Classes +//===----------------------------------------------------------------------===// + +struct Init { + virtual ~Init() {} + + /// isComplete - This virtual method should be overridden by values that may + /// not be completely specified yet. + virtual bool isComplete() const { return true; } + + /// print - Print out this value. + void print(std::ostream &OS) const { OS << getAsString(); } + + /// getAsString - Convert this value to a string form. + virtual std::string getAsString() const = 0; + + /// dump - Debugging method that may be called through a debugger, just + /// invokes print on cerr. + void dump() const; + + /// convertInitializerTo - This virtual function is a simple call-back + /// function that should be overridden to call the appropriate + /// RecTy::convertValue method. + /// + virtual Init *convertInitializerTo(RecTy *Ty) = 0; + + /// convertInitializerBitRange - This method is used to implement the bitrange + /// selection operator. Given an initializer, it selects the specified bits + /// out, returning them as a new init of bits type. If it is not legal to use + /// the bit subscript operator on this initializer, return null. + /// + virtual Init *convertInitializerBitRange(const std::vector<unsigned> &Bits) { + return 0; + } + + /// convertInitListSlice - This method is used to implement the list slice + /// selection operator. Given an initializer, it selects the specified list + /// elements, returning them as a new init of list type. If it is not legal + /// to take a slice of this, return null. + /// + virtual Init *convertInitListSlice(const std::vector<unsigned> &Elements) { + return 0; + } + + /// getFieldType - This method is used to implement the FieldInit class. + /// Implementors of this method should return the type of the named field if + /// they are of record type. + /// + virtual RecTy *getFieldType(const std::string &FieldName) const { return 0; } + + /// getFieldInit - This method complements getFieldType to return the + /// initializer for the specified field. If getFieldType returns non-null + /// this method should return non-null, otherwise it returns null. + /// + virtual Init *getFieldInit(Record &R, const std::string &FieldName) const { + return 0; + } + + /// resolveReferences - This method is used by classes that refer to other + /// variables which may not be defined at the time they expression is formed. + /// If a value is set for the variable later, this method will be called on + /// users of the value to allow the value to propagate out. + /// + virtual Init *resolveReferences(Record &R, const RecordVal *RV) { + return this; + } +}; + +inline std::ostream &operator<<(std::ostream &OS, const Init &I) { + I.print(OS); return OS; +} + +/// TypedInit - This is the common super-class of types that have a specific, +/// explicit, type. +/// +class TypedInit : public Init { + RecTy *Ty; +public: + explicit TypedInit(RecTy *T) : Ty(T) {} + + RecTy *getType() const { return Ty; } + + virtual Init *convertInitializerBitRange(const std::vector<unsigned> &Bits); + virtual Init *convertInitListSlice(const std::vector<unsigned> &Elements); + + /// resolveBitReference - This method is used to implement + /// VarBitInit::resolveReferences. If the bit is able to be resolved, we + /// simply return the resolved value, otherwise we return null. + /// + virtual Init *resolveBitReference(Record &R, const RecordVal *RV, + unsigned Bit) = 0; + + /// resolveListElementReference - This method is used to implement + /// VarListElementInit::resolveReferences. If the list element is resolvable + /// now, we return the resolved value, otherwise we return null. + virtual Init *resolveListElementReference(Record &R, const RecordVal *RV, + unsigned Elt) = 0; +}; + + +/// UnsetInit - ? - Represents an uninitialized value +/// +class UnsetInit : public Init { +public: + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + + virtual bool isComplete() const { return false; } + virtual std::string getAsString() const { return "?"; } +}; + + +/// BitInit - true/false - Represent a concrete initializer for a bit. +/// +class BitInit : public Init { + bool Value; +public: + explicit BitInit(bool V) : Value(V) {} + + bool getValue() const { return Value; } + + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + + virtual std::string getAsString() const { return Value ? "1" : "0"; } +}; + +/// BitsInit - { a, b, c } - Represents an initializer for a BitsRecTy value. +/// It contains a vector of bits, whose size is determined by the type. +/// +class BitsInit : public Init { + std::vector<Init*> Bits; +public: + explicit BitsInit(unsigned Size) : Bits(Size) {} + + unsigned getNumBits() const { return Bits.size(); } + + Init *getBit(unsigned Bit) const { + assert(Bit < Bits.size() && "Bit index out of range!"); + return Bits[Bit]; + } + void setBit(unsigned Bit, Init *V) { + assert(Bit < Bits.size() && "Bit index out of range!"); + assert(Bits[Bit] == 0 && "Bit already set!"); + Bits[Bit] = V; + } + + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + virtual Init *convertInitializerBitRange(const std::vector<unsigned> &Bits); + + virtual bool isComplete() const { + for (unsigned i = 0; i != getNumBits(); ++i) + if (!getBit(i)->isComplete()) return false; + return true; + } + virtual std::string getAsString() const; + + virtual Init *resolveReferences(Record &R, const RecordVal *RV); + + // printXX - Print this bitstream with the specified format, returning true if + // it is not possible. + bool printInHex(std::ostream &OS) const; + bool printAsVariable(std::ostream &OS) const; + bool printAsUnset(std::ostream &OS) const; +}; + + +/// IntInit - 7 - Represent an initalization by a literal integer value. +/// +class IntInit : public Init { + int64_t Value; +public: + explicit IntInit(int64_t V) : Value(V) {} + + int64_t getValue() const { return Value; } + + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + virtual Init *convertInitializerBitRange(const std::vector<unsigned> &Bits); + + virtual std::string getAsString() const; +}; + + +/// StringInit - "foo" - Represent an initialization by a string value. +/// +class StringInit : public TypedInit { + std::string Value; +public: + explicit StringInit(const std::string &V) + : TypedInit(new StringRecTy), Value(V) {} + + const std::string &getValue() const { return Value; } + + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + + virtual std::string getAsString() const { return "\"" + Value + "\""; } + + /// resolveBitReference - This method is used to implement + /// VarBitInit::resolveReferences. If the bit is able to be resolved, we + /// simply return the resolved value, otherwise we return null. + /// + virtual Init *resolveBitReference(Record &R, const RecordVal *RV, + unsigned Bit) { + assert(0 && "Illegal bit reference off string"); + return 0; + } + + /// resolveListElementReference - This method is used to implement + /// VarListElementInit::resolveReferences. If the list element is resolvable + /// now, we return the resolved value, otherwise we return null. + virtual Init *resolveListElementReference(Record &R, const RecordVal *RV, + unsigned Elt) { + assert(0 && "Illegal element reference off string"); + return 0; + } +}; + +/// CodeInit - "[{...}]" - Represent a code fragment. +/// +class CodeInit : public Init { + std::string Value; +public: + explicit CodeInit(const std::string &V) : Value(V) {} + + const std::string getValue() const { return Value; } + + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + + virtual std::string getAsString() const { return "[{" + Value + "}]"; } +}; + +/// ListInit - [AL, AH, CL] - Represent a list of defs +/// +class ListInit : public Init { + std::vector<Init*> Values; +public: + typedef std::vector<Init*>::iterator iterator; + typedef std::vector<Init*>::const_iterator const_iterator; + + explicit ListInit(std::vector<Init*> &Vs) { + Values.swap(Vs); + } + explicit ListInit(iterator Start, iterator End) + : Values(Start, End) {} + + unsigned getSize() const { return Values.size(); } + Init *getElement(unsigned i) const { + assert(i < Values.size() && "List element index out of range!"); + return Values[i]; + } + + Record *getElementAsRecord(unsigned i) const; + + Init *convertInitListSlice(const std::vector<unsigned> &Elements); + + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + + /// resolveReferences - This method is used by classes that refer to other + /// variables which may not be defined at the time they expression is formed. + /// If a value is set for the variable later, this method will be called on + /// users of the value to allow the value to propagate out. + /// + virtual Init *resolveReferences(Record &R, const RecordVal *RV); + + virtual std::string getAsString() const; + + inline iterator begin() { return Values.begin(); } + inline const_iterator begin() const { return Values.begin(); } + inline iterator end () { return Values.end(); } + inline const_iterator end () const { return Values.end(); } + + inline size_t size () const { return Values.size(); } + inline bool empty() const { return Values.empty(); } +}; + + +/// OpInit - Base class for operators +/// +class OpInit : public TypedInit { +public: + OpInit(RecTy *Type) : TypedInit(Type) {} + + // Clone - Clone this operator, replacing arguments with the new list + virtual OpInit *clone(std::vector<Init *> &Operands) = 0; + + virtual int getNumOperands(void) const = 0; + virtual Init *getOperand(int i) = 0; + + // Fold - If possible, fold this to a simpler init. Return this if not + // possible to fold. + virtual Init *Fold(Record *CurRec, MultiClass *CurMultiClass) = 0; + + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + + virtual Init *resolveBitReference(Record &R, const RecordVal *RV, + unsigned Bit); + virtual Init *resolveListElementReference(Record &R, const RecordVal *RV, + unsigned Elt); +}; + + +/// UnOpInit - !op (X) - Transform an init. +/// +class UnOpInit : public OpInit { +public: + enum UnaryOp { CAST, CAR, CDR, LNULL }; +private: + UnaryOp Opc; + Init *LHS; +public: + UnOpInit(UnaryOp opc, Init *lhs, RecTy *Type) : + OpInit(Type), Opc(opc), LHS(lhs) { + } + + // Clone - Clone this operator, replacing arguments with the new list + virtual OpInit *clone(std::vector<Init *> &Operands) { + assert(Operands.size() == 1 && + "Wrong number of operands for unary operation"); + return new UnOpInit(getOpcode(), *Operands.begin(), getType()); + } + + int getNumOperands(void) const { return 1; } + Init *getOperand(int i) { + assert(i == 0 && "Invalid operand id for unary operator"); + return getOperand(); + } + + UnaryOp getOpcode() const { return Opc; } + Init *getOperand() const { return LHS; } + + // Fold - If possible, fold this to a simpler init. Return this if not + // possible to fold. + Init *Fold(Record *CurRec, MultiClass *CurMultiClass); + + virtual Init *resolveReferences(Record &R, const RecordVal *RV); + + virtual std::string getAsString() const; +}; + +/// BinOpInit - !op (X, Y) - Combine two inits. +/// +class BinOpInit : public OpInit { +public: + enum BinaryOp { SHL, SRA, SRL, STRCONCAT, CONCAT, NAMECONCAT }; +private: + BinaryOp Opc; + Init *LHS, *RHS; +public: + BinOpInit(BinaryOp opc, Init *lhs, Init *rhs, RecTy *Type) : + OpInit(Type), Opc(opc), LHS(lhs), RHS(rhs) { + } + + // Clone - Clone this operator, replacing arguments with the new list + virtual OpInit *clone(std::vector<Init *> &Operands) { + assert(Operands.size() == 2 && + "Wrong number of operands for binary operation"); + return new BinOpInit(getOpcode(), Operands[0], Operands[1], getType()); + } + + int getNumOperands(void) const { return 2; } + Init *getOperand(int i) { + assert((i == 0 || i == 1) && "Invalid operand id for binary operator"); + if (i == 0) { + return getLHS(); + } + else { + return getRHS(); + } + } + + BinaryOp getOpcode() const { return Opc; } + Init *getLHS() const { return LHS; } + Init *getRHS() const { return RHS; } + + // Fold - If possible, fold this to a simpler init. Return this if not + // possible to fold. + Init *Fold(Record *CurRec, MultiClass *CurMultiClass); + + virtual Init *resolveReferences(Record &R, const RecordVal *RV); + + virtual std::string getAsString() const; +}; + +/// TernOpInit - !op (X, Y, Z) - Combine two inits. +/// +class TernOpInit : public OpInit { +public: + enum TernaryOp { SUBST, FOREACH, IF }; +private: + TernaryOp Opc; + Init *LHS, *MHS, *RHS; +public: + TernOpInit(TernaryOp opc, Init *lhs, Init *mhs, Init *rhs, RecTy *Type) : + OpInit(Type), Opc(opc), LHS(lhs), MHS(mhs), RHS(rhs) { + } + + // Clone - Clone this operator, replacing arguments with the new list + virtual OpInit *clone(std::vector<Init *> &Operands) { + assert(Operands.size() == 3 && + "Wrong number of operands for ternary operation"); + return new TernOpInit(getOpcode(), Operands[0], Operands[1], Operands[2], + getType()); + } + + int getNumOperands(void) const { return 3; } + Init *getOperand(int i) { + assert((i == 0 || i == 1 || i == 2) && + "Invalid operand id for ternary operator"); + if (i == 0) { + return getLHS(); + } + else if (i == 1) { + return getMHS(); + } + else { + return getRHS(); + } + } + + TernaryOp getOpcode() const { return Opc; } + Init *getLHS() const { return LHS; } + Init *getMHS() const { return MHS; } + Init *getRHS() const { return RHS; } + + // Fold - If possible, fold this to a simpler init. Return this if not + // possible to fold. + Init *Fold(Record *CurRec, MultiClass *CurMultiClass); + + virtual Init *resolveReferences(Record &R, const RecordVal *RV); + + virtual std::string getAsString() const; +}; + + +/// VarInit - 'Opcode' - Represent a reference to an entire variable object. +/// +class VarInit : public TypedInit { + std::string VarName; +public: + explicit VarInit(const std::string &VN, RecTy *T) + : TypedInit(T), VarName(VN) {} + + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + + const std::string &getName() const { return VarName; } + + virtual Init *resolveBitReference(Record &R, const RecordVal *RV, + unsigned Bit); + virtual Init *resolveListElementReference(Record &R, const RecordVal *RV, + unsigned Elt); + + virtual RecTy *getFieldType(const std::string &FieldName) const; + virtual Init *getFieldInit(Record &R, const std::string &FieldName) const; + + /// resolveReferences - This method is used by classes that refer to other + /// variables which may not be defined at the time they expression is formed. + /// If a value is set for the variable later, this method will be called on + /// users of the value to allow the value to propagate out. + /// + virtual Init *resolveReferences(Record &R, const RecordVal *RV); + + virtual std::string getAsString() const { return VarName; } +}; + + +/// VarBitInit - Opcode{0} - Represent access to one bit of a variable or field. +/// +class VarBitInit : public Init { + TypedInit *TI; + unsigned Bit; +public: + VarBitInit(TypedInit *T, unsigned B) : TI(T), Bit(B) { + assert(T->getType() && dynamic_cast<BitsRecTy*>(T->getType()) && + ((BitsRecTy*)T->getType())->getNumBits() > B && + "Illegal VarBitInit expression!"); + } + + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + + TypedInit *getVariable() const { return TI; } + unsigned getBitNum() const { return Bit; } + + virtual std::string getAsString() const; + virtual Init *resolveReferences(Record &R, const RecordVal *RV); +}; + +/// VarListElementInit - List[4] - Represent access to one element of a var or +/// field. +class VarListElementInit : public TypedInit { + TypedInit *TI; + unsigned Element; +public: + VarListElementInit(TypedInit *T, unsigned E) + : TypedInit(dynamic_cast<ListRecTy*>(T->getType())->getElementType()), + TI(T), Element(E) { + assert(T->getType() && dynamic_cast<ListRecTy*>(T->getType()) && + "Illegal VarBitInit expression!"); + } + + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + + TypedInit *getVariable() const { return TI; } + unsigned getElementNum() const { return Element; } + + virtual Init *resolveBitReference(Record &R, const RecordVal *RV, + unsigned Bit); + + /// resolveListElementReference - This method is used to implement + /// VarListElementInit::resolveReferences. If the list element is resolvable + /// now, we return the resolved value, otherwise we return null. + virtual Init *resolveListElementReference(Record &R, const RecordVal *RV, + unsigned Elt); + + virtual std::string getAsString() const; + virtual Init *resolveReferences(Record &R, const RecordVal *RV); +}; + +/// DefInit - AL - Represent a reference to a 'def' in the description +/// +class DefInit : public TypedInit { + Record *Def; +public: + explicit DefInit(Record *D) : TypedInit(new RecordRecTy(D)), Def(D) {} + + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + + Record *getDef() const { return Def; } + + //virtual Init *convertInitializerBitRange(const std::vector<unsigned> &Bits); + + virtual RecTy *getFieldType(const std::string &FieldName) const; + virtual Init *getFieldInit(Record &R, const std::string &FieldName) const; + + virtual std::string getAsString() const; + + /// resolveBitReference - This method is used to implement + /// VarBitInit::resolveReferences. If the bit is able to be resolved, we + /// simply return the resolved value, otherwise we return null. + /// + virtual Init *resolveBitReference(Record &R, const RecordVal *RV, + unsigned Bit) { + assert(0 && "Illegal bit reference off def"); + return 0; + } + + /// resolveListElementReference - This method is used to implement + /// VarListElementInit::resolveReferences. If the list element is resolvable + /// now, we return the resolved value, otherwise we return null. + virtual Init *resolveListElementReference(Record &R, const RecordVal *RV, + unsigned Elt) { + assert(0 && "Illegal element reference off def"); + return 0; + } +}; + + +/// FieldInit - X.Y - Represent a reference to a subfield of a variable +/// +class FieldInit : public TypedInit { + Init *Rec; // Record we are referring to + std::string FieldName; // Field we are accessing +public: + FieldInit(Init *R, const std::string &FN) + : TypedInit(R->getFieldType(FN)), Rec(R), FieldName(FN) { + assert(getType() && "FieldInit with non-record type!"); + } + + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + + virtual Init *resolveBitReference(Record &R, const RecordVal *RV, + unsigned Bit); + virtual Init *resolveListElementReference(Record &R, const RecordVal *RV, + unsigned Elt); + + virtual Init *resolveReferences(Record &R, const RecordVal *RV); + + virtual std::string getAsString() const { + return Rec->getAsString() + "." + FieldName; + } +}; + +/// DagInit - (v a, b) - Represent a DAG tree value. DAG inits are required +/// to have at least one value then a (possibly empty) list of arguments. Each +/// argument can have a name associated with it. +/// +class DagInit : public TypedInit { + Init *Val; + std::string ValName; + std::vector<Init*> Args; + std::vector<std::string> ArgNames; +public: + DagInit(Init *V, std::string VN, + const std::vector<std::pair<Init*, std::string> > &args) + : TypedInit(new DagRecTy), Val(V), ValName(VN) { + Args.reserve(args.size()); + ArgNames.reserve(args.size()); + for (unsigned i = 0, e = args.size(); i != e; ++i) { + Args.push_back(args[i].first); + ArgNames.push_back(args[i].second); + } + } + DagInit(Init *V, std::string VN, const std::vector<Init*> &args, + const std::vector<std::string> &argNames) + : TypedInit(new DagRecTy), Val(V), ValName(VN), Args(args), ArgNames(argNames) { + } + + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + + Init *getOperator() const { return Val; } + + const std::string &getName() const { return ValName; } + + unsigned getNumArgs() const { return Args.size(); } + Init *getArg(unsigned Num) const { + assert(Num < Args.size() && "Arg number out of range!"); + return Args[Num]; + } + const std::string &getArgName(unsigned Num) const { + assert(Num < ArgNames.size() && "Arg number out of range!"); + return ArgNames[Num]; + } + + void setArg(unsigned Num, Init *I) { + assert(Num < Args.size() && "Arg number out of range!"); + Args[Num] = I; + } + + virtual Init *resolveReferences(Record &R, const RecordVal *RV); + + virtual std::string getAsString() const; + + typedef std::vector<Init*>::iterator arg_iterator; + typedef std::vector<Init*>::const_iterator const_arg_iterator; + typedef std::vector<std::string>::iterator name_iterator; + typedef std::vector<std::string>::const_iterator const_name_iterator; + + inline arg_iterator arg_begin() { return Args.begin(); } + inline const_arg_iterator arg_begin() const { return Args.begin(); } + inline arg_iterator arg_end () { return Args.end(); } + inline const_arg_iterator arg_end () const { return Args.end(); } + + inline size_t arg_size () const { return Args.size(); } + inline bool arg_empty() const { return Args.empty(); } + + inline name_iterator name_begin() { return ArgNames.begin(); } + inline const_name_iterator name_begin() const { return ArgNames.begin(); } + inline name_iterator name_end () { return ArgNames.end(); } + inline const_name_iterator name_end () const { return ArgNames.end(); } + + inline size_t name_size () const { return ArgNames.size(); } + inline bool name_empty() const { return ArgNames.empty(); } + + virtual Init *resolveBitReference(Record &R, const RecordVal *RV, + unsigned Bit) { + assert(0 && "Illegal bit reference off dag"); + return 0; + } + + virtual Init *resolveListElementReference(Record &R, const RecordVal *RV, + unsigned Elt) { + assert(0 && "Illegal element reference off dag"); + return 0; + } + +}; + +//===----------------------------------------------------------------------===// +// High-Level Classes +//===----------------------------------------------------------------------===// + +class RecordVal { + std::string Name; + RecTy *Ty; + unsigned Prefix; + Init *Value; +public: + RecordVal(const std::string &N, RecTy *T, unsigned P); + + const std::string &getName() const { return Name; } + + unsigned getPrefix() const { return Prefix; } + RecTy *getType() const { return Ty; } + Init *getValue() const { return Value; } + + bool setValue(Init *V) { + if (V) { + Value = V->convertInitializerTo(Ty); + return Value == 0; + } + Value = 0; + return false; + } + + void dump() const; + void print(std::ostream &OS, bool PrintSem = true) const; +}; + +inline std::ostream &operator<<(std::ostream &OS, const RecordVal &RV) { + RV.print(OS << " "); + return OS; +} + +class Record { + std::string Name; + TGLoc Loc; + std::vector<std::string> TemplateArgs; + std::vector<RecordVal> Values; + std::vector<Record*> SuperClasses; +public: + + explicit Record(const std::string &N, TGLoc loc) : Name(N), Loc(loc) {} + ~Record() {} + + const std::string &getName() const { return Name; } + void setName(const std::string &Name); // Also updates RecordKeeper. + + TGLoc getLoc() const { return Loc; } + + const std::vector<std::string> &getTemplateArgs() const { + return TemplateArgs; + } + const std::vector<RecordVal> &getValues() const { return Values; } + const std::vector<Record*> &getSuperClasses() const { return SuperClasses; } + + bool isTemplateArg(const std::string &Name) const { + for (unsigned i = 0, e = TemplateArgs.size(); i != e; ++i) + if (TemplateArgs[i] == Name) return true; + return false; + } + + const RecordVal *getValue(const std::string &Name) const { + for (unsigned i = 0, e = Values.size(); i != e; ++i) + if (Values[i].getName() == Name) return &Values[i]; + return 0; + } + RecordVal *getValue(const std::string &Name) { + for (unsigned i = 0, e = Values.size(); i != e; ++i) + if (Values[i].getName() == Name) return &Values[i]; + return 0; + } + + void addTemplateArg(const std::string &Name) { + assert(!isTemplateArg(Name) && "Template arg already defined!"); + TemplateArgs.push_back(Name); + } + + void addValue(const RecordVal &RV) { + assert(getValue(RV.getName()) == 0 && "Value already added!"); + Values.push_back(RV); + } + + void removeValue(const std::string &Name) { + assert(getValue(Name) && "Cannot remove an entry that does not exist!"); + for (unsigned i = 0, e = Values.size(); i != e; ++i) + if (Values[i].getName() == Name) { + Values.erase(Values.begin()+i); + return; + } + assert(0 && "Name does not exist in record!"); + } + + bool isSubClassOf(const Record *R) const { + for (unsigned i = 0, e = SuperClasses.size(); i != e; ++i) + if (SuperClasses[i] == R) + return true; + return false; + } + + bool isSubClassOf(const std::string &Name) const { + for (unsigned i = 0, e = SuperClasses.size(); i != e; ++i) + if (SuperClasses[i]->getName() == Name) + return true; + return false; + } + + void addSuperClass(Record *R) { + assert(!isSubClassOf(R) && "Already subclassing record!"); + SuperClasses.push_back(R); + } + + /// resolveReferences - If there are any field references that refer to fields + /// that have been filled in, we can propagate the values now. + /// + void resolveReferences() { resolveReferencesTo(0); } + + /// resolveReferencesTo - If anything in this record refers to RV, replace the + /// reference to RV with the RHS of RV. If RV is null, we resolve all + /// possible references. + void resolveReferencesTo(const RecordVal *RV); + + void dump() const; + + //===--------------------------------------------------------------------===// + // High-level methods useful to tablegen back-ends + // + + /// getValueInit - Return the initializer for a value with the specified name, + /// or throw an exception if the field does not exist. + /// + Init *getValueInit(const std::string &FieldName) const; + + /// getValueAsString - This method looks up the specified field and returns + /// its value as a string, throwing an exception if the field does not exist + /// or if the value is not a string. + /// + std::string getValueAsString(const std::string &FieldName) const; + + /// getValueAsBitsInit - This method looks up the specified field and returns + /// its value as a BitsInit, throwing an exception if the field does not exist + /// or if the value is not the right type. + /// + BitsInit *getValueAsBitsInit(const std::string &FieldName) const; + + /// getValueAsListInit - This method looks up the specified field and returns + /// its value as a ListInit, throwing an exception if the field does not exist + /// or if the value is not the right type. + /// + ListInit *getValueAsListInit(const std::string &FieldName) const; + + /// getValueAsListOfDefs - This method looks up the specified field and + /// returns its value as a vector of records, throwing an exception if the + /// field does not exist or if the value is not the right type. + /// + std::vector<Record*> getValueAsListOfDefs(const std::string &FieldName) const; + + /// getValueAsListOfInts - This method looks up the specified field and returns + /// its value as a vector of integers, throwing an exception if the field does + /// not exist or if the value is not the right type. + /// + std::vector<int64_t> getValueAsListOfInts(const std::string &FieldName) const; + + /// getValueAsDef - This method looks up the specified field and returns its + /// value as a Record, throwing an exception if the field does not exist or if + /// the value is not the right type. + /// + Record *getValueAsDef(const std::string &FieldName) const; + + /// getValueAsBit - This method looks up the specified field and returns its + /// value as a bit, throwing an exception if the field does not exist or if + /// the value is not the right type. + /// + bool getValueAsBit(const std::string &FieldName) const; + + /// getValueAsInt - This method looks up the specified field and returns its + /// value as an int64_t, throwing an exception if the field does not exist or + /// if the value is not the right type. + /// + int64_t getValueAsInt(const std::string &FieldName) const; + + /// getValueAsDag - This method looks up the specified field and returns its + /// value as an Dag, throwing an exception if the field does not exist or if + /// the value is not the right type. + /// + DagInit *getValueAsDag(const std::string &FieldName) const; + + /// getValueAsCode - This method looks up the specified field and returns + /// its value as the string data in a CodeInit, throwing an exception if the + /// field does not exist or if the value is not a code object. + /// + std::string getValueAsCode(const std::string &FieldName) const; +}; + +std::ostream &operator<<(std::ostream &OS, const Record &R); + +struct MultiClass { + Record Rec; // Placeholder for template args and Name. + typedef std::vector<Record*> RecordVector; + RecordVector DefPrototypes; + + void dump() const; + + MultiClass(const std::string &Name, TGLoc Loc) : Rec(Name, Loc) {} +}; + +class RecordKeeper { + std::map<std::string, Record*> Classes, Defs; +public: + ~RecordKeeper() { + for (std::map<std::string, Record*>::iterator I = Classes.begin(), + E = Classes.end(); I != E; ++I) + delete I->second; + for (std::map<std::string, Record*>::iterator I = Defs.begin(), + E = Defs.end(); I != E; ++I) + delete I->second; + } + + const std::map<std::string, Record*> &getClasses() const { return Classes; } + const std::map<std::string, Record*> &getDefs() const { return Defs; } + + Record *getClass(const std::string &Name) const { + std::map<std::string, Record*>::const_iterator I = Classes.find(Name); + return I == Classes.end() ? 0 : I->second; + } + Record *getDef(const std::string &Name) const { + std::map<std::string, Record*>::const_iterator I = Defs.find(Name); + return I == Defs.end() ? 0 : I->second; + } + void addClass(Record *R) { + assert(getClass(R->getName()) == 0 && "Class already exists!"); + Classes.insert(std::make_pair(R->getName(), R)); + } + void addDef(Record *R) { + assert(getDef(R->getName()) == 0 && "Def already exists!"); + Defs.insert(std::make_pair(R->getName(), R)); + } + + /// removeClass - Remove, but do not delete, the specified record. + /// + void removeClass(const std::string &Name) { + assert(Classes.count(Name) && "Class does not exist!"); + Classes.erase(Name); + } + /// removeDef - Remove, but do not delete, the specified record. + /// + void removeDef(const std::string &Name) { + assert(Defs.count(Name) && "Def does not exist!"); + Defs.erase(Name); + } + + //===--------------------------------------------------------------------===// + // High-level helper methods, useful for tablegen backends... + + /// getAllDerivedDefinitions - This method returns all concrete definitions + /// that derive from the specified class name. If a class with the specified + /// name does not exist, an exception is thrown. + std::vector<Record*> + getAllDerivedDefinitions(const std::string &ClassName) const; + + + void dump() const; +}; + +/// LessRecord - Sorting predicate to sort record pointers by name. +/// +struct LessRecord { + bool operator()(const Record *Rec1, const Record *Rec2) const { + return Rec1->getName() < Rec2->getName(); + } +}; + +/// LessRecordFieldName - Sorting predicate to sort record pointers by their +/// name field. +/// +struct LessRecordFieldName { + bool operator()(const Record *Rec1, const Record *Rec2) const { + return Rec1->getValueAsString("Name") < Rec2->getValueAsString("Name"); + } +}; + + +class TGError { + TGLoc Loc; + std::string Message; +public: + TGError(TGLoc loc, const std::string &message) : Loc(loc), Message(message) {} + + TGLoc getLoc() const { return Loc; } + const std::string &getMessage() const { return Message; } +}; + + +std::ostream &operator<<(std::ostream &OS, const RecordKeeper &RK); + +extern RecordKeeper Records; + +void PrintError(TGLoc ErrorLoc, const std::string &Msg); + + +} // End llvm namespace + +#endif diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp new file mode 100644 index 0000000000000..dcf965cc1d790 --- /dev/null +++ b/utils/TableGen/RegisterInfoEmitter.cpp @@ -0,0 +1,907 @@ +//===- RegisterInfoEmitter.cpp - Generate a Register File Desc. -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend is responsible for emitting a description of a target +// register file for a code generator. It uses instances of the Register, +// RegisterAliases, and RegisterClass classes to gather this information. +// +//===----------------------------------------------------------------------===// + +#include "RegisterInfoEmitter.h" +#include "CodeGenTarget.h" +#include "CodeGenRegisters.h" +#include "Record.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Streams.h" +#include <set> +#include <algorithm> +using namespace llvm; + +// runEnums - Print out enum values for all of the registers. +void RegisterInfoEmitter::runEnums(std::ostream &OS) { + CodeGenTarget Target; + const std::vector<CodeGenRegister> &Registers = Target.getRegisters(); + + std::string Namespace = Registers[0].TheDef->getValueAsString("Namespace"); + + EmitSourceFileHeader("Target Register Enum Values", OS); + OS << "namespace llvm {\n\n"; + + if (!Namespace.empty()) + OS << "namespace " << Namespace << " {\n"; + OS << " enum {\n NoRegister,\n"; + + for (unsigned i = 0, e = Registers.size(); i != e; ++i) + OS << " " << Registers[i].getName() << ", \t// " << i+1 << "\n"; + OS << " NUM_TARGET_REGS \t// " << Registers.size()+1 << "\n"; + OS << " };\n"; + if (!Namespace.empty()) + OS << "}\n"; + OS << "} // End llvm namespace \n"; +} + +void RegisterInfoEmitter::runHeader(std::ostream &OS) { + EmitSourceFileHeader("Register Information Header Fragment", OS); + CodeGenTarget Target; + const std::string &TargetName = Target.getName(); + std::string ClassName = TargetName + "GenRegisterInfo"; + + OS << "#include \"llvm/Target/TargetRegisterInfo.h\"\n"; + OS << "#include <string>\n\n"; + + OS << "namespace llvm {\n\n"; + + OS << "struct " << ClassName << " : public TargetRegisterInfo {\n" + << " explicit " << ClassName + << "(int CallFrameSetupOpcode = -1, int CallFrameDestroyOpcode = -1);\n" + << " virtual int getDwarfRegNumFull(unsigned RegNum, " + << "unsigned Flavour) const;\n" + << " virtual int getDwarfRegNum(unsigned RegNum, bool isEH) const = 0;\n" + << " virtual bool needsStackRealignment(const MachineFunction &) const\n" + << " { return false; }\n" + << " unsigned getSubReg(unsigned RegNo, unsigned Index) const;\n" + << "};\n\n"; + + const std::vector<CodeGenRegisterClass> &RegisterClasses = + Target.getRegisterClasses(); + + if (!RegisterClasses.empty()) { + OS << "namespace " << RegisterClasses[0].Namespace + << " { // Register classes\n"; + + OS << " enum {\n"; + for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) { + if (i) OS << ",\n"; + OS << " " << RegisterClasses[i].getName() << "RegClassID"; + OS << " = " << (i+1); + } + OS << "\n };\n\n"; + + for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) { + const std::string &Name = RegisterClasses[i].getName(); + + // Output the register class definition. + OS << " struct " << Name << "Class : public TargetRegisterClass {\n" + << " " << Name << "Class();\n" + << RegisterClasses[i].MethodProtos << " };\n"; + + // Output the extern for the instance. + OS << " extern " << Name << "Class\t" << Name << "RegClass;\n"; + // Output the extern for the pointer to the instance (should remove). + OS << " static TargetRegisterClass * const "<< Name <<"RegisterClass = &" + << Name << "RegClass;\n"; + } + OS << "} // end of namespace " << TargetName << "\n\n"; + } + OS << "} // End llvm namespace \n"; +} + +bool isSubRegisterClass(const CodeGenRegisterClass &RC, + std::set<Record*> &RegSet) { + for (unsigned i = 0, e = RC.Elements.size(); i != e; ++i) { + Record *Reg = RC.Elements[i]; + if (!RegSet.count(Reg)) + return false; + } + return true; +} + +static void addSuperReg(Record *R, Record *S, + std::map<Record*, std::set<Record*>, LessRecord> &SubRegs, + std::map<Record*, std::set<Record*>, LessRecord> &SuperRegs, + std::map<Record*, std::set<Record*>, LessRecord> &Aliases) { + if (R == S) { + cerr << "Error: recursive sub-register relationship between" + << " register " << getQualifiedName(R) + << " and its sub-registers?\n"; + abort(); + } + if (!SuperRegs[R].insert(S).second) + return; + SubRegs[S].insert(R); + Aliases[R].insert(S); + Aliases[S].insert(R); + if (SuperRegs.count(S)) + for (std::set<Record*>::iterator I = SuperRegs[S].begin(), + E = SuperRegs[S].end(); I != E; ++I) + addSuperReg(R, *I, SubRegs, SuperRegs, Aliases); +} + +static void addSubSuperReg(Record *R, Record *S, + std::map<Record*, std::set<Record*>, LessRecord> &SubRegs, + std::map<Record*, std::set<Record*>, LessRecord> &SuperRegs, + std::map<Record*, std::set<Record*>, LessRecord> &Aliases) { + if (R == S) { + cerr << "Error: recursive sub-register relationship between" + << " register " << getQualifiedName(R) + << " and its sub-registers?\n"; + abort(); + } + + if (!SubRegs[R].insert(S).second) + return; + addSuperReg(S, R, SubRegs, SuperRegs, Aliases); + Aliases[R].insert(S); + Aliases[S].insert(R); + if (SubRegs.count(S)) + for (std::set<Record*>::iterator I = SubRegs[S].begin(), + E = SubRegs[S].end(); I != E; ++I) + addSubSuperReg(R, *I, SubRegs, SuperRegs, Aliases); +} + +class RegisterSorter { +private: + std::map<Record*, std::set<Record*>, LessRecord> &RegisterSubRegs; + +public: + RegisterSorter(std::map<Record*, std::set<Record*>, LessRecord> &RS) + : RegisterSubRegs(RS) {}; + + bool operator()(Record *RegA, Record *RegB) { + // B is sub-register of A. + return RegisterSubRegs.count(RegA) && RegisterSubRegs[RegA].count(RegB); + } +}; + +// RegisterInfoEmitter::run - Main register file description emitter. +// +void RegisterInfoEmitter::run(std::ostream &OS) { + CodeGenTarget Target; + EmitSourceFileHeader("Register Information Source Fragment", OS); + + OS << "namespace llvm {\n\n"; + + // Start out by emitting each of the register classes... to do this, we build + // a set of registers which belong to a register class, this is to ensure that + // each register is only in a single register class. + // + const std::vector<CodeGenRegisterClass> &RegisterClasses = + Target.getRegisterClasses(); + + // Loop over all of the register classes... emitting each one. + OS << "namespace { // Register classes...\n"; + + // RegClassesBelongedTo - Keep track of which register classes each reg + // belongs to. + std::multimap<Record*, const CodeGenRegisterClass*> RegClassesBelongedTo; + + // Emit the register enum value arrays for each RegisterClass + for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) { + const CodeGenRegisterClass &RC = RegisterClasses[rc]; + + // Give the register class a legal C name if it's anonymous. + std::string Name = RC.TheDef->getName(); + + // Emit the register list now. + OS << " // " << Name << " Register Class...\n" + << " static const unsigned " << Name + << "[] = {\n "; + for (unsigned i = 0, e = RC.Elements.size(); i != e; ++i) { + Record *Reg = RC.Elements[i]; + OS << getQualifiedName(Reg) << ", "; + + // Keep track of which regclasses this register is in. + RegClassesBelongedTo.insert(std::make_pair(Reg, &RC)); + } + OS << "\n };\n\n"; + } + + // Emit the ValueType arrays for each RegisterClass + for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) { + const CodeGenRegisterClass &RC = RegisterClasses[rc]; + + // Give the register class a legal C name if it's anonymous. + std::string Name = RC.TheDef->getName() + "VTs"; + + // Emit the register list now. + OS << " // " << Name + << " Register Class Value Types...\n" + << " static const MVT " << Name + << "[] = {\n "; + for (unsigned i = 0, e = RC.VTs.size(); i != e; ++i) + OS << getEnumName(RC.VTs[i]) << ", "; + OS << "MVT::Other\n };\n\n"; + } + OS << "} // end anonymous namespace\n\n"; + + // Now that all of the structs have been emitted, emit the instances. + if (!RegisterClasses.empty()) { + OS << "namespace " << RegisterClasses[0].Namespace + << " { // Register class instances\n"; + for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) + OS << " " << RegisterClasses[i].getName() << "Class\t" + << RegisterClasses[i].getName() << "RegClass;\n"; + + std::map<unsigned, std::set<unsigned> > SuperClassMap; + std::map<unsigned, std::set<unsigned> > SuperRegClassMap; + OS << "\n"; + + // Emit the sub-register classes for each RegisterClass + for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) { + const CodeGenRegisterClass &RC = RegisterClasses[rc]; + + // Give the register class a legal C name if it's anonymous. + std::string Name = RC.TheDef->getName(); + + OS << " // " << Name + << " Sub-register Classes...\n" + << " static const TargetRegisterClass* const " + << Name << "SubRegClasses [] = {\n "; + + bool Empty = true; + + for (unsigned subrc = 0, subrcMax = RC.SubRegClasses.size(); + subrc != subrcMax; ++subrc) { + unsigned rc2 = 0, e2 = RegisterClasses.size(); + for (; rc2 != e2; ++rc2) { + const CodeGenRegisterClass &RC2 = RegisterClasses[rc2]; + if (RC.SubRegClasses[subrc]->getName() == RC2.getName()) { + if (!Empty) + OS << ", "; + OS << "&" << getQualifiedName(RC2.TheDef) << "RegClass"; + Empty = false; + + std::map<unsigned, std::set<unsigned> >::iterator SCMI = + SuperRegClassMap.find(rc2); + if (SCMI == SuperRegClassMap.end()) { + SuperRegClassMap.insert(std::make_pair(rc2, + std::set<unsigned>())); + SCMI = SuperRegClassMap.find(rc2); + } + SCMI->second.insert(rc); + break; + } + } + if (rc2 == e2) + throw "Register Class member '" + + RC.SubRegClasses[subrc]->getName() + + "' is not a valid RegisterClass!"; + } + + OS << (!Empty ? ", " : "") << "NULL"; + OS << "\n };\n\n"; + } + + // Emit the super-register classes for each RegisterClass + for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) { + const CodeGenRegisterClass &RC = RegisterClasses[rc]; + + // Give the register class a legal C name if it's anonymous. + std::string Name = RC.TheDef->getName(); + + OS << " // " << Name + << " Super-register Classes...\n" + << " static const TargetRegisterClass* const " + << Name << "SuperRegClasses [] = {\n "; + + bool Empty = true; + std::map<unsigned, std::set<unsigned> >::iterator I = + SuperRegClassMap.find(rc); + if (I != SuperRegClassMap.end()) { + for (std::set<unsigned>::iterator II = I->second.begin(), + EE = I->second.end(); II != EE; ++II) { + const CodeGenRegisterClass &RC2 = RegisterClasses[*II]; + if (!Empty) + OS << ", "; + OS << "&" << getQualifiedName(RC2.TheDef) << "RegClass"; + Empty = false; + } + } + + OS << (!Empty ? ", " : "") << "NULL"; + OS << "\n };\n\n"; + } + + // Emit the sub-classes array for each RegisterClass + for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) { + const CodeGenRegisterClass &RC = RegisterClasses[rc]; + + // Give the register class a legal C name if it's anonymous. + std::string Name = RC.TheDef->getName(); + + std::set<Record*> RegSet; + for (unsigned i = 0, e = RC.Elements.size(); i != e; ++i) { + Record *Reg = RC.Elements[i]; + RegSet.insert(Reg); + } + + OS << " // " << Name + << " Register Class sub-classes...\n" + << " static const TargetRegisterClass* const " + << Name << "Subclasses [] = {\n "; + + bool Empty = true; + for (unsigned rc2 = 0, e2 = RegisterClasses.size(); rc2 != e2; ++rc2) { + const CodeGenRegisterClass &RC2 = RegisterClasses[rc2]; + + // RC2 is a sub-class of RC if it is a valid replacement for any + // instruction operand where an RC register is required. It must satisfy + // these conditions: + // + // 1. All RC2 registers are also in RC. + // 2. The RC2 spill size must not be smaller that the RC spill size. + // 3. RC2 spill alignment must be compatible with RC. + // + // Sub-classes are used to determine if a virtual register can be used + // as an instruction operand, or if it must be copied first. + + if (rc == rc2 || RC2.Elements.size() > RC.Elements.size() || + (RC.SpillAlignment && RC2.SpillAlignment % RC.SpillAlignment) || + RC.SpillSize > RC2.SpillSize || !isSubRegisterClass(RC2, RegSet)) + continue; + + if (!Empty) OS << ", "; + OS << "&" << getQualifiedName(RC2.TheDef) << "RegClass"; + Empty = false; + + std::map<unsigned, std::set<unsigned> >::iterator SCMI = + SuperClassMap.find(rc2); + if (SCMI == SuperClassMap.end()) { + SuperClassMap.insert(std::make_pair(rc2, std::set<unsigned>())); + SCMI = SuperClassMap.find(rc2); + } + SCMI->second.insert(rc); + } + + OS << (!Empty ? ", " : "") << "NULL"; + OS << "\n };\n\n"; + } + + for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) { + const CodeGenRegisterClass &RC = RegisterClasses[rc]; + + // Give the register class a legal C name if it's anonymous. + std::string Name = RC.TheDef->getName(); + + OS << " // " << Name + << " Register Class super-classes...\n" + << " static const TargetRegisterClass* const " + << Name << "Superclasses [] = {\n "; + + bool Empty = true; + std::map<unsigned, std::set<unsigned> >::iterator I = + SuperClassMap.find(rc); + if (I != SuperClassMap.end()) { + for (std::set<unsigned>::iterator II = I->second.begin(), + EE = I->second.end(); II != EE; ++II) { + const CodeGenRegisterClass &RC2 = RegisterClasses[*II]; + if (!Empty) OS << ", "; + OS << "&" << getQualifiedName(RC2.TheDef) << "RegClass"; + Empty = false; + } + } + + OS << (!Empty ? ", " : "") << "NULL"; + OS << "\n };\n\n"; + } + + + for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) { + const CodeGenRegisterClass &RC = RegisterClasses[i]; + OS << RC.MethodBodies << "\n"; + OS << RC.getName() << "Class::" << RC.getName() + << "Class() : TargetRegisterClass(" + << RC.getName() + "RegClassID" << ", " + << '\"' << RC.getName() << "\", " + << RC.getName() + "VTs" << ", " + << RC.getName() + "Subclasses" << ", " + << RC.getName() + "Superclasses" << ", " + << RC.getName() + "SubRegClasses" << ", " + << RC.getName() + "SuperRegClasses" << ", " + << RC.SpillSize/8 << ", " + << RC.SpillAlignment/8 << ", " + << RC.CopyCost << ", " + << RC.getName() << ", " << RC.getName() << " + " << RC.Elements.size() + << ") {}\n"; + } + + OS << "}\n"; + } + + OS << "\nnamespace {\n"; + OS << " const TargetRegisterClass* const RegisterClasses[] = {\n"; + for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) + OS << " &" << getQualifiedName(RegisterClasses[i].TheDef) + << "RegClass,\n"; + OS << " };\n"; + + // Emit register sub-registers / super-registers, aliases... + std::map<Record*, std::set<Record*>, LessRecord> RegisterSubRegs; + std::map<Record*, std::set<Record*>, LessRecord> RegisterSuperRegs; + std::map<Record*, std::set<Record*>, LessRecord> RegisterAliases; + std::map<Record*, std::vector<std::pair<int, Record*> > > SubRegVectors; + typedef std::map<Record*, std::vector<int64_t>, LessRecord> DwarfRegNumsMapTy; + DwarfRegNumsMapTy DwarfRegNums; + + const std::vector<CodeGenRegister> &Regs = Target.getRegisters(); + + for (unsigned i = 0, e = Regs.size(); i != e; ++i) { + Record *R = Regs[i].TheDef; + std::vector<Record*> LI = Regs[i].TheDef->getValueAsListOfDefs("Aliases"); + // Add information that R aliases all of the elements in the list... and + // that everything in the list aliases R. + for (unsigned j = 0, e = LI.size(); j != e; ++j) { + Record *Reg = LI[j]; + if (RegisterAliases[R].count(Reg)) + cerr << "Warning: register alias between " << getQualifiedName(R) + << " and " << getQualifiedName(Reg) + << " specified multiple times!\n"; + RegisterAliases[R].insert(Reg); + + if (RegisterAliases[Reg].count(R)) + cerr << "Warning: register alias between " << getQualifiedName(R) + << " and " << getQualifiedName(Reg) + << " specified multiple times!\n"; + RegisterAliases[Reg].insert(R); + } + } + + // Process sub-register sets. + for (unsigned i = 0, e = Regs.size(); i != e; ++i) { + Record *R = Regs[i].TheDef; + std::vector<Record*> LI = Regs[i].TheDef->getValueAsListOfDefs("SubRegs"); + // Process sub-register set and add aliases information. + for (unsigned j = 0, e = LI.size(); j != e; ++j) { + Record *SubReg = LI[j]; + if (RegisterSubRegs[R].count(SubReg)) + cerr << "Warning: register " << getQualifiedName(SubReg) + << " specified as a sub-register of " << getQualifiedName(R) + << " multiple times!\n"; + addSubSuperReg(R, SubReg, RegisterSubRegs, RegisterSuperRegs, + RegisterAliases); + } + } + + // Print the SubregHashTable, a simple quadratically probed + // hash table for determining if a register is a subregister + // of another register. + unsigned NumSubRegs = 0; + std::map<Record*, unsigned> RegNo; + for (unsigned i = 0, e = Regs.size(); i != e; ++i) { + RegNo[Regs[i].TheDef] = i; + NumSubRegs += RegisterSubRegs[Regs[i].TheDef].size(); + } + + unsigned SubregHashTableSize = 2 * NextPowerOf2(2 * NumSubRegs); + unsigned* SubregHashTable = new unsigned[2 * SubregHashTableSize]; + std::fill(SubregHashTable, SubregHashTable + 2 * SubregHashTableSize, ~0U); + + unsigned hashMisses = 0; + + for (unsigned i = 0, e = Regs.size(); i != e; ++i) { + Record* R = Regs[i].TheDef; + for (std::set<Record*>::iterator I = RegisterSubRegs[R].begin(), + E = RegisterSubRegs[R].end(); I != E; ++I) { + Record* RJ = *I; + // We have to increase the indices of both registers by one when + // computing the hash because, in the generated code, there + // will be an extra empty slot at register 0. + size_t index = ((i+1) + (RegNo[RJ]+1) * 37) & (SubregHashTableSize-1); + unsigned ProbeAmt = 2; + while (SubregHashTable[index*2] != ~0U && + SubregHashTable[index*2+1] != ~0U) { + index = (index + ProbeAmt) & (SubregHashTableSize-1); + ProbeAmt += 2; + + hashMisses++; + } + + SubregHashTable[index*2] = i; + SubregHashTable[index*2+1] = RegNo[RJ]; + } + } + + OS << "\n\n // Number of hash collisions: " << hashMisses << "\n"; + + if (SubregHashTableSize) { + std::string Namespace = Regs[0].TheDef->getValueAsString("Namespace"); + + OS << " const unsigned SubregHashTable[] = { "; + for (unsigned i = 0; i < SubregHashTableSize - 1; ++i) { + if (i != 0) + // Insert spaces for nice formatting. + OS << " "; + + if (SubregHashTable[2*i] != ~0U) { + OS << getQualifiedName(Regs[SubregHashTable[2*i]].TheDef) << ", " + << getQualifiedName(Regs[SubregHashTable[2*i+1]].TheDef) << ", \n"; + } else { + OS << Namespace << "::NoRegister, " << Namespace << "::NoRegister, \n"; + } + } + + unsigned Idx = SubregHashTableSize*2-2; + if (SubregHashTable[Idx] != ~0U) { + OS << " " + << getQualifiedName(Regs[SubregHashTable[Idx]].TheDef) << ", " + << getQualifiedName(Regs[SubregHashTable[Idx+1]].TheDef) << " };\n"; + } else { + OS << Namespace << "::NoRegister, " << Namespace << "::NoRegister };\n"; + } + + OS << " const unsigned SubregHashTableSize = " + << SubregHashTableSize << ";\n"; + } else { + OS << " const unsigned SubregHashTable[] = { ~0U, ~0U };\n" + << " const unsigned SubregHashTableSize = 1;\n"; + } + + delete [] SubregHashTable; + + + // Print the SuperregHashTable, a simple quadratically probed + // hash table for determining if a register is a super-register + // of another register. + unsigned NumSupRegs = 0; + RegNo.clear(); + for (unsigned i = 0, e = Regs.size(); i != e; ++i) { + RegNo[Regs[i].TheDef] = i; + NumSupRegs += RegisterSuperRegs[Regs[i].TheDef].size(); + } + + unsigned SuperregHashTableSize = 2 * NextPowerOf2(2 * NumSupRegs); + unsigned* SuperregHashTable = new unsigned[2 * SuperregHashTableSize]; + std::fill(SuperregHashTable, SuperregHashTable + 2 * SuperregHashTableSize, ~0U); + + hashMisses = 0; + + for (unsigned i = 0, e = Regs.size(); i != e; ++i) { + Record* R = Regs[i].TheDef; + for (std::set<Record*>::iterator I = RegisterSuperRegs[R].begin(), + E = RegisterSuperRegs[R].end(); I != E; ++I) { + Record* RJ = *I; + // We have to increase the indices of both registers by one when + // computing the hash because, in the generated code, there + // will be an extra empty slot at register 0. + size_t index = ((i+1) + (RegNo[RJ]+1) * 37) & (SuperregHashTableSize-1); + unsigned ProbeAmt = 2; + while (SuperregHashTable[index*2] != ~0U && + SuperregHashTable[index*2+1] != ~0U) { + index = (index + ProbeAmt) & (SuperregHashTableSize-1); + ProbeAmt += 2; + + hashMisses++; + } + + SuperregHashTable[index*2] = i; + SuperregHashTable[index*2+1] = RegNo[RJ]; + } + } + + OS << "\n\n // Number of hash collisions: " << hashMisses << "\n"; + + if (SuperregHashTableSize) { + std::string Namespace = Regs[0].TheDef->getValueAsString("Namespace"); + + OS << " const unsigned SuperregHashTable[] = { "; + for (unsigned i = 0; i < SuperregHashTableSize - 1; ++i) { + if (i != 0) + // Insert spaces for nice formatting. + OS << " "; + + if (SuperregHashTable[2*i] != ~0U) { + OS << getQualifiedName(Regs[SuperregHashTable[2*i]].TheDef) << ", " + << getQualifiedName(Regs[SuperregHashTable[2*i+1]].TheDef) << ", \n"; + } else { + OS << Namespace << "::NoRegister, " << Namespace << "::NoRegister, \n"; + } + } + + unsigned Idx = SuperregHashTableSize*2-2; + if (SuperregHashTable[Idx] != ~0U) { + OS << " " + << getQualifiedName(Regs[SuperregHashTable[Idx]].TheDef) << ", " + << getQualifiedName(Regs[SuperregHashTable[Idx+1]].TheDef) << " };\n"; + } else { + OS << Namespace << "::NoRegister, " << Namespace << "::NoRegister };\n"; + } + + OS << " const unsigned SuperregHashTableSize = " + << SuperregHashTableSize << ";\n"; + } else { + OS << " const unsigned SuperregHashTable[] = { ~0U, ~0U };\n" + << " const unsigned SuperregHashTableSize = 1;\n"; + } + + delete [] SuperregHashTable; + + + // Print the AliasHashTable, a simple quadratically probed + // hash table for determining if a register aliases another register. + unsigned NumAliases = 0; + RegNo.clear(); + for (unsigned i = 0, e = Regs.size(); i != e; ++i) { + RegNo[Regs[i].TheDef] = i; + NumAliases += RegisterAliases[Regs[i].TheDef].size(); + } + + unsigned AliasesHashTableSize = 2 * NextPowerOf2(2 * NumAliases); + unsigned* AliasesHashTable = new unsigned[2 * AliasesHashTableSize]; + std::fill(AliasesHashTable, AliasesHashTable + 2 * AliasesHashTableSize, ~0U); + + hashMisses = 0; + + for (unsigned i = 0, e = Regs.size(); i != e; ++i) { + Record* R = Regs[i].TheDef; + for (std::set<Record*>::iterator I = RegisterAliases[R].begin(), + E = RegisterAliases[R].end(); I != E; ++I) { + Record* RJ = *I; + // We have to increase the indices of both registers by one when + // computing the hash because, in the generated code, there + // will be an extra empty slot at register 0. + size_t index = ((i+1) + (RegNo[RJ]+1) * 37) & (AliasesHashTableSize-1); + unsigned ProbeAmt = 2; + while (AliasesHashTable[index*2] != ~0U && + AliasesHashTable[index*2+1] != ~0U) { + index = (index + ProbeAmt) & (AliasesHashTableSize-1); + ProbeAmt += 2; + + hashMisses++; + } + + AliasesHashTable[index*2] = i; + AliasesHashTable[index*2+1] = RegNo[RJ]; + } + } + + OS << "\n\n // Number of hash collisions: " << hashMisses << "\n"; + + if (AliasesHashTableSize) { + std::string Namespace = Regs[0].TheDef->getValueAsString("Namespace"); + + OS << " const unsigned AliasesHashTable[] = { "; + for (unsigned i = 0; i < AliasesHashTableSize - 1; ++i) { + if (i != 0) + // Insert spaces for nice formatting. + OS << " "; + + if (AliasesHashTable[2*i] != ~0U) { + OS << getQualifiedName(Regs[AliasesHashTable[2*i]].TheDef) << ", " + << getQualifiedName(Regs[AliasesHashTable[2*i+1]].TheDef) << ", \n"; + } else { + OS << Namespace << "::NoRegister, " << Namespace << "::NoRegister, \n"; + } + } + + unsigned Idx = AliasesHashTableSize*2-2; + if (AliasesHashTable[Idx] != ~0U) { + OS << " " + << getQualifiedName(Regs[AliasesHashTable[Idx]].TheDef) << ", " + << getQualifiedName(Regs[AliasesHashTable[Idx+1]].TheDef) << " };\n"; + } else { + OS << Namespace << "::NoRegister, " << Namespace << "::NoRegister };\n"; + } + + OS << " const unsigned AliasesHashTableSize = " + << AliasesHashTableSize << ";\n"; + } else { + OS << " const unsigned AliasesHashTable[] = { ~0U, ~0U };\n" + << " const unsigned AliasesHashTableSize = 1;\n"; + } + + delete [] AliasesHashTable; + + if (!RegisterAliases.empty()) + OS << "\n\n // Register Alias Sets...\n"; + + // Emit the empty alias list + OS << " const unsigned Empty_AliasSet[] = { 0 };\n"; + // Loop over all of the registers which have aliases, emitting the alias list + // to memory. + for (std::map<Record*, std::set<Record*>, LessRecord >::iterator + I = RegisterAliases.begin(), E = RegisterAliases.end(); I != E; ++I) { + OS << " const unsigned " << I->first->getName() << "_AliasSet[] = { "; + for (std::set<Record*>::iterator ASI = I->second.begin(), + E = I->second.end(); ASI != E; ++ASI) + OS << getQualifiedName(*ASI) << ", "; + OS << "0 };\n"; + } + + if (!RegisterSubRegs.empty()) + OS << "\n\n // Register Sub-registers Sets...\n"; + + // Emit the empty sub-registers list + OS << " const unsigned Empty_SubRegsSet[] = { 0 };\n"; + // Loop over all of the registers which have sub-registers, emitting the + // sub-registers list to memory. + for (std::map<Record*, std::set<Record*>, LessRecord>::iterator + I = RegisterSubRegs.begin(), E = RegisterSubRegs.end(); I != E; ++I) { + OS << " const unsigned " << I->first->getName() << "_SubRegsSet[] = { "; + std::vector<Record*> SubRegsVector; + for (std::set<Record*>::iterator ASI = I->second.begin(), + E = I->second.end(); ASI != E; ++ASI) + SubRegsVector.push_back(*ASI); + RegisterSorter RS(RegisterSubRegs); + std::stable_sort(SubRegsVector.begin(), SubRegsVector.end(), RS); + for (unsigned i = 0, e = SubRegsVector.size(); i != e; ++i) + OS << getQualifiedName(SubRegsVector[i]) << ", "; + OS << "0 };\n"; + } + + if (!RegisterSuperRegs.empty()) + OS << "\n\n // Register Super-registers Sets...\n"; + + // Emit the empty super-registers list + OS << " const unsigned Empty_SuperRegsSet[] = { 0 };\n"; + // Loop over all of the registers which have super-registers, emitting the + // super-registers list to memory. + for (std::map<Record*, std::set<Record*>, LessRecord >::iterator + I = RegisterSuperRegs.begin(), E = RegisterSuperRegs.end(); I != E; ++I) { + OS << " const unsigned " << I->first->getName() << "_SuperRegsSet[] = { "; + + std::vector<Record*> SuperRegsVector; + for (std::set<Record*>::iterator ASI = I->second.begin(), + E = I->second.end(); ASI != E; ++ASI) + SuperRegsVector.push_back(*ASI); + RegisterSorter RS(RegisterSubRegs); + std::stable_sort(SuperRegsVector.begin(), SuperRegsVector.end(), RS); + for (unsigned i = 0, e = SuperRegsVector.size(); i != e; ++i) + OS << getQualifiedName(SuperRegsVector[i]) << ", "; + OS << "0 };\n"; + } + + OS<<"\n const TargetRegisterDesc RegisterDescriptors[] = { // Descriptors\n"; + OS << " { \"NOREG\",\t\"NOREG\",\t0,\t0,\t0 },\n"; + + // Now that register alias and sub-registers sets have been emitted, emit the + // register descriptors now. + const std::vector<CodeGenRegister> &Registers = Target.getRegisters(); + for (unsigned i = 0, e = Registers.size(); i != e; ++i) { + const CodeGenRegister &Reg = Registers[i]; + OS << " { \""; + if (!Reg.TheDef->getValueAsString("AsmName").empty()) + OS << Reg.TheDef->getValueAsString("AsmName"); + else + OS << Reg.getName(); + OS << "\",\t\""; + OS << Reg.getName() << "\",\t"; + if (RegisterAliases.count(Reg.TheDef)) + OS << Reg.getName() << "_AliasSet,\t"; + else + OS << "Empty_AliasSet,\t"; + if (RegisterSubRegs.count(Reg.TheDef)) + OS << Reg.getName() << "_SubRegsSet,\t"; + else + OS << "Empty_SubRegsSet,\t"; + if (RegisterSuperRegs.count(Reg.TheDef)) + OS << Reg.getName() << "_SuperRegsSet },\n"; + else + OS << "Empty_SuperRegsSet },\n"; + } + OS << " };\n"; // End of register descriptors... + OS << "}\n\n"; // End of anonymous namespace... + + std::string ClassName = Target.getName() + "GenRegisterInfo"; + + // Calculate the mapping of subregister+index pairs to physical registers. + std::vector<Record*> SubRegs = Records.getAllDerivedDefinitions("SubRegSet"); + for (unsigned i = 0, e = SubRegs.size(); i != e; ++i) { + int subRegIndex = SubRegs[i]->getValueAsInt("index"); + std::vector<Record*> From = SubRegs[i]->getValueAsListOfDefs("From"); + std::vector<Record*> To = SubRegs[i]->getValueAsListOfDefs("To"); + + if (From.size() != To.size()) { + cerr << "Error: register list and sub-register list not of equal length" + << " in SubRegSet\n"; + exit(1); + } + + // For each entry in from/to vectors, insert the to register at index + for (unsigned ii = 0, ee = From.size(); ii != ee; ++ii) + SubRegVectors[From[ii]].push_back(std::make_pair(subRegIndex, To[ii])); + } + + // Emit the subregister + index mapping function based on the information + // calculated above. + OS << "unsigned " << ClassName + << "::getSubReg(unsigned RegNo, unsigned Index) const {\n" + << " switch (RegNo) {\n" + << " default:\n return 0;\n"; + for (std::map<Record*, std::vector<std::pair<int, Record*> > >::iterator + I = SubRegVectors.begin(), E = SubRegVectors.end(); I != E; ++I) { + OS << " case " << getQualifiedName(I->first) << ":\n"; + OS << " switch (Index) {\n"; + OS << " default: return 0;\n"; + for (unsigned i = 0, e = I->second.size(); i != e; ++i) + OS << " case " << (I->second)[i].first << ": return " + << getQualifiedName((I->second)[i].second) << ";\n"; + OS << " };\n" << " break;\n"; + } + OS << " };\n"; + OS << " return 0;\n"; + OS << "}\n\n"; + + // Emit the constructor of the class... + OS << ClassName << "::" << ClassName + << "(int CallFrameSetupOpcode, int CallFrameDestroyOpcode)\n" + << " : TargetRegisterInfo(RegisterDescriptors, " << Registers.size()+1 + << ", RegisterClasses, RegisterClasses+" << RegisterClasses.size() <<",\n " + << " CallFrameSetupOpcode, CallFrameDestroyOpcode,\n" + << " SubregHashTable, SubregHashTableSize,\n" + << " SuperregHashTable, SuperregHashTableSize,\n" + << " AliasesHashTable, AliasesHashTableSize) {\n" + << "}\n\n"; + + // Collect all information about dwarf register numbers + + // First, just pull all provided information to the map + unsigned maxLength = 0; + for (unsigned i = 0, e = Registers.size(); i != e; ++i) { + Record *Reg = Registers[i].TheDef; + std::vector<int64_t> RegNums = Reg->getValueAsListOfInts("DwarfNumbers"); + maxLength = std::max((size_t)maxLength, RegNums.size()); + if (DwarfRegNums.count(Reg)) + cerr << "Warning: DWARF numbers for register " << getQualifiedName(Reg) + << "specified multiple times\n"; + DwarfRegNums[Reg] = RegNums; + } + + // Now we know maximal length of number list. Append -1's, where needed + for (DwarfRegNumsMapTy::iterator + I = DwarfRegNums.begin(), E = DwarfRegNums.end(); I != E; ++I) + for (unsigned i = I->second.size(), e = maxLength; i != e; ++i) + I->second.push_back(-1); + + // Emit information about the dwarf register numbers. + OS << "int " << ClassName << "::getDwarfRegNumFull(unsigned RegNum, " + << "unsigned Flavour) const {\n" + << " switch (Flavour) {\n" + << " default:\n" + << " assert(0 && \"Unknown DWARF flavour\");\n" + << " return -1;\n"; + + for (unsigned i = 0, e = maxLength; i != e; ++i) { + OS << " case " << i << ":\n" + << " switch (RegNum) {\n" + << " default:\n" + << " assert(0 && \"Invalid RegNum\");\n" + << " return -1;\n"; + + // Sort by name to get a stable order. + + + for (DwarfRegNumsMapTy::iterator + I = DwarfRegNums.begin(), E = DwarfRegNums.end(); I != E; ++I) { + int RegNo = I->second[i]; + if (RegNo != -2) + OS << " case " << getQualifiedName(I->first) << ":\n" + << " return " << RegNo << ";\n"; + else + OS << " case " << getQualifiedName(I->first) << ":\n" + << " assert(0 && \"Invalid register for this mode\");\n" + << " return -1;\n"; + } + OS << " };\n"; + } + + OS << " };\n}\n\n"; + + OS << "} // End llvm namespace \n"; +} diff --git a/utils/TableGen/RegisterInfoEmitter.h b/utils/TableGen/RegisterInfoEmitter.h new file mode 100644 index 0000000000000..b5493a9f4574f --- /dev/null +++ b/utils/TableGen/RegisterInfoEmitter.h @@ -0,0 +1,40 @@ +//===- RegisterInfoEmitter.h - Generate a Register File Desc. ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend is responsible for emitting a description of a target +// register file for a code generator. It uses instances of the Register, +// RegisterAliases, and RegisterClass classes to gather this information. +// +//===----------------------------------------------------------------------===// + +#ifndef REGISTER_INFO_EMITTER_H +#define REGISTER_INFO_EMITTER_H + +#include "TableGenBackend.h" + +namespace llvm { + +class RegisterInfoEmitter : public TableGenBackend { + RecordKeeper &Records; +public: + RegisterInfoEmitter(RecordKeeper &R) : Records(R) {} + + // run - Output the register file description, returning true on failure. + void run(std::ostream &o); + + // runHeader - Emit a header fragment for the register info emitter. + void runHeader(std::ostream &o); + + // runEnums - Print out enum values for all of the registers. + void runEnums(std::ostream &o); +}; + +} // End llvm namespace + +#endif diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp new file mode 100644 index 0000000000000..a28e8bc3a4634 --- /dev/null +++ b/utils/TableGen/SubtargetEmitter.cpp @@ -0,0 +1,513 @@ +//===- SubtargetEmitter.cpp - Generate subtarget enumerations -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend emits subtarget enumerations. +// +//===----------------------------------------------------------------------===// + +#include "SubtargetEmitter.h" +#include "CodeGenTarget.h" +#include "Record.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Debug.h" +#include <algorithm> +using namespace llvm; + +// +// Enumeration - Emit the specified class as an enumeration. +// +void SubtargetEmitter::Enumeration(std::ostream &OS, + const char *ClassName, + bool isBits) { + // Get all records of class and sort + std::vector<Record*> DefList = Records.getAllDerivedDefinitions(ClassName); + std::sort(DefList.begin(), DefList.end(), LessRecord()); + + // Open enumeration + OS << "enum {\n"; + + // For each record + for (unsigned i = 0, N = DefList.size(); i < N;) { + // Next record + Record *Def = DefList[i]; + + // Get and emit name + OS << " " << Def->getName(); + + // If bit flags then emit expression (1 << i) + if (isBits) OS << " = " << " 1 << " << i; + + // Depending on 'if more in the list' emit comma + if (++i < N) OS << ","; + + OS << "\n"; + } + + // Close enumeration + OS << "};\n"; +} + +// +// FeatureKeyValues - Emit data of all the subtarget features. Used by the +// command line. +// +void SubtargetEmitter::FeatureKeyValues(std::ostream &OS) { + // Gather and sort all the features + std::vector<Record*> FeatureList = + Records.getAllDerivedDefinitions("SubtargetFeature"); + std::sort(FeatureList.begin(), FeatureList.end(), LessRecordFieldName()); + + // Begin feature table + OS << "// Sorted (by key) array of values for CPU features.\n" + << "static const llvm::SubtargetFeatureKV FeatureKV[] = {\n"; + + // For each feature + for (unsigned i = 0, N = FeatureList.size(); i < N; ++i) { + // Next feature + Record *Feature = FeatureList[i]; + + const std::string &Name = Feature->getName(); + const std::string &CommandLineName = Feature->getValueAsString("Name"); + const std::string &Desc = Feature->getValueAsString("Desc"); + + if (CommandLineName.empty()) continue; + + // Emit as { "feature", "description", featureEnum, i1 | i2 | ... | in } + OS << " { " + << "\"" << CommandLineName << "\", " + << "\"" << Desc << "\", " + << Name << ", "; + + const std::vector<Record*> &ImpliesList = + Feature->getValueAsListOfDefs("Implies"); + + if (ImpliesList.empty()) { + OS << "0"; + } else { + for (unsigned j = 0, M = ImpliesList.size(); j < M;) { + OS << ImpliesList[j]->getName(); + if (++j < M) OS << " | "; + } + } + + OS << " }"; + + // Depending on 'if more in the list' emit comma + if ((i + 1) < N) OS << ","; + + OS << "\n"; + } + + // End feature table + OS << "};\n"; + + // Emit size of table + OS<<"\nenum {\n"; + OS<<" FeatureKVSize = sizeof(FeatureKV)/sizeof(llvm::SubtargetFeatureKV)\n"; + OS<<"};\n"; +} + +// +// CPUKeyValues - Emit data of all the subtarget processors. Used by command +// line. +// +void SubtargetEmitter::CPUKeyValues(std::ostream &OS) { + // Gather and sort processor information + std::vector<Record*> ProcessorList = + Records.getAllDerivedDefinitions("Processor"); + std::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName()); + + // Begin processor table + OS << "// Sorted (by key) array of values for CPU subtype.\n" + << "static const llvm::SubtargetFeatureKV SubTypeKV[] = {\n"; + + // For each processor + for (unsigned i = 0, N = ProcessorList.size(); i < N;) { + // Next processor + Record *Processor = ProcessorList[i]; + + const std::string &Name = Processor->getValueAsString("Name"); + const std::vector<Record*> &FeatureList = + Processor->getValueAsListOfDefs("Features"); + + // Emit as { "cpu", "description", f1 | f2 | ... fn }, + OS << " { " + << "\"" << Name << "\", " + << "\"Select the " << Name << " processor\", "; + + if (FeatureList.empty()) { + OS << "0"; + } else { + for (unsigned j = 0, M = FeatureList.size(); j < M;) { + OS << FeatureList[j]->getName(); + if (++j < M) OS << " | "; + } + } + + // The "0" is for the "implies" section of this data structure. + OS << ", 0 }"; + + // Depending on 'if more in the list' emit comma + if (++i < N) OS << ","; + + OS << "\n"; + } + + // End processor table + OS << "};\n"; + + // Emit size of table + OS<<"\nenum {\n"; + OS<<" SubTypeKVSize = sizeof(SubTypeKV)/sizeof(llvm::SubtargetFeatureKV)\n"; + OS<<"};\n"; +} + +// +// CollectAllItinClasses - Gathers and enumerates all the itinerary classes. +// Returns itinerary class count. +// +unsigned SubtargetEmitter::CollectAllItinClasses(std::ostream &OS, + std::map<std::string, unsigned> &ItinClassesMap) { + // Gather and sort all itinerary classes + std::vector<Record*> ItinClassList = + Records.getAllDerivedDefinitions("InstrItinClass"); + std::sort(ItinClassList.begin(), ItinClassList.end(), LessRecord()); + + // For each itinerary class + unsigned N = ItinClassList.size(); + for (unsigned i = 0; i < N; i++) { + // Next itinerary class + const Record *ItinClass = ItinClassList[i]; + // Get name of itinerary class + // Assign itinerary class a unique number + ItinClassesMap[ItinClass->getName()] = i; + } + + // Emit size of table + OS<<"\nenum {\n"; + OS<<" ItinClassesSize = " << N << "\n"; + OS<<"};\n"; + + // Return itinerary class count + return N; +} + +// +// FormItineraryString - Compose a string containing the data initialization +// for the specified itinerary. N is the number of stages. +// +void SubtargetEmitter::FormItineraryString(Record *ItinData, + std::string &ItinString, + unsigned &NStages) { + // Get states list + const std::vector<Record*> &StageList = + ItinData->getValueAsListOfDefs("Stages"); + + // For each stage + unsigned N = NStages = StageList.size(); + for (unsigned i = 0; i < N;) { + // Next stage + const Record *Stage = StageList[i]; + + // Form string as ,{ cycles, u1 | u2 | ... | un } + int Cycles = Stage->getValueAsInt("Cycles"); + ItinString += " { " + itostr(Cycles) + ", "; + + // Get unit list + const std::vector<Record*> &UnitList = Stage->getValueAsListOfDefs("Units"); + + // For each unit + for (unsigned j = 0, M = UnitList.size(); j < M;) { + // Add name and bitwise or + ItinString += UnitList[j]->getName(); + if (++j < M) ItinString += " | "; + } + + // Close off stage + ItinString += " }"; + if (++i < N) ItinString += ", "; + } +} + +// +// EmitStageData - Generate unique itinerary stages. Record itineraries for +// processors. +// +void SubtargetEmitter::EmitStageData(std::ostream &OS, + unsigned NItinClasses, + std::map<std::string, unsigned> &ItinClassesMap, + std::vector<std::vector<InstrItinerary> > &ProcList) { + // Gather processor iteraries + std::vector<Record*> ProcItinList = + Records.getAllDerivedDefinitions("ProcessorItineraries"); + + // If just no itinerary then don't bother + if (ProcItinList.size() < 2) return; + + // Begin stages table + OS << "static const llvm::InstrStage Stages[] = {\n" + " { 0, 0 }, // No itinerary\n"; + + unsigned StageCount = 1; + unsigned ItinEnum = 1; + std::map<std::string, unsigned> ItinMap; + for (unsigned i = 0, N = ProcItinList.size(); i < N; i++) { + // Next record + Record *Proc = ProcItinList[i]; + + // Get processor itinerary name + const std::string &Name = Proc->getName(); + + // Skip default + if (Name == "NoItineraries") continue; + + // Create and expand processor itinerary to cover all itinerary classes + std::vector<InstrItinerary> ItinList; + ItinList.resize(NItinClasses); + + // Get itinerary data list + std::vector<Record*> ItinDataList = Proc->getValueAsListOfDefs("IID"); + + // For each itinerary data + for (unsigned j = 0, M = ItinDataList.size(); j < M; j++) { + // Next itinerary data + Record *ItinData = ItinDataList[j]; + + // Get string and stage count + std::string ItinString; + unsigned NStages; + FormItineraryString(ItinData, ItinString, NStages); + + // Check to see if it already exists + unsigned Find = ItinMap[ItinString]; + + // If new itinerary + if (Find == 0) { + // Emit as { cycles, u1 | u2 | ... | un }, // index + OS << ItinString << ", // " << ItinEnum << "\n"; + // Record Itin class number. + ItinMap[ItinString] = Find = StageCount; + StageCount += NStages; + ItinEnum++; + } + + // Set up itinerary as location and location + stage count + InstrItinerary Intinerary = { Find, Find + NStages }; + + // Locate where to inject into processor itinerary table + const std::string &Name = ItinData->getValueAsDef("TheClass")->getName(); + Find = ItinClassesMap[Name]; + + // Inject - empty slots will be 0, 0 + ItinList[Find] = Intinerary; + } + + // Add process itinerary to list + ProcList.push_back(ItinList); + } + + // Closing stage + OS << " { 0, 0 } // End itinerary\n"; + // End stages table + OS << "};\n"; + + // Emit size of table + OS<<"\nenum {\n"; + OS<<" StagesSize = sizeof(Stages)/sizeof(llvm::InstrStage)\n"; + OS<<"};\n"; +} + +// +// EmitProcessorData - Generate data for processor itineraries. +// +void SubtargetEmitter::EmitProcessorData(std::ostream &OS, + std::vector<std::vector<InstrItinerary> > &ProcList) { + // Get an iterator for processor itinerary stages + std::vector<std::vector<InstrItinerary> >::iterator + ProcListIter = ProcList.begin(); + + // For each processor itinerary + std::vector<Record*> Itins = + Records.getAllDerivedDefinitions("ProcessorItineraries"); + for (unsigned i = 0, N = Itins.size(); i < N; i++) { + // Next record + Record *Itin = Itins[i]; + + // Get processor itinerary name + const std::string &Name = Itin->getName(); + + // Skip default + if (Name == "NoItineraries") continue; + + // Begin processor itinerary table + OS << "\n"; + OS << "static const llvm::InstrItinerary " << Name << "[] = {\n"; + + // For each itinerary class + std::vector<InstrItinerary> &ItinList = *ProcListIter++; + for (unsigned j = 0, M = ItinList.size(); j < M;) { + InstrItinerary &Intinerary = ItinList[j]; + + // Emit in the form of { first, last } // index + if (Intinerary.First == 0) { + OS << " { 0, 0 }"; + } else { + OS << " { " << Intinerary.First << ", " << Intinerary.Last << " }"; + } + + // If more in list add comma + if (++j < M) OS << ","; + + OS << " // " << (j - 1) << "\n"; + } + + // End processor itinerary table + OS << "};\n"; + } +} + +// +// EmitProcessorLookup - generate cpu name to itinerary lookup table. +// +void SubtargetEmitter::EmitProcessorLookup(std::ostream &OS) { + // Gather and sort processor information + std::vector<Record*> ProcessorList = + Records.getAllDerivedDefinitions("Processor"); + std::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName()); + + // Begin processor table + OS << "\n"; + OS << "// Sorted (by key) array of itineraries for CPU subtype.\n" + << "static const llvm::SubtargetInfoKV ProcItinKV[] = {\n"; + + // For each processor + for (unsigned i = 0, N = ProcessorList.size(); i < N;) { + // Next processor + Record *Processor = ProcessorList[i]; + + const std::string &Name = Processor->getValueAsString("Name"); + const std::string &ProcItin = + Processor->getValueAsDef("ProcItin")->getName(); + + // Emit as { "cpu", procinit }, + OS << " { " + << "\"" << Name << "\", " + << "(void *)&" << ProcItin; + + OS << " }"; + + // Depending on ''if more in the list'' emit comma + if (++i < N) OS << ","; + + OS << "\n"; + } + + // End processor table + OS << "};\n"; + + // Emit size of table + OS<<"\nenum {\n"; + OS<<" ProcItinKVSize = sizeof(ProcItinKV)/" + "sizeof(llvm::SubtargetInfoKV)\n"; + OS<<"};\n"; +} + +// +// EmitData - Emits all stages and itineries, folding common patterns. +// +void SubtargetEmitter::EmitData(std::ostream &OS) { + std::map<std::string, unsigned> ItinClassesMap; + std::vector<std::vector<InstrItinerary> > ProcList; + + // Enumerate all the itinerary classes + unsigned NItinClasses = CollectAllItinClasses(OS, ItinClassesMap); + // Make sure the rest is worth the effort + HasItineraries = NItinClasses != 1; // Ignore NoItinerary. + + if (HasItineraries) { + // Emit the stage data + EmitStageData(OS, NItinClasses, ItinClassesMap, ProcList); + // Emit the processor itinerary data + EmitProcessorData(OS, ProcList); + // Emit the processor lookup data + EmitProcessorLookup(OS); + } +} + +// +// ParseFeaturesFunction - Produces a subtarget specific function for parsing +// the subtarget features string. +// +void SubtargetEmitter::ParseFeaturesFunction(std::ostream &OS) { + std::vector<Record*> Features = + Records.getAllDerivedDefinitions("SubtargetFeature"); + std::sort(Features.begin(), Features.end(), LessRecord()); + + OS << "// ParseSubtargetFeatures - Parses features string setting specified\n" + << "// subtarget options.\n" + << "std::string llvm::"; + OS << Target; + OS << "Subtarget::ParseSubtargetFeatures(const std::string &FS,\n" + << " const std::string &CPU) {\n" + << " SubtargetFeatures Features(FS);\n" + << " Features.setCPUIfNone(CPU);\n" + << " uint32_t Bits = Features.getBits(SubTypeKV, SubTypeKVSize,\n" + << " FeatureKV, FeatureKVSize);\n"; + + for (unsigned i = 0; i < Features.size(); i++) { + // Next record + Record *R = Features[i]; + const std::string &Instance = R->getName(); + const std::string &Value = R->getValueAsString("Value"); + const std::string &Attribute = R->getValueAsString("Attribute"); + + if (Value=="true" || Value=="false") + OS << " if ((Bits & " << Instance << ") != 0) " + << Attribute << " = " << Value << ";\n"; + else + OS << " if ((Bits & " << Instance << ") != 0 && " << Attribute << + " < " << Value << ") " << Attribute << " = " << Value << ";\n"; + } + + if (HasItineraries) { + OS << "\n" + << " InstrItinerary *Itinerary = (InstrItinerary *)" + << "Features.getInfo(ProcItinKV, ProcItinKVSize);\n" + << " InstrItins = InstrItineraryData(Stages, Itinerary);\n"; + } + + OS << " return Features.getCPU();\n" + << "}\n"; +} + +// +// SubtargetEmitter::run - Main subtarget enumeration emitter. +// +void SubtargetEmitter::run(std::ostream &OS) { + Target = CodeGenTarget().getName(); + + EmitSourceFileHeader("Subtarget Enumeration Source Fragment", OS); + + OS << "#include \"llvm/Target/SubtargetFeature.h\"\n"; + OS << "#include \"llvm/Target/TargetInstrItineraries.h\"\n\n"; + + Enumeration(OS, "FuncUnit", true); + OS<<"\n"; +// Enumeration(OS, "InstrItinClass", false); +// OS<<"\n"; + Enumeration(OS, "SubtargetFeature", true); + OS<<"\n"; + FeatureKeyValues(OS); + OS<<"\n"; + CPUKeyValues(OS); + OS<<"\n"; + EmitData(OS); + OS<<"\n"; + ParseFeaturesFunction(OS); +} diff --git a/utils/TableGen/SubtargetEmitter.h b/utils/TableGen/SubtargetEmitter.h new file mode 100644 index 0000000000000..4fcd8f8b0b24b --- /dev/null +++ b/utils/TableGen/SubtargetEmitter.h @@ -0,0 +1,62 @@ +//===- SubtargetEmitter.h - Generate subtarget enumerations -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend emits subtarget enumerations. +// +//===----------------------------------------------------------------------===// + +#ifndef SUBTARGET_EMITTER_H +#define SUBTARGET_EMITTER_H + +#include "TableGenBackend.h" +#include "llvm/Target/TargetInstrItineraries.h" +#include <vector> +#include <map> +#include <string> + + +namespace llvm { + +class SubtargetEmitter : public TableGenBackend { + + RecordKeeper &Records; + std::string Target; + bool HasItineraries; + + void Enumeration(std::ostream &OS, const char *ClassName, bool isBits); + void FeatureKeyValues(std::ostream &OS); + void CPUKeyValues(std::ostream &OS); + unsigned CollectAllItinClasses(std::ostream &OS, + std::map<std::string, unsigned> &ItinClassesMap); + void FormItineraryString(Record *ItinData, std::string &ItinString, + unsigned &NStages); + void EmitStageData(std::ostream &OS, unsigned NItinClasses, + std::map<std::string, unsigned> &ItinClassesMap, + std::vector<std::vector<InstrItinerary> > &ProcList); + void EmitProcessorData(std::ostream &OS, + std::vector<std::vector<InstrItinerary> > &ProcList); + void EmitProcessorLookup(std::ostream &OS); + void EmitData(std::ostream &OS); + void ParseFeaturesFunction(std::ostream &OS); + +public: + SubtargetEmitter(RecordKeeper &R) : Records(R), HasItineraries(false) {} + + // run - Output the subtarget enumerations, returning true on failure. + void run(std::ostream &o); + +}; + + +} // End llvm namespace + +#endif + + + diff --git a/utils/TableGen/TGLexer.cpp b/utils/TableGen/TGLexer.cpp new file mode 100644 index 0000000000000..758d499a8b5f3 --- /dev/null +++ b/utils/TableGen/TGLexer.cpp @@ -0,0 +1,460 @@ +//===- TGLexer.cpp - Lexer for TableGen -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implement the Lexer for TableGen. +// +//===----------------------------------------------------------------------===// + +#include "TGLexer.h" +#include "TGSourceMgr.h" +#include "llvm/Support/Streams.h" +#include "llvm/Support/MemoryBuffer.h" +#include <ostream> +#include "llvm/Config/config.h" +#include <cctype> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <cerrno> +using namespace llvm; + +TGLexer::TGLexer(TGSourceMgr &SM) : SrcMgr(SM) { + CurBuffer = 0; + CurBuf = SrcMgr.getMemoryBuffer(CurBuffer); + CurPtr = CurBuf->getBufferStart(); + TokStart = 0; +} + +TGLoc TGLexer::getLoc() const { + return TGLoc::getFromPointer(TokStart); +} + + +/// ReturnError - Set the error to the specified string at the specified +/// location. This is defined to always return tgtok::Error. +tgtok::TokKind TGLexer::ReturnError(const char *Loc, const std::string &Msg) { + PrintError(Loc, Msg); + return tgtok::Error; +} + + +void TGLexer::PrintError(const char *Loc, const std::string &Msg) const { + SrcMgr.PrintError(TGLoc::getFromPointer(Loc), Msg); +} + +void TGLexer::PrintError(TGLoc Loc, const std::string &Msg) const { + SrcMgr.PrintError(Loc, Msg); +} + + +int TGLexer::getNextChar() { + char CurChar = *CurPtr++; + switch (CurChar) { + default: + return (unsigned char)CurChar; + case 0: { + // A nul character in the stream is either the end of the current buffer or + // a random nul in the file. Disambiguate that here. + if (CurPtr-1 != CurBuf->getBufferEnd()) + return 0; // Just whitespace. + + // If this is the end of an included file, pop the parent file off the + // include stack. + TGLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer); + if (ParentIncludeLoc != TGLoc()) { + CurBuffer = SrcMgr.FindBufferContainingLoc(ParentIncludeLoc); + CurBuf = SrcMgr.getMemoryBuffer(CurBuffer); + CurPtr = ParentIncludeLoc.getPointer(); + return getNextChar(); + } + + // Otherwise, return end of file. + --CurPtr; // Another call to lex will return EOF again. + return EOF; + } + case '\n': + case '\r': + // Handle the newline character by ignoring it and incrementing the line + // count. However, be careful about 'dos style' files with \n\r in them. + // Only treat a \n\r or \r\n as a single line. + if ((*CurPtr == '\n' || (*CurPtr == '\r')) && + *CurPtr != CurChar) + ++CurPtr; // Eat the two char newline sequence. + return '\n'; + } +} + +tgtok::TokKind TGLexer::LexToken() { + TokStart = CurPtr; + // This always consumes at least one character. + int CurChar = getNextChar(); + + switch (CurChar) { + default: + // Handle letters: [a-zA-Z_] + if (isalpha(CurChar) || CurChar == '_' || CurChar == '#') + return LexIdentifier(); + + // Unknown character, emit an error. + return ReturnError(TokStart, "Unexpected character"); + case EOF: return tgtok::Eof; + case ':': return tgtok::colon; + case ';': return tgtok::semi; + case '.': return tgtok::period; + case ',': return tgtok::comma; + case '<': return tgtok::less; + case '>': return tgtok::greater; + case ']': return tgtok::r_square; + case '{': return tgtok::l_brace; + case '}': return tgtok::r_brace; + case '(': return tgtok::l_paren; + case ')': return tgtok::r_paren; + case '=': return tgtok::equal; + case '?': return tgtok::question; + + case 0: + case ' ': + case '\t': + case '\n': + case '\r': + // Ignore whitespace. + return LexToken(); + case '/': + // If this is the start of a // comment, skip until the end of the line or + // the end of the buffer. + if (*CurPtr == '/') + SkipBCPLComment(); + else if (*CurPtr == '*') { + if (SkipCComment()) + return tgtok::Error; + } else // Otherwise, this is an error. + return ReturnError(TokStart, "Unexpected character"); + return LexToken(); + case '-': case '+': + case '0': case '1': case '2': case '3': case '4': case '5': case '6': + case '7': case '8': case '9': + return LexNumber(); + case '"': return LexString(); + case '$': return LexVarName(); + case '[': return LexBracket(); + case '!': return LexExclaim(); + } +} + +/// LexString - Lex "[^"]*" +tgtok::TokKind TGLexer::LexString() { + const char *StrStart = CurPtr; + + CurStrVal = ""; + + while (*CurPtr != '"') { + // If we hit the end of the buffer, report an error. + if (*CurPtr == 0 && CurPtr == CurBuf->getBufferEnd()) + return ReturnError(StrStart, "End of file in string literal"); + + if (*CurPtr == '\n' || *CurPtr == '\r') + return ReturnError(StrStart, "End of line in string literal"); + + if (*CurPtr != '\\') { + CurStrVal += *CurPtr++; + continue; + } + + ++CurPtr; + + switch (*CurPtr) { + case '\\': case '\'': case '"': + // These turn into their literal character. + CurStrVal += *CurPtr++; + break; + case 't': + CurStrVal += '\t'; + ++CurPtr; + break; + case 'n': + CurStrVal += '\n'; + ++CurPtr; + break; + + case '\n': + case '\r': + return ReturnError(CurPtr, "escaped newlines not supported in tblgen"); + + // If we hit the end of the buffer, report an error. + case '\0': + if (CurPtr == CurBuf->getBufferEnd()) + return ReturnError(StrStart, "End of file in string literal"); + // FALL THROUGH + default: + return ReturnError(CurPtr, "invalid escape in string literal"); + } + } + + ++CurPtr; + return tgtok::StrVal; +} + +tgtok::TokKind TGLexer::LexVarName() { + if (!isalpha(CurPtr[0]) && CurPtr[0] != '_') + return ReturnError(TokStart, "Invalid variable name"); + + // Otherwise, we're ok, consume the rest of the characters. + const char *VarNameStart = CurPtr++; + + while (isalpha(*CurPtr) || isdigit(*CurPtr) || *CurPtr == '_') + ++CurPtr; + + CurStrVal.assign(VarNameStart, CurPtr); + return tgtok::VarName; +} + + +tgtok::TokKind TGLexer::LexIdentifier() { + // The first letter is [a-zA-Z_]. + const char *IdentStart = TokStart; + + // Match the rest of the identifier regex: [0-9a-zA-Z_]* + while (isalpha(*CurPtr) || isdigit(*CurPtr) || *CurPtr == '_' + || *CurPtr == '#') { + // If this contains a '#', make sure it's value + if (*CurPtr == '#') { + if (strncmp(CurPtr, "#NAME#", 6) != 0) { + return tgtok::Error; + } + CurPtr += 6; + } + else { + ++CurPtr; + } + } + + + // Check to see if this identifier is a keyword. + unsigned Len = CurPtr-IdentStart; + + if (Len == 3 && !memcmp(IdentStart, "int", 3)) return tgtok::Int; + if (Len == 3 && !memcmp(IdentStart, "bit", 3)) return tgtok::Bit; + if (Len == 4 && !memcmp(IdentStart, "bits", 4)) return tgtok::Bits; + if (Len == 6 && !memcmp(IdentStart, "string", 6)) return tgtok::String; + if (Len == 4 && !memcmp(IdentStart, "list", 4)) return tgtok::List; + if (Len == 4 && !memcmp(IdentStart, "code", 4)) return tgtok::Code; + if (Len == 3 && !memcmp(IdentStart, "dag", 3)) return tgtok::Dag; + + if (Len == 5 && !memcmp(IdentStart, "class", 5)) return tgtok::Class; + if (Len == 3 && !memcmp(IdentStart, "def", 3)) return tgtok::Def; + if (Len == 4 && !memcmp(IdentStart, "defm", 4)) return tgtok::Defm; + if (Len == 10 && !memcmp(IdentStart, "multiclass", 10)) + return tgtok::MultiClass; + if (Len == 5 && !memcmp(IdentStart, "field", 5)) return tgtok::Field; + if (Len == 3 && !memcmp(IdentStart, "let", 3)) return tgtok::Let; + if (Len == 2 && !memcmp(IdentStart, "in", 2)) return tgtok::In; + + if (Len == 7 && !memcmp(IdentStart, "include", 7)) { + if (LexInclude()) return tgtok::Error; + return Lex(); + } + + CurStrVal.assign(IdentStart, CurPtr); + return tgtok::Id; +} + +/// LexInclude - We just read the "include" token. Get the string token that +/// comes next and enter the include. +bool TGLexer::LexInclude() { + // The token after the include must be a string. + tgtok::TokKind Tok = LexToken(); + if (Tok == tgtok::Error) return true; + if (Tok != tgtok::StrVal) { + PrintError(getLoc(), "Expected filename after include"); + return true; + } + + // Get the string. + std::string Filename = CurStrVal; + + // Try to find the file. + MemoryBuffer *NewBuf = MemoryBuffer::getFile(Filename.c_str()); + + // If the file didn't exist directly, see if it's in an include path. + for (unsigned i = 0, e = IncludeDirectories.size(); i != e && !NewBuf; ++i) { + std::string IncFile = IncludeDirectories[i] + "/" + Filename; + NewBuf = MemoryBuffer::getFile(IncFile.c_str()); + } + + if (NewBuf == 0) { + PrintError(getLoc(), "Could not find include file '" + Filename + "'"); + return true; + } + + // Save the line number and lex buffer of the includer. + CurBuffer = SrcMgr.AddNewSourceBuffer(NewBuf, TGLoc::getFromPointer(CurPtr)); + + CurBuf = NewBuf; + CurPtr = CurBuf->getBufferStart(); + return false; +} + +void TGLexer::SkipBCPLComment() { + ++CurPtr; // skip the second slash. + while (1) { + switch (*CurPtr) { + case '\n': + case '\r': + return; // Newline is end of comment. + case 0: + // If this is the end of the buffer, end the comment. + if (CurPtr == CurBuf->getBufferEnd()) + return; + break; + } + // Otherwise, skip the character. + ++CurPtr; + } +} + +/// SkipCComment - This skips C-style /**/ comments. The only difference from C +/// is that we allow nesting. +bool TGLexer::SkipCComment() { + ++CurPtr; // skip the star. + unsigned CommentDepth = 1; + + while (1) { + int CurChar = getNextChar(); + switch (CurChar) { + case EOF: + PrintError(TokStart, "Unterminated comment!"); + return true; + case '*': + // End of the comment? + if (CurPtr[0] != '/') break; + + ++CurPtr; // End the */. + if (--CommentDepth == 0) + return false; + break; + case '/': + // Start of a nested comment? + if (CurPtr[0] != '*') break; + ++CurPtr; + ++CommentDepth; + break; + } + } +} + +/// LexNumber - Lex: +/// [-+]?[0-9]+ +/// 0x[0-9a-fA-F]+ +/// 0b[01]+ +tgtok::TokKind TGLexer::LexNumber() { + if (CurPtr[-1] == '0') { + if (CurPtr[0] == 'x') { + ++CurPtr; + const char *NumStart = CurPtr; + while (isxdigit(CurPtr[0])) + ++CurPtr; + + // Requires at least one hex digit. + if (CurPtr == NumStart) + return ReturnError(CurPtr-2, "Invalid hexadecimal number"); + + errno = 0; + CurIntVal = strtoll(NumStart, 0, 16); + if (errno == EINVAL) + return ReturnError(CurPtr-2, "Invalid hexadecimal number"); + if (errno == ERANGE) { + errno = 0; + CurIntVal = (int64_t)strtoull(NumStart, 0, 16); + if (errno == EINVAL) + return ReturnError(CurPtr-2, "Invalid hexadecimal number"); + if (errno == ERANGE) + return ReturnError(CurPtr-2, "Hexadecimal number out of range"); + } + return tgtok::IntVal; + } else if (CurPtr[0] == 'b') { + ++CurPtr; + const char *NumStart = CurPtr; + while (CurPtr[0] == '0' || CurPtr[0] == '1') + ++CurPtr; + + // Requires at least one binary digit. + if (CurPtr == NumStart) + return ReturnError(CurPtr-2, "Invalid binary number"); + CurIntVal = strtoll(NumStart, 0, 2); + return tgtok::IntVal; + } + } + + // Check for a sign without a digit. + if (!isdigit(CurPtr[0])) { + if (CurPtr[-1] == '-') + return tgtok::minus; + else if (CurPtr[-1] == '+') + return tgtok::plus; + } + + while (isdigit(CurPtr[0])) + ++CurPtr; + CurIntVal = strtoll(TokStart, 0, 10); + return tgtok::IntVal; +} + +/// LexBracket - We just read '['. If this is a code block, return it, +/// otherwise return the bracket. Match: '[' and '[{ ( [^}]+ | }[^]] )* }]' +tgtok::TokKind TGLexer::LexBracket() { + if (CurPtr[0] != '{') + return tgtok::l_square; + ++CurPtr; + const char *CodeStart = CurPtr; + while (1) { + int Char = getNextChar(); + if (Char == EOF) break; + + if (Char != '}') continue; + + Char = getNextChar(); + if (Char == EOF) break; + if (Char == ']') { + CurStrVal.assign(CodeStart, CurPtr-2); + return tgtok::CodeFragment; + } + } + + return ReturnError(CodeStart-2, "Unterminated Code Block"); +} + +/// LexExclaim - Lex '!' and '![a-zA-Z]+'. +tgtok::TokKind TGLexer::LexExclaim() { + if (!isalpha(*CurPtr)) + return ReturnError(CurPtr-1, "Invalid \"!operator\""); + + const char *Start = CurPtr++; + while (isalpha(*CurPtr)) + ++CurPtr; + + // Check to see which operator this is. + unsigned Len = CurPtr-Start; + + if (Len == 3 && !memcmp(Start, "con", 3)) return tgtok::XConcat; + if (Len == 3 && !memcmp(Start, "sra", 3)) return tgtok::XSRA; + if (Len == 3 && !memcmp(Start, "srl", 3)) return tgtok::XSRL; + if (Len == 3 && !memcmp(Start, "shl", 3)) return tgtok::XSHL; + if (Len == 9 && !memcmp(Start, "strconcat", 9)) return tgtok::XStrConcat; + if (Len == 10 && !memcmp(Start, "nameconcat", 10)) return tgtok::XNameConcat; + if (Len == 5 && !memcmp(Start, "subst", 5)) return tgtok::XSubst; + if (Len == 7 && !memcmp(Start, "foreach", 7)) return tgtok::XForEach; + if (Len == 4 && !memcmp(Start, "cast", 4)) return tgtok::XCast; + if (Len == 3 && !memcmp(Start, "car", 3)) return tgtok::XCar; + if (Len == 3 && !memcmp(Start, "cdr", 3)) return tgtok::XCdr; + if (Len == 4 && !memcmp(Start, "null", 4)) return tgtok::XNull; + if (Len == 2 && !memcmp(Start, "if", 2)) return tgtok::XIf; + + return ReturnError(Start-1, "Unknown operator"); +} + diff --git a/utils/TableGen/TGLexer.h b/utils/TableGen/TGLexer.h new file mode 100644 index 0000000000000..ac3b9840039b2 --- /dev/null +++ b/utils/TableGen/TGLexer.h @@ -0,0 +1,129 @@ +//===- TGLexer.h - Lexer for TableGen Files ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class represents the Lexer for tablegen files. +// +//===----------------------------------------------------------------------===// + +#ifndef TGLEXER_H +#define TGLEXER_H + +#include "llvm/Support/DataTypes.h" +#include <vector> +#include <string> +#include <iosfwd> +#include <cassert> + +namespace llvm { +class MemoryBuffer; +class TGSourceMgr; +class TGLoc; + +namespace tgtok { + enum TokKind { + // Markers + Eof, Error, + + // Tokens with no info. + minus, plus, // - + + l_square, r_square, // [ ] + l_brace, r_brace, // { } + l_paren, r_paren, // ( ) + less, greater, // < > + colon, semi, // ; : + comma, period, // , . + equal, question, // = ? + + // Keywords. + Bit, Bits, Class, Code, Dag, Def, Defm, Field, In, Int, Let, List, + MultiClass, String, + + // !keywords. + XConcat, XSRA, XSRL, XSHL, XStrConcat, XNameConcat, XCast, XSubst, + XForEach, XCar, XCdr, XNull, XIf, + + // Integer value. + IntVal, + + // String valued tokens. + Id, StrVal, VarName, CodeFragment + }; +} + +/// TGLexer - TableGen Lexer class. +class TGLexer { + TGSourceMgr &SrcMgr; + + const char *CurPtr; + const MemoryBuffer *CurBuf; + + // Information about the current token. + const char *TokStart; + tgtok::TokKind CurCode; + std::string CurStrVal; // This is valid for ID, STRVAL, VARNAME, CODEFRAGMENT + int64_t CurIntVal; // This is valid for INTVAL. + + /// CurBuffer - This is the current buffer index we're lexing from as managed + /// by the SourceMgr object. + int CurBuffer; + + // IncludeDirectories - This is the list of directories we should search for + // include files in. + std::vector<std::string> IncludeDirectories; +public: + TGLexer(TGSourceMgr &SrcMgr); + ~TGLexer() {} + + void setIncludeDirs(const std::vector<std::string> &Dirs) { + IncludeDirectories = Dirs; + } + + tgtok::TokKind Lex() { + return CurCode = LexToken(); + } + + tgtok::TokKind getCode() const { return CurCode; } + + const std::string &getCurStrVal() const { + assert((CurCode == tgtok::Id || CurCode == tgtok::StrVal || + CurCode == tgtok::VarName || CurCode == tgtok::CodeFragment) && + "This token doesn't have a string value"); + return CurStrVal; + } + int64_t getCurIntVal() const { + assert(CurCode == tgtok::IntVal && "This token isn't an integer"); + return CurIntVal; + } + + TGLoc getLoc() const; + + void PrintError(const char *Loc, const std::string &Msg) const; + void PrintError(TGLoc Loc, const std::string &Msg) const; + +private: + /// LexToken - Read the next token and return its code. + tgtok::TokKind LexToken(); + + tgtok::TokKind ReturnError(const char *Loc, const std::string &Msg); + + int getNextChar(); + void SkipBCPLComment(); + bool SkipCComment(); + tgtok::TokKind LexIdentifier(); + bool LexInclude(); + tgtok::TokKind LexString(); + tgtok::TokKind LexVarName(); + tgtok::TokKind LexNumber(); + tgtok::TokKind LexBracket(); + tgtok::TokKind LexExclaim(); +}; + +} // end namespace llvm + +#endif diff --git a/utils/TableGen/TGParser.cpp b/utils/TableGen/TGParser.cpp new file mode 100644 index 0000000000000..fc6f29fd9f1b5 --- /dev/null +++ b/utils/TableGen/TGParser.cpp @@ -0,0 +1,1937 @@ +//===- TGParser.cpp - Parser for TableGen Files ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implement the Parser for TableGen. +// +//===----------------------------------------------------------------------===// + +#include <algorithm> + +#include "TGParser.h" +#include "Record.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Streams.h" +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Support Code for the Semantic Actions. +//===----------------------------------------------------------------------===// + +namespace llvm { +struct SubClassReference { + TGLoc RefLoc; + Record *Rec; + std::vector<Init*> TemplateArgs; + SubClassReference() : Rec(0) {} + + bool isInvalid() const { return Rec == 0; } +}; + +struct SubMultiClassReference { + TGLoc RefLoc; + MultiClass *MC; + std::vector<Init*> TemplateArgs; + SubMultiClassReference() : MC(0) {} + + bool isInvalid() const { return MC == 0; } + void dump() const; +}; + +void SubMultiClassReference::dump() const { + cerr << "Multiclass:\n"; + + MC->dump(); + + cerr << "Template args:\n"; + for (std::vector<Init *>::const_iterator i = TemplateArgs.begin(), + iend = TemplateArgs.end(); + i != iend; + ++i) { + (*i)->dump(); + } +} + +} // end namespace llvm + +bool TGParser::AddValue(Record *CurRec, TGLoc Loc, const RecordVal &RV) { + if (CurRec == 0) + CurRec = &CurMultiClass->Rec; + + if (RecordVal *ERV = CurRec->getValue(RV.getName())) { + // The value already exists in the class, treat this as a set. + if (ERV->setValue(RV.getValue())) + return Error(Loc, "New definition of '" + RV.getName() + "' of type '" + + RV.getType()->getAsString() + "' is incompatible with " + + "previous definition of type '" + + ERV->getType()->getAsString() + "'"); + } else { + CurRec->addValue(RV); + } + return false; +} + +/// SetValue - +/// Return true on error, false on success. +bool TGParser::SetValue(Record *CurRec, TGLoc Loc, const std::string &ValName, + const std::vector<unsigned> &BitList, Init *V) { + if (!V) return false; + + if (CurRec == 0) CurRec = &CurMultiClass->Rec; + + RecordVal *RV = CurRec->getValue(ValName); + if (RV == 0) + return Error(Loc, "Value '" + ValName + "' unknown!"); + + // Do not allow assignments like 'X = X'. This will just cause infinite loops + // in the resolution machinery. + if (BitList.empty()) + if (VarInit *VI = dynamic_cast<VarInit*>(V)) + if (VI->getName() == ValName) + return false; + + // If we are assigning to a subset of the bits in the value... then we must be + // assigning to a field of BitsRecTy, which must have a BitsInit + // initializer. + // + if (!BitList.empty()) { + BitsInit *CurVal = dynamic_cast<BitsInit*>(RV->getValue()); + if (CurVal == 0) + return Error(Loc, "Value '" + ValName + "' is not a bits type"); + + // Convert the incoming value to a bits type of the appropriate size... + Init *BI = V->convertInitializerTo(new BitsRecTy(BitList.size())); + if (BI == 0) { + V->convertInitializerTo(new BitsRecTy(BitList.size())); + return Error(Loc, "Initializer is not compatible with bit range"); + } + + // We should have a BitsInit type now. + BitsInit *BInit = dynamic_cast<BitsInit*>(BI); + assert(BInit != 0); + + BitsInit *NewVal = new BitsInit(CurVal->getNumBits()); + + // Loop over bits, assigning values as appropriate. + for (unsigned i = 0, e = BitList.size(); i != e; ++i) { + unsigned Bit = BitList[i]; + if (NewVal->getBit(Bit)) + return Error(Loc, "Cannot set bit #" + utostr(Bit) + " of value '" + + ValName + "' more than once"); + NewVal->setBit(Bit, BInit->getBit(i)); + } + + for (unsigned i = 0, e = CurVal->getNumBits(); i != e; ++i) + if (NewVal->getBit(i) == 0) + NewVal->setBit(i, CurVal->getBit(i)); + + V = NewVal; + } + + if (RV->setValue(V)) + return Error(Loc, "Value '" + ValName + "' of type '" + + RV->getType()->getAsString() + + "' is incompatible with initializer '" + V->getAsString() +"'"); + return false; +} + +/// AddSubClass - Add SubClass as a subclass to CurRec, resolving its template +/// args as SubClass's template arguments. +bool TGParser::AddSubClass(Record *CurRec, SubClassReference &SubClass) { + Record *SC = SubClass.Rec; + // Add all of the values in the subclass into the current class. + const std::vector<RecordVal> &Vals = SC->getValues(); + for (unsigned i = 0, e = Vals.size(); i != e; ++i) + if (AddValue(CurRec, SubClass.RefLoc, Vals[i])) + return true; + + const std::vector<std::string> &TArgs = SC->getTemplateArgs(); + + // Ensure that an appropriate number of template arguments are specified. + if (TArgs.size() < SubClass.TemplateArgs.size()) + return Error(SubClass.RefLoc, "More template args specified than expected"); + + // Loop over all of the template arguments, setting them to the specified + // value or leaving them as the default if necessary. + for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { + if (i < SubClass.TemplateArgs.size()) { + // If a value is specified for this template arg, set it now. + if (SetValue(CurRec, SubClass.RefLoc, TArgs[i], std::vector<unsigned>(), + SubClass.TemplateArgs[i])) + return true; + + // Resolve it next. + CurRec->resolveReferencesTo(CurRec->getValue(TArgs[i])); + + // Now remove it. + CurRec->removeValue(TArgs[i]); + + } else if (!CurRec->getValue(TArgs[i])->getValue()->isComplete()) { + return Error(SubClass.RefLoc,"Value not specified for template argument #" + + utostr(i) + " (" + TArgs[i] + ") of subclass '" + + SC->getName() + "'!"); + } + } + + // Since everything went well, we can now set the "superclass" list for the + // current record. + const std::vector<Record*> &SCs = SC->getSuperClasses(); + for (unsigned i = 0, e = SCs.size(); i != e; ++i) { + if (CurRec->isSubClassOf(SCs[i])) + return Error(SubClass.RefLoc, + "Already subclass of '" + SCs[i]->getName() + "'!\n"); + CurRec->addSuperClass(SCs[i]); + } + + if (CurRec->isSubClassOf(SC)) + return Error(SubClass.RefLoc, + "Already subclass of '" + SC->getName() + "'!\n"); + CurRec->addSuperClass(SC); + return false; +} + +/// AddSubMultiClass - Add SubMultiClass as a subclass to +/// CurMC, resolving its template args as SubMultiClass's +/// template arguments. +bool TGParser::AddSubMultiClass(MultiClass *CurMC, + SubMultiClassReference &SubMultiClass) { + MultiClass *SMC = SubMultiClass.MC; + Record *CurRec = &CurMC->Rec; + + const std::vector<RecordVal> &MCVals = CurRec->getValues(); + + // Add all of the values in the subclass into the current class. + const std::vector<RecordVal> &SMCVals = SMC->Rec.getValues(); + for (unsigned i = 0, e = SMCVals.size(); i != e; ++i) + if (AddValue(CurRec, SubMultiClass.RefLoc, SMCVals[i])) + return true; + + int newDefStart = CurMC->DefPrototypes.size(); + + // Add all of the defs in the subclass into the current multiclass. + for (MultiClass::RecordVector::const_iterator i = SMC->DefPrototypes.begin(), + iend = SMC->DefPrototypes.end(); + i != iend; + ++i) { + // Clone the def and add it to the current multiclass + Record *NewDef = new Record(**i); + + // Add all of the values in the superclass into the current def. + for (unsigned i = 0, e = MCVals.size(); i != e; ++i) + if (AddValue(NewDef, SubMultiClass.RefLoc, MCVals[i])) + return true; + + CurMC->DefPrototypes.push_back(NewDef); + } + + const std::vector<std::string> &SMCTArgs = SMC->Rec.getTemplateArgs(); + + // Ensure that an appropriate number of template arguments are + // specified. + if (SMCTArgs.size() < SubMultiClass.TemplateArgs.size()) + return Error(SubMultiClass.RefLoc, + "More template args specified than expected"); + + // Loop over all of the template arguments, setting them to the specified + // value or leaving them as the default if necessary. + for (unsigned i = 0, e = SMCTArgs.size(); i != e; ++i) { + if (i < SubMultiClass.TemplateArgs.size()) { + // If a value is specified for this template arg, set it in the + // superclass now. + if (SetValue(CurRec, SubMultiClass.RefLoc, SMCTArgs[i], + std::vector<unsigned>(), + SubMultiClass.TemplateArgs[i])) + return true; + + // Resolve it next. + CurRec->resolveReferencesTo(CurRec->getValue(SMCTArgs[i])); + + // Now remove it. + CurRec->removeValue(SMCTArgs[i]); + + // If a value is specified for this template arg, set it in the + // new defs now. + for (MultiClass::RecordVector::iterator j = + CurMC->DefPrototypes.begin() + newDefStart, + jend = CurMC->DefPrototypes.end(); + j != jend; + ++j) { + Record *Def = *j; + + if (SetValue(Def, SubMultiClass.RefLoc, SMCTArgs[i], + std::vector<unsigned>(), + SubMultiClass.TemplateArgs[i])) + return true; + + // Resolve it next. + Def->resolveReferencesTo(Def->getValue(SMCTArgs[i])); + + // Now remove it + Def->removeValue(SMCTArgs[i]); + } + } else if (!CurRec->getValue(SMCTArgs[i])->getValue()->isComplete()) { + return Error(SubMultiClass.RefLoc, + "Value not specified for template argument #" + + utostr(i) + " (" + SMCTArgs[i] + ") of subclass '" + + SMC->Rec.getName() + "'!"); + } + } + + return false; +} + +//===----------------------------------------------------------------------===// +// Parser Code +//===----------------------------------------------------------------------===// + +/// isObjectStart - Return true if this is a valid first token for an Object. +static bool isObjectStart(tgtok::TokKind K) { + return K == tgtok::Class || K == tgtok::Def || + K == tgtok::Defm || K == tgtok::Let || K == tgtok::MultiClass; +} + +/// ParseObjectName - If an object name is specified, return it. Otherwise, +/// return an anonymous name. +/// ObjectName ::= ID +/// ObjectName ::= /*empty*/ +/// +std::string TGParser::ParseObjectName() { + if (Lex.getCode() == tgtok::Id) { + std::string Ret = Lex.getCurStrVal(); + Lex.Lex(); + return Ret; + } + + static unsigned AnonCounter = 0; + return "anonymous."+utostr(AnonCounter++); +} + + +/// ParseClassID - Parse and resolve a reference to a class name. This returns +/// null on error. +/// +/// ClassID ::= ID +/// +Record *TGParser::ParseClassID() { + if (Lex.getCode() != tgtok::Id) { + TokError("expected name for ClassID"); + return 0; + } + + Record *Result = Records.getClass(Lex.getCurStrVal()); + if (Result == 0) + TokError("Couldn't find class '" + Lex.getCurStrVal() + "'"); + + Lex.Lex(); + return Result; +} + +/// ParseMultiClassID - Parse and resolve a reference to a multiclass name. +/// This returns null on error. +/// +/// MultiClassID ::= ID +/// +MultiClass *TGParser::ParseMultiClassID() { + if (Lex.getCode() != tgtok::Id) { + TokError("expected name for ClassID"); + return 0; + } + + MultiClass *Result = MultiClasses[Lex.getCurStrVal()]; + if (Result == 0) + TokError("Couldn't find class '" + Lex.getCurStrVal() + "'"); + + Lex.Lex(); + return Result; +} + +Record *TGParser::ParseDefmID() { + if (Lex.getCode() != tgtok::Id) { + TokError("expected multiclass name"); + return 0; + } + + MultiClass *MC = MultiClasses[Lex.getCurStrVal()]; + if (MC == 0) { + TokError("Couldn't find multiclass '" + Lex.getCurStrVal() + "'"); + return 0; + } + + Lex.Lex(); + return &MC->Rec; +} + + + +/// ParseSubClassReference - Parse a reference to a subclass or to a templated +/// subclass. This returns a SubClassRefTy with a null Record* on error. +/// +/// SubClassRef ::= ClassID +/// SubClassRef ::= ClassID '<' ValueList '>' +/// +SubClassReference TGParser:: +ParseSubClassReference(Record *CurRec, bool isDefm) { + SubClassReference Result; + Result.RefLoc = Lex.getLoc(); + + if (isDefm) + Result.Rec = ParseDefmID(); + else + Result.Rec = ParseClassID(); + if (Result.Rec == 0) return Result; + + // If there is no template arg list, we're done. + if (Lex.getCode() != tgtok::less) + return Result; + Lex.Lex(); // Eat the '<' + + if (Lex.getCode() == tgtok::greater) { + TokError("subclass reference requires a non-empty list of template values"); + Result.Rec = 0; + return Result; + } + + Result.TemplateArgs = ParseValueList(CurRec); + if (Result.TemplateArgs.empty()) { + Result.Rec = 0; // Error parsing value list. + return Result; + } + + if (Lex.getCode() != tgtok::greater) { + TokError("expected '>' in template value list"); + Result.Rec = 0; + return Result; + } + Lex.Lex(); + + return Result; +} + +/// ParseSubMultiClassReference - Parse a reference to a subclass or to a +/// templated submulticlass. This returns a SubMultiClassRefTy with a null +/// Record* on error. +/// +/// SubMultiClassRef ::= MultiClassID +/// SubMultiClassRef ::= MultiClassID '<' ValueList '>' +/// +SubMultiClassReference TGParser:: +ParseSubMultiClassReference(MultiClass *CurMC) { + SubMultiClassReference Result; + Result.RefLoc = Lex.getLoc(); + + Result.MC = ParseMultiClassID(); + if (Result.MC == 0) return Result; + + // If there is no template arg list, we're done. + if (Lex.getCode() != tgtok::less) + return Result; + Lex.Lex(); // Eat the '<' + + if (Lex.getCode() == tgtok::greater) { + TokError("subclass reference requires a non-empty list of template values"); + Result.MC = 0; + return Result; + } + + Result.TemplateArgs = ParseValueList(&CurMC->Rec); + if (Result.TemplateArgs.empty()) { + Result.MC = 0; // Error parsing value list. + return Result; + } + + if (Lex.getCode() != tgtok::greater) { + TokError("expected '>' in template value list"); + Result.MC = 0; + return Result; + } + Lex.Lex(); + + return Result; +} + +/// ParseRangePiece - Parse a bit/value range. +/// RangePiece ::= INTVAL +/// RangePiece ::= INTVAL '-' INTVAL +/// RangePiece ::= INTVAL INTVAL +bool TGParser::ParseRangePiece(std::vector<unsigned> &Ranges) { + if (Lex.getCode() != tgtok::IntVal) { + TokError("expected integer or bitrange"); + return true; + } + int64_t Start = Lex.getCurIntVal(); + int64_t End; + + if (Start < 0) + return TokError("invalid range, cannot be negative"); + + switch (Lex.Lex()) { // eat first character. + default: + Ranges.push_back(Start); + return false; + case tgtok::minus: + if (Lex.Lex() != tgtok::IntVal) { + TokError("expected integer value as end of range"); + return true; + } + End = Lex.getCurIntVal(); + break; + case tgtok::IntVal: + End = -Lex.getCurIntVal(); + break; + } + if (End < 0) + return TokError("invalid range, cannot be negative"); + Lex.Lex(); + + // Add to the range. + if (Start < End) { + for (; Start <= End; ++Start) + Ranges.push_back(Start); + } else { + for (; Start >= End; --Start) + Ranges.push_back(Start); + } + return false; +} + +/// ParseRangeList - Parse a list of scalars and ranges into scalar values. +/// +/// RangeList ::= RangePiece (',' RangePiece)* +/// +std::vector<unsigned> TGParser::ParseRangeList() { + std::vector<unsigned> Result; + + // Parse the first piece. + if (ParseRangePiece(Result)) + return std::vector<unsigned>(); + while (Lex.getCode() == tgtok::comma) { + Lex.Lex(); // Eat the comma. + + // Parse the next range piece. + if (ParseRangePiece(Result)) + return std::vector<unsigned>(); + } + return Result; +} + +/// ParseOptionalRangeList - Parse either a range list in <>'s or nothing. +/// OptionalRangeList ::= '<' RangeList '>' +/// OptionalRangeList ::= /*empty*/ +bool TGParser::ParseOptionalRangeList(std::vector<unsigned> &Ranges) { + if (Lex.getCode() != tgtok::less) + return false; + + TGLoc StartLoc = Lex.getLoc(); + Lex.Lex(); // eat the '<' + + // Parse the range list. + Ranges = ParseRangeList(); + if (Ranges.empty()) return true; + + if (Lex.getCode() != tgtok::greater) { + TokError("expected '>' at end of range list"); + return Error(StartLoc, "to match this '<'"); + } + Lex.Lex(); // eat the '>'. + return false; +} + +/// ParseOptionalBitList - Parse either a bit list in {}'s or nothing. +/// OptionalBitList ::= '{' RangeList '}' +/// OptionalBitList ::= /*empty*/ +bool TGParser::ParseOptionalBitList(std::vector<unsigned> &Ranges) { + if (Lex.getCode() != tgtok::l_brace) + return false; + + TGLoc StartLoc = Lex.getLoc(); + Lex.Lex(); // eat the '{' + + // Parse the range list. + Ranges = ParseRangeList(); + if (Ranges.empty()) return true; + + if (Lex.getCode() != tgtok::r_brace) { + TokError("expected '}' at end of bit list"); + return Error(StartLoc, "to match this '{'"); + } + Lex.Lex(); // eat the '}'. + return false; +} + + +/// ParseType - Parse and return a tblgen type. This returns null on error. +/// +/// Type ::= STRING // string type +/// Type ::= BIT // bit type +/// Type ::= BITS '<' INTVAL '>' // bits<x> type +/// Type ::= INT // int type +/// Type ::= LIST '<' Type '>' // list<x> type +/// Type ::= CODE // code type +/// Type ::= DAG // dag type +/// Type ::= ClassID // Record Type +/// +RecTy *TGParser::ParseType() { + switch (Lex.getCode()) { + default: TokError("Unknown token when expecting a type"); return 0; + case tgtok::String: Lex.Lex(); return new StringRecTy(); + case tgtok::Bit: Lex.Lex(); return new BitRecTy(); + case tgtok::Int: Lex.Lex(); return new IntRecTy(); + case tgtok::Code: Lex.Lex(); return new CodeRecTy(); + case tgtok::Dag: Lex.Lex(); return new DagRecTy(); + case tgtok::Id: + if (Record *R = ParseClassID()) return new RecordRecTy(R); + return 0; + case tgtok::Bits: { + if (Lex.Lex() != tgtok::less) { // Eat 'bits' + TokError("expected '<' after bits type"); + return 0; + } + if (Lex.Lex() != tgtok::IntVal) { // Eat '<' + TokError("expected integer in bits<n> type"); + return 0; + } + uint64_t Val = Lex.getCurIntVal(); + if (Lex.Lex() != tgtok::greater) { // Eat count. + TokError("expected '>' at end of bits<n> type"); + return 0; + } + Lex.Lex(); // Eat '>' + return new BitsRecTy(Val); + } + case tgtok::List: { + if (Lex.Lex() != tgtok::less) { // Eat 'bits' + TokError("expected '<' after list type"); + return 0; + } + Lex.Lex(); // Eat '<' + RecTy *SubType = ParseType(); + if (SubType == 0) return 0; + + if (Lex.getCode() != tgtok::greater) { + TokError("expected '>' at end of list<ty> type"); + return 0; + } + Lex.Lex(); // Eat '>' + return new ListRecTy(SubType); + } + } +} + +/// ParseIDValue - Parse an ID as a value and decode what it means. +/// +/// IDValue ::= ID [def local value] +/// IDValue ::= ID [def template arg] +/// IDValue ::= ID [multiclass local value] +/// IDValue ::= ID [multiclass template argument] +/// IDValue ::= ID [def name] +/// +Init *TGParser::ParseIDValue(Record *CurRec) { + assert(Lex.getCode() == tgtok::Id && "Expected ID in ParseIDValue"); + std::string Name = Lex.getCurStrVal(); + TGLoc Loc = Lex.getLoc(); + Lex.Lex(); + return ParseIDValue(CurRec, Name, Loc); +} + +/// ParseIDValue - This is just like ParseIDValue above, but it assumes the ID +/// has already been read. +Init *TGParser::ParseIDValue(Record *CurRec, + const std::string &Name, TGLoc NameLoc) { + if (CurRec) { + if (const RecordVal *RV = CurRec->getValue(Name)) + return new VarInit(Name, RV->getType()); + + std::string TemplateArgName = CurRec->getName()+":"+Name; + if (CurRec->isTemplateArg(TemplateArgName)) { + const RecordVal *RV = CurRec->getValue(TemplateArgName); + assert(RV && "Template arg doesn't exist??"); + return new VarInit(TemplateArgName, RV->getType()); + } + } + + if (CurMultiClass) { + std::string MCName = CurMultiClass->Rec.getName()+"::"+Name; + if (CurMultiClass->Rec.isTemplateArg(MCName)) { + const RecordVal *RV = CurMultiClass->Rec.getValue(MCName); + assert(RV && "Template arg doesn't exist??"); + return new VarInit(MCName, RV->getType()); + } + } + + if (Record *D = Records.getDef(Name)) + return new DefInit(D); + + Error(NameLoc, "Variable not defined: '" + Name + "'"); + return 0; +} + +/// ParseOperation - Parse an operator. This returns null on error. +/// +/// Operation ::= XOperator ['<' Type '>'] '(' Args ')' +/// +Init *TGParser::ParseOperation(Record *CurRec) { + switch (Lex.getCode()) { + default: + TokError("unknown operation"); + return 0; + break; + case tgtok::XCar: + case tgtok::XCdr: + case tgtok::XNull: + case tgtok::XCast: { // Value ::= !unop '(' Value ')' + UnOpInit::UnaryOp Code; + RecTy *Type = 0; + + switch (Lex.getCode()) { + default: assert(0 && "Unhandled code!"); + case tgtok::XCast: + Lex.Lex(); // eat the operation + Code = UnOpInit::CAST; + + Type = ParseOperatorType(); + + if (Type == 0) { + TokError("did not get type for unary operator"); + return 0; + } + + break; + case tgtok::XCar: + Lex.Lex(); // eat the operation + Code = UnOpInit::CAR; + break; + case tgtok::XCdr: + Lex.Lex(); // eat the operation + Code = UnOpInit::CDR; + break; + case tgtok::XNull: + Lex.Lex(); // eat the operation + Code = UnOpInit::LNULL; + Type = new IntRecTy; + break; + } + if (Lex.getCode() != tgtok::l_paren) { + TokError("expected '(' after unary operator"); + return 0; + } + Lex.Lex(); // eat the '(' + + Init *LHS = ParseValue(CurRec); + if (LHS == 0) return 0; + + if (Code == UnOpInit::CAR + || Code == UnOpInit::CDR + || Code == UnOpInit::LNULL) { + ListInit *LHSl = dynamic_cast<ListInit*>(LHS); + TypedInit *LHSt = dynamic_cast<TypedInit*>(LHS); + if (LHSl == 0 && LHSt == 0) { + TokError("expected list type argument in unary operator"); + return 0; + } + if (LHSt) { + ListRecTy *LType = dynamic_cast<ListRecTy*>(LHSt->getType()); + if (LType == 0) { + TokError("expected list type argumnet in unary operator"); + return 0; + } + } + + if (Code == UnOpInit::CAR + || Code == UnOpInit::CDR) { + if (LHSl && LHSl->getSize() == 0) { + TokError("empty list argument in unary operator"); + return 0; + } + if (LHSl) { + Init *Item = LHSl->getElement(0); + TypedInit *Itemt = dynamic_cast<TypedInit*>(Item); + if (Itemt == 0) { + TokError("untyped list element in unary operator"); + return 0; + } + if (Code == UnOpInit::CAR) { + Type = Itemt->getType(); + } + else { + Type = new ListRecTy(Itemt->getType()); + } + } + else { + assert(LHSt && "expected list type argument in unary operator"); + ListRecTy *LType = dynamic_cast<ListRecTy*>(LHSt->getType()); + if (LType == 0) { + TokError("expected list type argumnet in unary operator"); + return 0; + } + if (Code == UnOpInit::CAR) { + Type = LType->getElementType(); + } + else { + Type = LType; + } + } + } + } + + if (Lex.getCode() != tgtok::r_paren) { + TokError("expected ')' in unary operator"); + return 0; + } + Lex.Lex(); // eat the ')' + return (new UnOpInit(Code, LHS, Type))->Fold(CurRec, CurMultiClass); + } + + case tgtok::XConcat: + case tgtok::XSRA: + case tgtok::XSRL: + case tgtok::XSHL: + case tgtok::XStrConcat: + case tgtok::XNameConcat: { // Value ::= !binop '(' Value ',' Value ')' + BinOpInit::BinaryOp Code; + RecTy *Type = 0; + + + switch (Lex.getCode()) { + default: assert(0 && "Unhandled code!"); + case tgtok::XConcat: + Lex.Lex(); // eat the operation + Code = BinOpInit::CONCAT; + Type = new DagRecTy(); + break; + case tgtok::XSRA: + Lex.Lex(); // eat the operation + Code = BinOpInit::SRA; + Type = new IntRecTy(); + break; + case tgtok::XSRL: + Lex.Lex(); // eat the operation + Code = BinOpInit::SRL; + Type = new IntRecTy(); + break; + case tgtok::XSHL: + Lex.Lex(); // eat the operation + Code = BinOpInit::SHL; + Type = new IntRecTy(); + break; + case tgtok::XStrConcat: + Lex.Lex(); // eat the operation + Code = BinOpInit::STRCONCAT; + Type = new StringRecTy(); + break; + case tgtok::XNameConcat: + Lex.Lex(); // eat the operation + Code = BinOpInit::NAMECONCAT; + + Type = ParseOperatorType(); + + if (Type == 0) { + TokError("did not get type for binary operator"); + return 0; + } + + break; + } + if (Lex.getCode() != tgtok::l_paren) { + TokError("expected '(' after binary operator"); + return 0; + } + Lex.Lex(); // eat the '(' + + Init *LHS = ParseValue(CurRec); + if (LHS == 0) return 0; + + if (Lex.getCode() != tgtok::comma) { + TokError("expected ',' in binary operator"); + return 0; + } + Lex.Lex(); // eat the ',' + + Init *RHS = ParseValue(CurRec); + if (RHS == 0) return 0; + + if (Lex.getCode() != tgtok::r_paren) { + TokError("expected ')' in binary operator"); + return 0; + } + Lex.Lex(); // eat the ')' + return (new BinOpInit(Code, LHS, RHS, Type))->Fold(CurRec, CurMultiClass); + } + + case tgtok::XIf: + case tgtok::XForEach: + case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')' + TernOpInit::TernaryOp Code; + RecTy *Type = 0; + + + tgtok::TokKind LexCode = Lex.getCode(); + Lex.Lex(); // eat the operation + switch (LexCode) { + default: assert(0 && "Unhandled code!"); + case tgtok::XIf: + Code = TernOpInit::IF; + break; + case tgtok::XForEach: + Code = TernOpInit::FOREACH; + break; + case tgtok::XSubst: + Code = TernOpInit::SUBST; + break; + } + if (Lex.getCode() != tgtok::l_paren) { + TokError("expected '(' after ternary operator"); + return 0; + } + Lex.Lex(); // eat the '(' + + Init *LHS = ParseValue(CurRec); + if (LHS == 0) return 0; + + if (Lex.getCode() != tgtok::comma) { + TokError("expected ',' in ternary operator"); + return 0; + } + Lex.Lex(); // eat the ',' + + Init *MHS = ParseValue(CurRec); + if (MHS == 0) return 0; + + if (Lex.getCode() != tgtok::comma) { + TokError("expected ',' in ternary operator"); + return 0; + } + Lex.Lex(); // eat the ',' + + Init *RHS = ParseValue(CurRec); + if (RHS == 0) return 0; + + if (Lex.getCode() != tgtok::r_paren) { + TokError("expected ')' in binary operator"); + return 0; + } + Lex.Lex(); // eat the ')' + + switch (LexCode) { + default: assert(0 && "Unhandled code!"); + case tgtok::XIf: { + TypedInit *MHSt = dynamic_cast<TypedInit *>(MHS); + TypedInit *RHSt = dynamic_cast<TypedInit *>(RHS); + if (MHSt == 0 || RHSt == 0) { + TokError("could not get type for !if"); + return 0; + } + if (MHSt->getType()->typeIsConvertibleTo(RHSt->getType())) { + Type = RHSt->getType(); + } + else if (RHSt->getType()->typeIsConvertibleTo(MHSt->getType())) { + Type = MHSt->getType(); + } + else { + TokError("inconsistent types for !if"); + return 0; + } + break; + } + case tgtok::XForEach: { + TypedInit *MHSt = dynamic_cast<TypedInit *>(MHS); + if (MHSt == 0) { + TokError("could not get type for !foreach"); + return 0; + } + Type = MHSt->getType(); + break; + } + case tgtok::XSubst: { + TypedInit *RHSt = dynamic_cast<TypedInit *>(RHS); + if (RHSt == 0) { + TokError("could not get type for !subst"); + return 0; + } + Type = RHSt->getType(); + break; + } + } + return (new TernOpInit(Code, LHS, MHS, RHS, Type))->Fold(CurRec, CurMultiClass); + } + } + TokError("could not parse operation"); + return 0; +} + +/// ParseOperatorType - Parse a type for an operator. This returns +/// null on error. +/// +/// OperatorType ::= '<' Type '>' +/// +RecTy *TGParser::ParseOperatorType(void) { + RecTy *Type = 0; + + if (Lex.getCode() != tgtok::less) { + TokError("expected type name for operator"); + return 0; + } + Lex.Lex(); // eat the < + + Type = ParseType(); + + if (Type == 0) { + TokError("expected type name for operator"); + return 0; + } + + if (Lex.getCode() != tgtok::greater) { + TokError("expected type name for operator"); + return 0; + } + Lex.Lex(); // eat the > + + return Type; +} + + +/// ParseSimpleValue - Parse a tblgen value. This returns null on error. +/// +/// SimpleValue ::= IDValue +/// SimpleValue ::= INTVAL +/// SimpleValue ::= STRVAL+ +/// SimpleValue ::= CODEFRAGMENT +/// SimpleValue ::= '?' +/// SimpleValue ::= '{' ValueList '}' +/// SimpleValue ::= ID '<' ValueListNE '>' +/// SimpleValue ::= '[' ValueList ']' +/// SimpleValue ::= '(' IDValue DagArgList ')' +/// SimpleValue ::= CONCATTOK '(' Value ',' Value ')' +/// SimpleValue ::= SHLTOK '(' Value ',' Value ')' +/// SimpleValue ::= SRATOK '(' Value ',' Value ')' +/// SimpleValue ::= SRLTOK '(' Value ',' Value ')' +/// SimpleValue ::= STRCONCATTOK '(' Value ',' Value ')' +/// +Init *TGParser::ParseSimpleValue(Record *CurRec) { + Init *R = 0; + switch (Lex.getCode()) { + default: TokError("Unknown token when parsing a value"); break; + case tgtok::IntVal: R = new IntInit(Lex.getCurIntVal()); Lex.Lex(); break; + case tgtok::StrVal: { + std::string Val = Lex.getCurStrVal(); + Lex.Lex(); + + // Handle multiple consecutive concatenated strings. + while (Lex.getCode() == tgtok::StrVal) { + Val += Lex.getCurStrVal(); + Lex.Lex(); + } + + R = new StringInit(Val); + break; + } + case tgtok::CodeFragment: + R = new CodeInit(Lex.getCurStrVal()); Lex.Lex(); break; + case tgtok::question: R = new UnsetInit(); Lex.Lex(); break; + case tgtok::Id: { + TGLoc NameLoc = Lex.getLoc(); + std::string Name = Lex.getCurStrVal(); + if (Lex.Lex() != tgtok::less) // consume the Id. + return ParseIDValue(CurRec, Name, NameLoc); // Value ::= IDValue + + // Value ::= ID '<' ValueListNE '>' + if (Lex.Lex() == tgtok::greater) { + TokError("expected non-empty value list"); + return 0; + } + std::vector<Init*> ValueList = ParseValueList(CurRec); + if (ValueList.empty()) return 0; + + if (Lex.getCode() != tgtok::greater) { + TokError("expected '>' at end of value list"); + return 0; + } + Lex.Lex(); // eat the '>' + + // This is a CLASS<initvalslist> expression. This is supposed to synthesize + // a new anonymous definition, deriving from CLASS<initvalslist> with no + // body. + Record *Class = Records.getClass(Name); + if (!Class) { + Error(NameLoc, "Expected a class name, got '" + Name + "'"); + return 0; + } + + // Create the new record, set it as CurRec temporarily. + static unsigned AnonCounter = 0; + Record *NewRec = new Record("anonymous.val."+utostr(AnonCounter++),NameLoc); + SubClassReference SCRef; + SCRef.RefLoc = NameLoc; + SCRef.Rec = Class; + SCRef.TemplateArgs = ValueList; + // Add info about the subclass to NewRec. + if (AddSubClass(NewRec, SCRef)) + return 0; + NewRec->resolveReferences(); + Records.addDef(NewRec); + + // The result of the expression is a reference to the new record. + return new DefInit(NewRec); + } + case tgtok::l_brace: { // Value ::= '{' ValueList '}' + TGLoc BraceLoc = Lex.getLoc(); + Lex.Lex(); // eat the '{' + std::vector<Init*> Vals; + + if (Lex.getCode() != tgtok::r_brace) { + Vals = ParseValueList(CurRec); + if (Vals.empty()) return 0; + } + if (Lex.getCode() != tgtok::r_brace) { + TokError("expected '}' at end of bit list value"); + return 0; + } + Lex.Lex(); // eat the '}' + + BitsInit *Result = new BitsInit(Vals.size()); + for (unsigned i = 0, e = Vals.size(); i != e; ++i) { + Init *Bit = Vals[i]->convertInitializerTo(new BitRecTy()); + if (Bit == 0) { + Error(BraceLoc, "Element #" + utostr(i) + " (" + Vals[i]->getAsString()+ + ") is not convertable to a bit"); + return 0; + } + Result->setBit(Vals.size()-i-1, Bit); + } + return Result; + } + case tgtok::l_square: { // Value ::= '[' ValueList ']' + Lex.Lex(); // eat the '[' + std::vector<Init*> Vals; + + if (Lex.getCode() != tgtok::r_square) { + Vals = ParseValueList(CurRec); + if (Vals.empty()) return 0; + } + if (Lex.getCode() != tgtok::r_square) { + TokError("expected ']' at end of list value"); + return 0; + } + Lex.Lex(); // eat the ']' + return new ListInit(Vals); + } + case tgtok::l_paren: { // Value ::= '(' IDValue DagArgList ')' + Lex.Lex(); // eat the '(' + if (Lex.getCode() != tgtok::Id + && Lex.getCode() != tgtok::XCast + && Lex.getCode() != tgtok::XNameConcat) { + TokError("expected identifier in dag init"); + return 0; + } + + Init *Operator = 0; + if (Lex.getCode() == tgtok::Id) { + Operator = ParseIDValue(CurRec); + if (Operator == 0) return 0; + } + else { + Operator = ParseOperation(CurRec); + if (Operator == 0) return 0; + } + + // If the operator name is present, parse it. + std::string OperatorName; + if (Lex.getCode() == tgtok::colon) { + if (Lex.Lex() != tgtok::VarName) { // eat the ':' + TokError("expected variable name in dag operator"); + return 0; + } + OperatorName = Lex.getCurStrVal(); + Lex.Lex(); // eat the VarName. + } + + std::vector<std::pair<llvm::Init*, std::string> > DagArgs; + if (Lex.getCode() != tgtok::r_paren) { + DagArgs = ParseDagArgList(CurRec); + if (DagArgs.empty()) return 0; + } + + if (Lex.getCode() != tgtok::r_paren) { + TokError("expected ')' in dag init"); + return 0; + } + Lex.Lex(); // eat the ')' + + return new DagInit(Operator, OperatorName, DagArgs); + break; + } + + case tgtok::XCar: + case tgtok::XCdr: + case tgtok::XNull: + case tgtok::XCast: // Value ::= !unop '(' Value ')' + case tgtok::XConcat: + case tgtok::XSRA: + case tgtok::XSRL: + case tgtok::XSHL: + case tgtok::XStrConcat: + case tgtok::XNameConcat: // Value ::= !binop '(' Value ',' Value ')' + case tgtok::XIf: + case tgtok::XForEach: + case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')' + return ParseOperation(CurRec); + break; + } + } + + return R; +} + +/// ParseValue - Parse a tblgen value. This returns null on error. +/// +/// Value ::= SimpleValue ValueSuffix* +/// ValueSuffix ::= '{' BitList '}' +/// ValueSuffix ::= '[' BitList ']' +/// ValueSuffix ::= '.' ID +/// +Init *TGParser::ParseValue(Record *CurRec) { + Init *Result = ParseSimpleValue(CurRec); + if (Result == 0) return 0; + + // Parse the suffixes now if present. + while (1) { + switch (Lex.getCode()) { + default: return Result; + case tgtok::l_brace: { + TGLoc CurlyLoc = Lex.getLoc(); + Lex.Lex(); // eat the '{' + std::vector<unsigned> Ranges = ParseRangeList(); + if (Ranges.empty()) return 0; + + // Reverse the bitlist. + std::reverse(Ranges.begin(), Ranges.end()); + Result = Result->convertInitializerBitRange(Ranges); + if (Result == 0) { + Error(CurlyLoc, "Invalid bit range for value"); + return 0; + } + + // Eat the '}'. + if (Lex.getCode() != tgtok::r_brace) { + TokError("expected '}' at end of bit range list"); + return 0; + } + Lex.Lex(); + break; + } + case tgtok::l_square: { + TGLoc SquareLoc = Lex.getLoc(); + Lex.Lex(); // eat the '[' + std::vector<unsigned> Ranges = ParseRangeList(); + if (Ranges.empty()) return 0; + + Result = Result->convertInitListSlice(Ranges); + if (Result == 0) { + Error(SquareLoc, "Invalid range for list slice"); + return 0; + } + + // Eat the ']'. + if (Lex.getCode() != tgtok::r_square) { + TokError("expected ']' at end of list slice"); + return 0; + } + Lex.Lex(); + break; + } + case tgtok::period: + if (Lex.Lex() != tgtok::Id) { // eat the . + TokError("expected field identifier after '.'"); + return 0; + } + if (!Result->getFieldType(Lex.getCurStrVal())) { + TokError("Cannot access field '" + Lex.getCurStrVal() + "' of value '" + + Result->getAsString() + "'"); + return 0; + } + Result = new FieldInit(Result, Lex.getCurStrVal()); + Lex.Lex(); // eat field name + break; + } + } +} + +/// ParseDagArgList - Parse the argument list for a dag literal expression. +/// +/// ParseDagArgList ::= Value (':' VARNAME)? +/// ParseDagArgList ::= ParseDagArgList ',' Value (':' VARNAME)? +std::vector<std::pair<llvm::Init*, std::string> > +TGParser::ParseDagArgList(Record *CurRec) { + std::vector<std::pair<llvm::Init*, std::string> > Result; + + while (1) { + Init *Val = ParseValue(CurRec); + if (Val == 0) return std::vector<std::pair<llvm::Init*, std::string> >(); + + // If the variable name is present, add it. + std::string VarName; + if (Lex.getCode() == tgtok::colon) { + if (Lex.Lex() != tgtok::VarName) { // eat the ':' + TokError("expected variable name in dag literal"); + return std::vector<std::pair<llvm::Init*, std::string> >(); + } + VarName = Lex.getCurStrVal(); + Lex.Lex(); // eat the VarName. + } + + Result.push_back(std::make_pair(Val, VarName)); + + if (Lex.getCode() != tgtok::comma) break; + Lex.Lex(); // eat the ',' + } + + return Result; +} + + +/// ParseValueList - Parse a comma separated list of values, returning them as a +/// vector. Note that this always expects to be able to parse at least one +/// value. It returns an empty list if this is not possible. +/// +/// ValueList ::= Value (',' Value) +/// +std::vector<Init*> TGParser::ParseValueList(Record *CurRec) { + std::vector<Init*> Result; + Result.push_back(ParseValue(CurRec)); + if (Result.back() == 0) return std::vector<Init*>(); + + while (Lex.getCode() == tgtok::comma) { + Lex.Lex(); // Eat the comma + + Result.push_back(ParseValue(CurRec)); + if (Result.back() == 0) return std::vector<Init*>(); + } + + return Result; +} + + + +/// ParseDeclaration - Read a declaration, returning the name of field ID, or an +/// empty string on error. This can happen in a number of different context's, +/// including within a def or in the template args for a def (which which case +/// CurRec will be non-null) and within the template args for a multiclass (in +/// which case CurRec will be null, but CurMultiClass will be set). This can +/// also happen within a def that is within a multiclass, which will set both +/// CurRec and CurMultiClass. +/// +/// Declaration ::= FIELD? Type ID ('=' Value)? +/// +std::string TGParser::ParseDeclaration(Record *CurRec, + bool ParsingTemplateArgs) { + // Read the field prefix if present. + bool HasField = Lex.getCode() == tgtok::Field; + if (HasField) Lex.Lex(); + + RecTy *Type = ParseType(); + if (Type == 0) return ""; + + if (Lex.getCode() != tgtok::Id) { + TokError("Expected identifier in declaration"); + return ""; + } + + TGLoc IdLoc = Lex.getLoc(); + std::string DeclName = Lex.getCurStrVal(); + Lex.Lex(); + + if (ParsingTemplateArgs) { + if (CurRec) { + DeclName = CurRec->getName() + ":" + DeclName; + } else { + assert(CurMultiClass); + } + if (CurMultiClass) + DeclName = CurMultiClass->Rec.getName() + "::" + DeclName; + } + + // Add the value. + if (AddValue(CurRec, IdLoc, RecordVal(DeclName, Type, HasField))) + return ""; + + // If a value is present, parse it. + if (Lex.getCode() == tgtok::equal) { + Lex.Lex(); + TGLoc ValLoc = Lex.getLoc(); + Init *Val = ParseValue(CurRec); + if (Val == 0 || + SetValue(CurRec, ValLoc, DeclName, std::vector<unsigned>(), Val)) + return ""; + } + + return DeclName; +} + +/// ParseTemplateArgList - Read a template argument list, which is a non-empty +/// sequence of template-declarations in <>'s. If CurRec is non-null, these are +/// template args for a def, which may or may not be in a multiclass. If null, +/// these are the template args for a multiclass. +/// +/// TemplateArgList ::= '<' Declaration (',' Declaration)* '>' +/// +bool TGParser::ParseTemplateArgList(Record *CurRec) { + assert(Lex.getCode() == tgtok::less && "Not a template arg list!"); + Lex.Lex(); // eat the '<' + + Record *TheRecToAddTo = CurRec ? CurRec : &CurMultiClass->Rec; + + // Read the first declaration. + std::string TemplArg = ParseDeclaration(CurRec, true/*templateargs*/); + if (TemplArg.empty()) + return true; + + TheRecToAddTo->addTemplateArg(TemplArg); + + while (Lex.getCode() == tgtok::comma) { + Lex.Lex(); // eat the ',' + + // Read the following declarations. + TemplArg = ParseDeclaration(CurRec, true/*templateargs*/); + if (TemplArg.empty()) + return true; + TheRecToAddTo->addTemplateArg(TemplArg); + } + + if (Lex.getCode() != tgtok::greater) + return TokError("expected '>' at end of template argument list"); + Lex.Lex(); // eat the '>'. + return false; +} + + +/// ParseBodyItem - Parse a single item at within the body of a def or class. +/// +/// BodyItem ::= Declaration ';' +/// BodyItem ::= LET ID OptionalBitList '=' Value ';' +bool TGParser::ParseBodyItem(Record *CurRec) { + if (Lex.getCode() != tgtok::Let) { + if (ParseDeclaration(CurRec, false).empty()) + return true; + + if (Lex.getCode() != tgtok::semi) + return TokError("expected ';' after declaration"); + Lex.Lex(); + return false; + } + + // LET ID OptionalRangeList '=' Value ';' + if (Lex.Lex() != tgtok::Id) + return TokError("expected field identifier after let"); + + TGLoc IdLoc = Lex.getLoc(); + std::string FieldName = Lex.getCurStrVal(); + Lex.Lex(); // eat the field name. + + std::vector<unsigned> BitList; + if (ParseOptionalBitList(BitList)) + return true; + std::reverse(BitList.begin(), BitList.end()); + + if (Lex.getCode() != tgtok::equal) + return TokError("expected '=' in let expression"); + Lex.Lex(); // eat the '='. + + Init *Val = ParseValue(CurRec); + if (Val == 0) return true; + + if (Lex.getCode() != tgtok::semi) + return TokError("expected ';' after let expression"); + Lex.Lex(); + + return SetValue(CurRec, IdLoc, FieldName, BitList, Val); +} + +/// ParseBody - Read the body of a class or def. Return true on error, false on +/// success. +/// +/// Body ::= ';' +/// Body ::= '{' BodyList '}' +/// BodyList BodyItem* +/// +bool TGParser::ParseBody(Record *CurRec) { + // If this is a null definition, just eat the semi and return. + if (Lex.getCode() == tgtok::semi) { + Lex.Lex(); + return false; + } + + if (Lex.getCode() != tgtok::l_brace) + return TokError("Expected ';' or '{' to start body"); + // Eat the '{'. + Lex.Lex(); + + while (Lex.getCode() != tgtok::r_brace) + if (ParseBodyItem(CurRec)) + return true; + + // Eat the '}'. + Lex.Lex(); + return false; +} + +/// ParseObjectBody - Parse the body of a def or class. This consists of an +/// optional ClassList followed by a Body. CurRec is the current def or class +/// that is being parsed. +/// +/// ObjectBody ::= BaseClassList Body +/// BaseClassList ::= /*empty*/ +/// BaseClassList ::= ':' BaseClassListNE +/// BaseClassListNE ::= SubClassRef (',' SubClassRef)* +/// +bool TGParser::ParseObjectBody(Record *CurRec) { + // If there is a baseclass list, read it. + if (Lex.getCode() == tgtok::colon) { + Lex.Lex(); + + // Read all of the subclasses. + SubClassReference SubClass = ParseSubClassReference(CurRec, false); + while (1) { + // Check for error. + if (SubClass.Rec == 0) return true; + + // Add it. + if (AddSubClass(CurRec, SubClass)) + return true; + + if (Lex.getCode() != tgtok::comma) break; + Lex.Lex(); // eat ','. + SubClass = ParseSubClassReference(CurRec, false); + } + } + + // Process any variables on the let stack. + for (unsigned i = 0, e = LetStack.size(); i != e; ++i) + for (unsigned j = 0, e = LetStack[i].size(); j != e; ++j) + if (SetValue(CurRec, LetStack[i][j].Loc, LetStack[i][j].Name, + LetStack[i][j].Bits, LetStack[i][j].Value)) + return true; + + return ParseBody(CurRec); +} + + +/// ParseDef - Parse and return a top level or multiclass def, return the record +/// corresponding to it. This returns null on error. +/// +/// DefInst ::= DEF ObjectName ObjectBody +/// +llvm::Record *TGParser::ParseDef(MultiClass *CurMultiClass) { + TGLoc DefLoc = Lex.getLoc(); + assert(Lex.getCode() == tgtok::Def && "Unknown tok"); + Lex.Lex(); // Eat the 'def' token. + + // Parse ObjectName and make a record for it. + Record *CurRec = new Record(ParseObjectName(), DefLoc); + + if (!CurMultiClass) { + // Top-level def definition. + + // Ensure redefinition doesn't happen. + if (Records.getDef(CurRec->getName())) { + Error(DefLoc, "def '" + CurRec->getName() + "' already defined"); + return 0; + } + Records.addDef(CurRec); + } else { + // Otherwise, a def inside a multiclass, add it to the multiclass. + for (unsigned i = 0, e = CurMultiClass->DefPrototypes.size(); i != e; ++i) + if (CurMultiClass->DefPrototypes[i]->getName() == CurRec->getName()) { + Error(DefLoc, "def '" + CurRec->getName() + + "' already defined in this multiclass!"); + return 0; + } + CurMultiClass->DefPrototypes.push_back(CurRec); + } + + if (ParseObjectBody(CurRec)) + return 0; + + if (CurMultiClass == 0) // Def's in multiclasses aren't really defs. + CurRec->resolveReferences(); + + // If ObjectBody has template arguments, it's an error. + assert(CurRec->getTemplateArgs().empty() && "How'd this get template args?"); + return CurRec; +} + + +/// ParseClass - Parse a tblgen class definition. +/// +/// ClassInst ::= CLASS ID TemplateArgList? ObjectBody +/// +bool TGParser::ParseClass() { + assert(Lex.getCode() == tgtok::Class && "Unexpected token!"); + Lex.Lex(); + + if (Lex.getCode() != tgtok::Id) + return TokError("expected class name after 'class' keyword"); + + Record *CurRec = Records.getClass(Lex.getCurStrVal()); + if (CurRec) { + // If the body was previously defined, this is an error. + if (!CurRec->getValues().empty() || + !CurRec->getSuperClasses().empty() || + !CurRec->getTemplateArgs().empty()) + return TokError("Class '" + CurRec->getName() + "' already defined"); + } else { + // If this is the first reference to this class, create and add it. + CurRec = new Record(Lex.getCurStrVal(), Lex.getLoc()); + Records.addClass(CurRec); + } + Lex.Lex(); // eat the name. + + // If there are template args, parse them. + if (Lex.getCode() == tgtok::less) + if (ParseTemplateArgList(CurRec)) + return true; + + // Finally, parse the object body. + return ParseObjectBody(CurRec); +} + +/// ParseLetList - Parse a non-empty list of assignment expressions into a list +/// of LetRecords. +/// +/// LetList ::= LetItem (',' LetItem)* +/// LetItem ::= ID OptionalRangeList '=' Value +/// +std::vector<LetRecord> TGParser::ParseLetList() { + std::vector<LetRecord> Result; + + while (1) { + if (Lex.getCode() != tgtok::Id) { + TokError("expected identifier in let definition"); + return std::vector<LetRecord>(); + } + std::string Name = Lex.getCurStrVal(); + TGLoc NameLoc = Lex.getLoc(); + Lex.Lex(); // Eat the identifier. + + // Check for an optional RangeList. + std::vector<unsigned> Bits; + if (ParseOptionalRangeList(Bits)) + return std::vector<LetRecord>(); + std::reverse(Bits.begin(), Bits.end()); + + if (Lex.getCode() != tgtok::equal) { + TokError("expected '=' in let expression"); + return std::vector<LetRecord>(); + } + Lex.Lex(); // eat the '='. + + Init *Val = ParseValue(0); + if (Val == 0) return std::vector<LetRecord>(); + + // Now that we have everything, add the record. + Result.push_back(LetRecord(Name, Bits, Val, NameLoc)); + + if (Lex.getCode() != tgtok::comma) + return Result; + Lex.Lex(); // eat the comma. + } +} + +/// ParseTopLevelLet - Parse a 'let' at top level. This can be a couple of +/// different related productions. +/// +/// Object ::= LET LetList IN '{' ObjectList '}' +/// Object ::= LET LetList IN Object +/// +bool TGParser::ParseTopLevelLet() { + assert(Lex.getCode() == tgtok::Let && "Unexpected token"); + Lex.Lex(); + + // Add this entry to the let stack. + std::vector<LetRecord> LetInfo = ParseLetList(); + if (LetInfo.empty()) return true; + LetStack.push_back(LetInfo); + + if (Lex.getCode() != tgtok::In) + return TokError("expected 'in' at end of top-level 'let'"); + Lex.Lex(); + + // If this is a scalar let, just handle it now + if (Lex.getCode() != tgtok::l_brace) { + // LET LetList IN Object + if (ParseObject()) + return true; + } else { // Object ::= LETCommand '{' ObjectList '}' + TGLoc BraceLoc = Lex.getLoc(); + // Otherwise, this is a group let. + Lex.Lex(); // eat the '{'. + + // Parse the object list. + if (ParseObjectList()) + return true; + + if (Lex.getCode() != tgtok::r_brace) { + TokError("expected '}' at end of top level let command"); + return Error(BraceLoc, "to match this '{'"); + } + Lex.Lex(); + } + + // Outside this let scope, this let block is not active. + LetStack.pop_back(); + return false; +} + +/// ParseMultiClassDef - Parse a def in a multiclass context. +/// +/// MultiClassDef ::= DefInst +/// +bool TGParser::ParseMultiClassDef(MultiClass *CurMC) { + if (Lex.getCode() != tgtok::Def) + return TokError("expected 'def' in multiclass body"); + + Record *D = ParseDef(CurMC); + if (D == 0) return true; + + // Copy the template arguments for the multiclass into the def. + const std::vector<std::string> &TArgs = CurMC->Rec.getTemplateArgs(); + + for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { + const RecordVal *RV = CurMC->Rec.getValue(TArgs[i]); + assert(RV && "Template arg doesn't exist?"); + D->addValue(*RV); + } + + return false; +} + +/// ParseMultiClass - Parse a multiclass definition. +/// +/// MultiClassInst ::= MULTICLASS ID TemplateArgList? +/// ':' BaseMultiClassList '{' MultiClassDef+ '}' +/// +bool TGParser::ParseMultiClass() { + assert(Lex.getCode() == tgtok::MultiClass && "Unexpected token"); + Lex.Lex(); // Eat the multiclass token. + + if (Lex.getCode() != tgtok::Id) + return TokError("expected identifier after multiclass for name"); + std::string Name = Lex.getCurStrVal(); + + if (MultiClasses.count(Name)) + return TokError("multiclass '" + Name + "' already defined"); + + CurMultiClass = MultiClasses[Name] = new MultiClass(Name, Lex.getLoc()); + Lex.Lex(); // Eat the identifier. + + // If there are template args, parse them. + if (Lex.getCode() == tgtok::less) + if (ParseTemplateArgList(0)) + return true; + + bool inherits = false; + + // If there are submulticlasses, parse them. + if (Lex.getCode() == tgtok::colon) { + inherits = true; + + Lex.Lex(); + + // Read all of the submulticlasses. + SubMultiClassReference SubMultiClass = + ParseSubMultiClassReference(CurMultiClass); + while (1) { + // Check for error. + if (SubMultiClass.MC == 0) return true; + + // Add it. + if (AddSubMultiClass(CurMultiClass, SubMultiClass)) + return true; + + if (Lex.getCode() != tgtok::comma) break; + Lex.Lex(); // eat ','. + SubMultiClass = ParseSubMultiClassReference(CurMultiClass); + } + } + + if (Lex.getCode() != tgtok::l_brace) { + if (!inherits) + return TokError("expected '{' in multiclass definition"); + else + if (Lex.getCode() != tgtok::semi) + return TokError("expected ';' in multiclass definition"); + else + Lex.Lex(); // eat the ';'. + } + else { + if (Lex.Lex() == tgtok::r_brace) // eat the '{'. + return TokError("multiclass must contain at least one def"); + + while (Lex.getCode() != tgtok::r_brace) + if (ParseMultiClassDef(CurMultiClass)) + return true; + + Lex.Lex(); // eat the '}'. + } + + CurMultiClass = 0; + return false; +} + +/// ParseDefm - Parse the instantiation of a multiclass. +/// +/// DefMInst ::= DEFM ID ':' DefmSubClassRef ';' +/// +bool TGParser::ParseDefm() { + assert(Lex.getCode() == tgtok::Defm && "Unexpected token!"); + if (Lex.Lex() != tgtok::Id) // eat the defm. + return TokError("expected identifier after defm"); + + TGLoc DefmPrefixLoc = Lex.getLoc(); + std::string DefmPrefix = Lex.getCurStrVal(); + if (Lex.Lex() != tgtok::colon) + return TokError("expected ':' after defm identifier"); + + // eat the colon. + Lex.Lex(); + + TGLoc SubClassLoc = Lex.getLoc(); + SubClassReference Ref = ParseSubClassReference(0, true); + + while (1) { + if (Ref.Rec == 0) return true; + + // To instantiate a multiclass, we need to first get the multiclass, then + // instantiate each def contained in the multiclass with the SubClassRef + // template parameters. + MultiClass *MC = MultiClasses[Ref.Rec->getName()]; + assert(MC && "Didn't lookup multiclass correctly?"); + std::vector<Init*> &TemplateVals = Ref.TemplateArgs; + + // Verify that the correct number of template arguments were specified. + const std::vector<std::string> &TArgs = MC->Rec.getTemplateArgs(); + if (TArgs.size() < TemplateVals.size()) + return Error(SubClassLoc, + "more template args specified than multiclass expects"); + + // Loop over all the def's in the multiclass, instantiating each one. + for (unsigned i = 0, e = MC->DefPrototypes.size(); i != e; ++i) { + Record *DefProto = MC->DefPrototypes[i]; + + // Add in the defm name + std::string DefName = DefProto->getName(); + std::string::size_type idx = DefName.find("#NAME#"); + if (idx != std::string::npos) { + DefName.replace(idx, 6, DefmPrefix); + } + else { + // Add the suffix to the defm name to get the new name. + DefName = DefmPrefix + DefName; + } + + Record *CurRec = new Record(DefName, DefmPrefixLoc); + + SubClassReference Ref; + Ref.RefLoc = DefmPrefixLoc; + Ref.Rec = DefProto; + AddSubClass(CurRec, Ref); + + // Loop over all of the template arguments, setting them to the specified + // value or leaving them as the default if necessary. + for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { + // Check if a value is specified for this temp-arg. + if (i < TemplateVals.size()) { + // Set it now. + if (SetValue(CurRec, DefmPrefixLoc, TArgs[i], std::vector<unsigned>(), + TemplateVals[i])) + return true; + + // Resolve it next. + CurRec->resolveReferencesTo(CurRec->getValue(TArgs[i])); + + // Now remove it. + CurRec->removeValue(TArgs[i]); + + } else if (!CurRec->getValue(TArgs[i])->getValue()->isComplete()) { + return Error(SubClassLoc, + "value not specified for template argument #"+ + utostr(i) + " (" + TArgs[i] + ") of multiclassclass '" + + MC->Rec.getName() + "'"); + } + } + + // If the mdef is inside a 'let' expression, add to each def. + for (unsigned i = 0, e = LetStack.size(); i != e; ++i) + for (unsigned j = 0, e = LetStack[i].size(); j != e; ++j) + if (SetValue(CurRec, LetStack[i][j].Loc, LetStack[i][j].Name, + LetStack[i][j].Bits, LetStack[i][j].Value)) { + Error(DefmPrefixLoc, "when instantiating this defm"); + return true; + } + + // Ensure redefinition doesn't happen. + if (Records.getDef(CurRec->getName())) + return Error(DefmPrefixLoc, "def '" + CurRec->getName() + + "' already defined, instantiating defm with subdef '" + + DefProto->getName() + "'"); + Records.addDef(CurRec); + CurRec->resolveReferences(); + } + + if (Lex.getCode() != tgtok::comma) break; + Lex.Lex(); // eat ','. + + SubClassLoc = Lex.getLoc(); + Ref = ParseSubClassReference(0, true); + } + + if (Lex.getCode() != tgtok::semi) + return TokError("expected ';' at end of defm"); + Lex.Lex(); + + return false; +} + +/// ParseObject +/// Object ::= ClassInst +/// Object ::= DefInst +/// Object ::= MultiClassInst +/// Object ::= DefMInst +/// Object ::= LETCommand '{' ObjectList '}' +/// Object ::= LETCommand Object +bool TGParser::ParseObject() { + switch (Lex.getCode()) { + default: assert(0 && "This is not an object"); + case tgtok::Let: return ParseTopLevelLet(); + case tgtok::Def: return ParseDef(0) == 0; + case tgtok::Defm: return ParseDefm(); + case tgtok::Class: return ParseClass(); + case tgtok::MultiClass: return ParseMultiClass(); + } +} + +/// ParseObjectList +/// ObjectList :== Object* +bool TGParser::ParseObjectList() { + while (isObjectStart(Lex.getCode())) { + if (ParseObject()) + return true; + } + return false; +} + + +bool TGParser::ParseFile() { + Lex.Lex(); // Prime the lexer. + if (ParseObjectList()) return true; + + // If we have unread input at the end of the file, report it. + if (Lex.getCode() == tgtok::Eof) + return false; + + return TokError("Unexpected input at top level"); +} + diff --git a/utils/TableGen/TGParser.h b/utils/TableGen/TGParser.h new file mode 100644 index 0000000000000..f03052eb79919 --- /dev/null +++ b/utils/TableGen/TGParser.h @@ -0,0 +1,115 @@ +//===- TGParser.h - Parser for TableGen Files -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class represents the Parser for tablegen files. +// +//===----------------------------------------------------------------------===// + +#ifndef TGPARSER_H +#define TGPARSER_H + +#include "TGLexer.h" +#include "TGSourceMgr.h" +#include <map> + +namespace llvm { + class Record; + class RecordVal; + struct RecTy; + struct Init; + struct MultiClass; + struct SubClassReference; + struct SubMultiClassReference; + + struct LetRecord { + std::string Name; + std::vector<unsigned> Bits; + Init *Value; + TGLoc Loc; + LetRecord(const std::string &N, const std::vector<unsigned> &B, Init *V, + TGLoc L) + : Name(N), Bits(B), Value(V), Loc(L) { + } + }; + +class TGParser { + TGLexer Lex; + std::vector<std::vector<LetRecord> > LetStack; + std::map<std::string, MultiClass*> MultiClasses; + + /// CurMultiClass - If we are parsing a 'multiclass' definition, this is the + /// current value. + MultiClass *CurMultiClass; +public: + TGParser(TGSourceMgr &SrcMgr) : Lex(SrcMgr), CurMultiClass(0) {} + + void setIncludeDirs(const std::vector<std::string> &D){Lex.setIncludeDirs(D);} + + /// ParseFile - Main entrypoint for parsing a tblgen file. These parser + /// routines return true on error, or false on success. + bool ParseFile(); + + bool Error(TGLoc L, const std::string &Msg) const { + Lex.PrintError(L, Msg); + return true; + } + bool TokError(const std::string &Msg) const { + return Error(Lex.getLoc(), Msg); + } +private: // Semantic analysis methods. + bool AddValue(Record *TheRec, TGLoc Loc, const RecordVal &RV); + bool SetValue(Record *TheRec, TGLoc Loc, const std::string &ValName, + const std::vector<unsigned> &BitList, Init *V); + bool AddSubClass(Record *Rec, SubClassReference &SubClass); + bool AddSubMultiClass(MultiClass *CurMC, + SubMultiClassReference &SubMultiClass); + +private: // Parser methods. + bool ParseObjectList(); + bool ParseObject(); + bool ParseClass(); + bool ParseMultiClass(); + bool ParseMultiClassDef(MultiClass *CurMC); + bool ParseDefm(); + bool ParseTopLevelLet(); + std::vector<LetRecord> ParseLetList(); + + Record *ParseDef(MultiClass *CurMultiClass); + bool ParseObjectBody(Record *CurRec); + bool ParseBody(Record *CurRec); + bool ParseBodyItem(Record *CurRec); + + bool ParseTemplateArgList(Record *CurRec); + std::string ParseDeclaration(Record *CurRec, bool ParsingTemplateArgs); + + SubClassReference ParseSubClassReference(Record *CurRec, bool isDefm); + SubMultiClassReference ParseSubMultiClassReference(MultiClass *CurMC); + + Init *ParseIDValue(Record *CurRec); + Init *ParseIDValue(Record *CurRec, const std::string &Name, TGLoc NameLoc); + Init *ParseSimpleValue(Record *CurRec); + Init *ParseValue(Record *CurRec); + std::vector<Init*> ParseValueList(Record *CurRec); + std::vector<std::pair<llvm::Init*, std::string> > ParseDagArgList(Record *); + bool ParseOptionalRangeList(std::vector<unsigned> &Ranges); + bool ParseOptionalBitList(std::vector<unsigned> &Ranges); + std::vector<unsigned> ParseRangeList(); + bool ParseRangePiece(std::vector<unsigned> &Ranges); + RecTy *ParseType(); + Init *ParseOperation(Record *CurRec); + RecTy *ParseOperatorType(); + std::string ParseObjectName(); + Record *ParseClassID(); + MultiClass *ParseMultiClassID(); + Record *ParseDefmID(); +}; + +} // end namespace llvm + +#endif diff --git a/utils/TableGen/TGSourceMgr.cpp b/utils/TableGen/TGSourceMgr.cpp new file mode 100644 index 0000000000000..42bc75246c9f8 --- /dev/null +++ b/utils/TableGen/TGSourceMgr.cpp @@ -0,0 +1,105 @@ +//===- TGSourceMgr.cpp - Manager for Source Buffers & Diagnostics ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the TGSourceMgr class. +// +//===----------------------------------------------------------------------===// + +#include "TGSourceMgr.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +TGSourceMgr::~TGSourceMgr() { + while (!Buffers.empty()) { + delete Buffers.back().Buffer; + Buffers.pop_back(); + } +} + +/// FindBufferContainingLoc - Return the ID of the buffer containing the +/// specified location, returning -1 if not found. +int TGSourceMgr::FindBufferContainingLoc(TGLoc Loc) const { + for (unsigned i = 0, e = Buffers.size(); i != e; ++i) + if (Loc.getPointer() >= Buffers[i].Buffer->getBufferStart() && + // Use <= here so that a pointer to the null at the end of the buffer + // is included as part of the buffer. + Loc.getPointer() <= Buffers[i].Buffer->getBufferEnd()) + return i; + return -1; +} + +/// FindLineNumber - Find the line number for the specified location in the +/// specified file. This is not a fast method. +unsigned TGSourceMgr::FindLineNumber(TGLoc Loc, int BufferID) const { + if (BufferID == -1) BufferID = FindBufferContainingLoc(Loc); + assert(BufferID != -1 && "Invalid Location!"); + + MemoryBuffer *Buff = getBufferInfo(BufferID).Buffer; + + // Count the number of \n's between the start of the file and the specified + // location. + unsigned LineNo = 1; + + const char *Ptr = Buff->getBufferStart(); + + for (; TGLoc::getFromPointer(Ptr) != Loc; ++Ptr) + if (*Ptr == '\n') ++LineNo; + return LineNo; +} + +void TGSourceMgr::PrintIncludeStack(TGLoc IncludeLoc) const { + if (IncludeLoc == TGLoc()) return; // Top of stack. + + int CurBuf = FindBufferContainingLoc(IncludeLoc); + assert(CurBuf != -1 && "Invalid or unspecified location!"); + + PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc); + + errs() << "Included from " + << getBufferInfo(CurBuf).Buffer->getBufferIdentifier() + << ":" << FindLineNumber(IncludeLoc, CurBuf) << ":\n"; +} + + +void TGSourceMgr::PrintError(TGLoc ErrorLoc, const std::string &Msg) const { + raw_ostream &OS = errs(); + + // First thing to do: find the current buffer containing the specified + // location. + int CurBuf = FindBufferContainingLoc(ErrorLoc); + assert(CurBuf != -1 && "Invalid or unspecified location!"); + + PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc); + + MemoryBuffer *CurMB = getBufferInfo(CurBuf).Buffer; + + + OS << "Parsing " << CurMB->getBufferIdentifier() << ":" + << FindLineNumber(ErrorLoc, CurBuf) << ": "; + + OS << Msg << "\n"; + + // Scan backward to find the start of the line. + const char *LineStart = ErrorLoc.getPointer(); + while (LineStart != CurMB->getBufferStart() && + LineStart[-1] != '\n' && LineStart[-1] != '\r') + --LineStart; + // Get the end of the line. + const char *LineEnd = ErrorLoc.getPointer(); + while (LineEnd != CurMB->getBufferEnd() && + LineEnd[0] != '\n' && LineEnd[0] != '\r') + ++LineEnd; + // Print out the line. + OS << std::string(LineStart, LineEnd) << "\n"; + // Print out spaces before the caret. + for (const char *Pos = LineStart; Pos != ErrorLoc.getPointer(); ++Pos) + OS << (*Pos == '\t' ? '\t' : ' '); + OS << "^\n"; +} diff --git a/utils/TableGen/TGSourceMgr.h b/utils/TableGen/TGSourceMgr.h new file mode 100644 index 0000000000000..69fb74ca20c6f --- /dev/null +++ b/utils/TableGen/TGSourceMgr.h @@ -0,0 +1,106 @@ +//===- TGSourceMgr.h - Manager for Source Buffers & Diagnostics -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the TGSourceMgr class. +// +//===----------------------------------------------------------------------===// + +#ifndef TGSOURCEMGR_H +#define TGSOURCEMGR_H + +#include <string> +#include <vector> +#include <cassert> + +namespace llvm { + class MemoryBuffer; + class TGSourceMgr; + +class TGLoc { + const char *Ptr; +public: + TGLoc() : Ptr(0) {} + TGLoc(const TGLoc &RHS) : Ptr(RHS.Ptr) {} + + bool operator==(const TGLoc &RHS) const { return RHS.Ptr == Ptr; } + bool operator!=(const TGLoc &RHS) const { return RHS.Ptr != Ptr; } + + const char *getPointer() const { return Ptr; } + + static TGLoc getFromPointer(const char *Ptr) { + TGLoc L; + L.Ptr = Ptr; + return L; + } +}; + +/// TGSourceMgr - This owns the files read by tblgen, handles include stacks, +/// and handles printing of diagnostics. +class TGSourceMgr { + struct SrcBuffer { + /// Buffer - The memory buffer for the file. + MemoryBuffer *Buffer; + + /// IncludeLoc - This is the location of the parent include, or null if at + /// the top level. + TGLoc IncludeLoc; + }; + + /// Buffers - This is all of the buffers that we are reading from. + std::vector<SrcBuffer> Buffers; + + TGSourceMgr(const TGSourceMgr&); // DO NOT IMPLEMENT + void operator=(const TGSourceMgr&); // DO NOT IMPLEMENT +public: + TGSourceMgr() {} + ~TGSourceMgr(); + + const SrcBuffer &getBufferInfo(unsigned i) const { + assert(i < Buffers.size() && "Invalid Buffer ID!"); + return Buffers[i]; + } + + const MemoryBuffer *getMemoryBuffer(unsigned i) const { + assert(i < Buffers.size() && "Invalid Buffer ID!"); + return Buffers[i].Buffer; + } + + TGLoc getParentIncludeLoc(unsigned i) const { + assert(i < Buffers.size() && "Invalid Buffer ID!"); + return Buffers[i].IncludeLoc; + } + + unsigned AddNewSourceBuffer(MemoryBuffer *F, TGLoc IncludeLoc) { + SrcBuffer NB; + NB.Buffer = F; + NB.IncludeLoc = IncludeLoc; + Buffers.push_back(NB); + return Buffers.size()-1; + } + + /// FindBufferContainingLoc - Return the ID of the buffer containing the + /// specified location, returning -1 if not found. + int FindBufferContainingLoc(TGLoc Loc) const; + + /// FindLineNumber - Find the line number for the specified location in the + /// specified file. This is not a fast method. + unsigned FindLineNumber(TGLoc Loc, int BufferID = -1) const; + + + /// PrintError - Emit an error message about the specified location with the + /// specified string. + void PrintError(TGLoc ErrorLoc, const std::string &Msg) const; + +private: + void PrintIncludeStack(TGLoc IncludeLoc) const; +}; + +} // end llvm namespace + +#endif diff --git a/utils/TableGen/TGValueTypes.cpp b/utils/TableGen/TGValueTypes.cpp new file mode 100644 index 0000000000000..8979e13f72baf --- /dev/null +++ b/utils/TableGen/TGValueTypes.cpp @@ -0,0 +1,126 @@ +//===- ValueTypes.cpp - Tablegen extended ValueType implementation --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// The MVT type is used by tablegen as well as in LLVM. In order to handle +// extended types, the MVT type uses support functions that call into +// LLVM's type system code. These aren't accessible in tablegen, so this +// file provides simple replacements. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/Support/Streams.h" +#include <map> +#include <vector> +using namespace llvm; + +namespace llvm { + +class Type { +public: + virtual unsigned getSizeInBits() const = 0; + virtual ~Type() {} +}; + +} + +class ExtendedIntegerType : public Type { + unsigned BitWidth; +public: + explicit ExtendedIntegerType(unsigned bits) + : BitWidth(bits) {} + unsigned getSizeInBits() const { + return getBitWidth(); + } + unsigned getBitWidth() const { + return BitWidth; + } +}; + +class ExtendedVectorType : public Type { + MVT ElementType; + unsigned NumElements; +public: + ExtendedVectorType(MVT elty, unsigned num) + : ElementType(elty), NumElements(num) {} + unsigned getSizeInBits() const { + return getNumElements() * getElementType().getSizeInBits(); + } + MVT getElementType() const { + return ElementType; + } + unsigned getNumElements() const { + return NumElements; + } +}; + +static std::map<unsigned, const Type *> + ExtendedIntegerTypeMap; +static std::map<std::pair<uintptr_t, uintptr_t>, const Type *> + ExtendedVectorTypeMap; + +MVT MVT::getExtendedIntegerVT(unsigned BitWidth) { + const Type *&ET = ExtendedIntegerTypeMap[BitWidth]; + if (!ET) ET = new ExtendedIntegerType(BitWidth); + MVT VT; + VT.LLVMTy = ET; + assert(VT.isExtended() && "Type is not extended!"); + return VT; +} + +MVT MVT::getExtendedVectorVT(MVT VT, unsigned NumElements) { + const Type *&ET = ExtendedVectorTypeMap[std::make_pair(VT.getRawBits(), + NumElements)]; + if (!ET) ET = new ExtendedVectorType(VT, NumElements); + MVT ResultVT; + ResultVT.LLVMTy = ET; + assert(ResultVT.isExtended() && "Type is not extended!"); + return ResultVT; +} + +bool MVT::isExtendedFloatingPoint() const { + assert(isExtended() && "Type is not extended!"); + // Extended floating-point types are not supported yet. + return false; +} + +bool MVT::isExtendedInteger() const { + assert(isExtended() && "Type is not extended!"); + return dynamic_cast<const ExtendedIntegerType *>(LLVMTy) != 0; +} + +bool MVT::isExtendedVector() const { + assert(isExtended() && "Type is not extended!"); + return dynamic_cast<const ExtendedVectorType *>(LLVMTy) != 0; +} + +bool MVT::isExtended64BitVector() const { + assert(isExtended() && "Type is not extended!"); + return isExtendedVector() && getSizeInBits() == 64; +} + +bool MVT::isExtended128BitVector() const { + assert(isExtended() && "Type is not extended!"); + return isExtendedVector() && getSizeInBits() == 128; +} + +MVT MVT::getExtendedVectorElementType() const { + assert(isExtendedVector() && "Type is not an extended vector!"); + return static_cast<const ExtendedVectorType *>(LLVMTy)->getElementType(); +} + +unsigned MVT::getExtendedVectorNumElements() const { + assert(isExtendedVector() && "Type is not an extended vector!"); + return static_cast<const ExtendedVectorType *>(LLVMTy)->getNumElements(); +} + +unsigned MVT::getExtendedSizeInBits() const { + assert(isExtended() && "Type is not extended!"); + return LLVMTy->getSizeInBits(); +} diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp new file mode 100644 index 0000000000000..dbc4d33e816b1 --- /dev/null +++ b/utils/TableGen/TableGen.cpp @@ -0,0 +1,270 @@ +//===- TableGen.cpp - Top-Level TableGen implementation -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// TableGen is a tool which can be used to build up a description of something, +// then invoke one or more "tablegen backends" to emit information about the +// description in some predefined format. In practice, this is used by the LLVM +// code generators to automate generation of a code generator through a +// high-level description of the target. +// +//===----------------------------------------------------------------------===// + +#include "Record.h" +#include "TGParser.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Streams.h" +#include "llvm/System/Signals.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "CallingConvEmitter.h" +#include "CodeEmitterGen.h" +#include "RegisterInfoEmitter.h" +#include "InstrInfoEmitter.h" +#include "InstrEnumEmitter.h" +#include "AsmWriterEmitter.h" +#include "DAGISelEmitter.h" +#include "FastISelEmitter.h" +#include "SubtargetEmitter.h" +#include "IntrinsicEmitter.h" +#include "LLVMCConfigurationEmitter.h" +#include "ClangDiagnosticsEmitter.h" +#include <algorithm> +#include <cstdio> +#include <fstream> +#include <ios> +using namespace llvm; + +enum ActionType { + PrintRecords, + GenEmitter, + GenRegisterEnums, GenRegister, GenRegisterHeader, + GenInstrEnums, GenInstrs, GenAsmWriter, + GenCallingConv, + GenClangDiagsDefs, + GenClangDiagGroups, + GenDAGISel, + GenFastISel, + GenSubtarget, + GenIntrinsic, + GenTgtIntrinsic, + GenLLVMCConf, + PrintEnums +}; + +namespace { + cl::opt<ActionType> + Action(cl::desc("Action to perform:"), + cl::values(clEnumValN(PrintRecords, "print-records", + "Print all records to stdout (default)"), + clEnumValN(GenEmitter, "gen-emitter", + "Generate machine code emitter"), + clEnumValN(GenRegisterEnums, "gen-register-enums", + "Generate enum values for registers"), + clEnumValN(GenRegister, "gen-register-desc", + "Generate a register info description"), + clEnumValN(GenRegisterHeader, "gen-register-desc-header", + "Generate a register info description header"), + clEnumValN(GenInstrEnums, "gen-instr-enums", + "Generate enum values for instructions"), + clEnumValN(GenInstrs, "gen-instr-desc", + "Generate instruction descriptions"), + clEnumValN(GenCallingConv, "gen-callingconv", + "Generate calling convention descriptions"), + clEnumValN(GenAsmWriter, "gen-asm-writer", + "Generate assembly writer"), + clEnumValN(GenDAGISel, "gen-dag-isel", + "Generate a DAG instruction selector"), + clEnumValN(GenFastISel, "gen-fast-isel", + "Generate a \"fast\" instruction selector"), + clEnumValN(GenSubtarget, "gen-subtarget", + "Generate subtarget enumerations"), + clEnumValN(GenIntrinsic, "gen-intrinsic", + "Generate intrinsic information"), + clEnumValN(GenTgtIntrinsic, "gen-tgt-intrinsic", + "Generate target intrinsic information"), + clEnumValN(GenClangDiagsDefs, "gen-clang-diags-defs", + "Generate Clang diagnostics definitions"), + clEnumValN(GenClangDiagGroups, "gen-clang-diag-groups", + "Generate Clang diagnostic groups"), + clEnumValN(GenLLVMCConf, "gen-llvmc", + "Generate LLVMC configuration library"), + clEnumValN(PrintEnums, "print-enums", + "Print enum values for a class"), + clEnumValEnd)); + + cl::opt<std::string> + Class("class", cl::desc("Print Enum list for this class"), + cl::value_desc("class name")); + + cl::opt<std::string> + OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"), + cl::init("-")); + + cl::opt<std::string> + InputFilename(cl::Positional, cl::desc("<input file>"), cl::init("-")); + + cl::list<std::string> + IncludeDirs("I", cl::desc("Directory of include files"), + cl::value_desc("directory"), cl::Prefix); + + cl::opt<std::string> + ClangComponent("clang-component", + cl::desc("Only use warnings from specified component"), + cl::value_desc("component"), cl::Hidden); +} + + +// FIXME: Eliminate globals from tblgen. +RecordKeeper llvm::Records; + +static TGSourceMgr SrcMgr; + +void llvm::PrintError(TGLoc ErrorLoc, const std::string &Msg) { + SrcMgr.PrintError(ErrorLoc, Msg); +} + + + +/// ParseFile - this function begins the parsing of the specified tablegen +/// file. +static bool ParseFile(const std::string &Filename, + const std::vector<std::string> &IncludeDirs, + TGSourceMgr &SrcMgr) { + std::string ErrorStr; + MemoryBuffer *F = MemoryBuffer::getFileOrSTDIN(Filename.c_str(), &ErrorStr); + if (F == 0) { + cerr << "Could not open input file '" + Filename + "': " << ErrorStr <<"\n"; + return true; + } + + // Tell SrcMgr about this buffer, which is what TGParser will pick up. + SrcMgr.AddNewSourceBuffer(F, TGLoc()); + + TGParser Parser(SrcMgr); + + // Record the location of the include directory so that the lexer can find + // it later. + Parser.setIncludeDirs(IncludeDirs); + + return Parser.ParseFile(); +} + +int main(int argc, char **argv) { + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + cl::ParseCommandLineOptions(argc, argv); + + + // Parse the input file. + if (ParseFile(InputFilename, IncludeDirs, SrcMgr)) + return 1; + + std::ostream *Out = cout.stream(); + if (OutputFilename != "-") { + Out = new std::ofstream(OutputFilename.c_str()); + + if (!Out->good()) { + cerr << argv[0] << ": error opening " << OutputFilename << "!\n"; + return 1; + } + + // Make sure the file gets removed if *gasp* tablegen crashes... + sys::RemoveFileOnSignal(sys::Path(OutputFilename)); + } + + try { + switch (Action) { + case PrintRecords: + *Out << Records; // No argument, dump all contents + break; + case GenEmitter: + CodeEmitterGen(Records).run(*Out); + break; + + case GenRegisterEnums: + RegisterInfoEmitter(Records).runEnums(*Out); + break; + case GenRegister: + RegisterInfoEmitter(Records).run(*Out); + break; + case GenRegisterHeader: + RegisterInfoEmitter(Records).runHeader(*Out); + break; + case GenInstrEnums: + InstrEnumEmitter(Records).run(*Out); + break; + case GenInstrs: + InstrInfoEmitter(Records).run(*Out); + break; + case GenCallingConv: + CallingConvEmitter(Records).run(*Out); + break; + case GenAsmWriter: + AsmWriterEmitter(Records).run(*Out); + break; + case GenClangDiagsDefs: + ClangDiagsDefsEmitter(Records, ClangComponent).run(*Out); + break; + case GenClangDiagGroups: + ClangDiagGroupsEmitter(Records).run(*Out); + break; + case GenDAGISel: + DAGISelEmitter(Records).run(*Out); + break; + case GenFastISel: + FastISelEmitter(Records).run(*Out); + break; + case GenSubtarget: + SubtargetEmitter(Records).run(*Out); + break; + case GenIntrinsic: + IntrinsicEmitter(Records).run(*Out); + break; + case GenTgtIntrinsic: + IntrinsicEmitter(Records, true).run(*Out); + break; + case GenLLVMCConf: + LLVMCConfigurationEmitter(Records).run(*Out); + break; + case PrintEnums: + { + std::vector<Record*> Recs = Records.getAllDerivedDefinitions(Class); + for (unsigned i = 0, e = Recs.size(); i != e; ++i) + *Out << Recs[i]->getName() << ", "; + *Out << "\n"; + break; + } + default: + assert(1 && "Invalid Action"); + return 1; + } + + if (Out != cout.stream()) + delete Out; // Close the file + return 0; + + } catch (const TGError &Error) { + cerr << argv[0] << ": error:\n"; + PrintError(Error.getLoc(), Error.getMessage()); + + } catch (const std::string &Error) { + cerr << argv[0] << ": " << Error << "\n"; + } catch (const char *Error) { + cerr << argv[0] << ": " << Error << "\n"; + } catch (...) { + cerr << argv[0] << ": Unknown unexpected exception occurred.\n"; + } + + if (Out != cout.stream()) { + delete Out; // Close the file + std::remove(OutputFilename.c_str()); // Remove the file, it's broken + } + return 1; +} diff --git a/utils/TableGen/TableGenBackend.cpp b/utils/TableGen/TableGenBackend.cpp new file mode 100644 index 0000000000000..87a1b3da11969 --- /dev/null +++ b/utils/TableGen/TableGenBackend.cpp @@ -0,0 +1,25 @@ +//===- TableGenBackend.cpp - Base class for TableGen Backends ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides useful services for TableGen backends... +// +//===----------------------------------------------------------------------===// + +#include "TableGenBackend.h" +#include "Record.h" +using namespace llvm; + +void TableGenBackend::EmitSourceFileHeader(const std::string &Desc, + std::ostream &OS) const { + OS << "//===- TableGen'erated file -------------------------------------*-" + " C++ -*-===//\n//\n// " << Desc << "\n//\n// Automatically generate" + "d file, do not edit!\n//\n//===------------------------------------" + "----------------------------------===//\n\n"; +} + diff --git a/utils/TableGen/TableGenBackend.h b/utils/TableGen/TableGenBackend.h new file mode 100644 index 0000000000000..109bc9f9ae8d0 --- /dev/null +++ b/utils/TableGen/TableGenBackend.h @@ -0,0 +1,43 @@ +//===- TableGenBackend.h - Base class for TableGen Backends -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// The TableGenBackend class is provided as a common interface for all TableGen +// backends. It provides useful services and an standardized interface. +// +//===----------------------------------------------------------------------===// + +#ifndef TABLEGENBACKEND_H +#define TABLEGENBACKEND_H + +#include <string> +#include <iosfwd> + +namespace llvm { + +class Record; +class RecordKeeper; + +struct TableGenBackend { + virtual ~TableGenBackend() {} + + // run - All TableGen backends should implement the run method, which should + // be the main entry point. + virtual void run(std::ostream &OS) = 0; + + +public: // Useful helper routines... + /// EmitSourceFileHeader - Output a LLVM style file header to the specified + /// ostream. + void EmitSourceFileHeader(const std::string &Desc, std::ostream &OS) const; + +}; + +} // End llvm namespace + +#endif |