diff options
Diffstat (limited to 'llvm/utils/TableGen')
| -rw-r--r-- | llvm/utils/TableGen/CodeEmitterGen.cpp | 217 | ||||
| -rw-r--r-- | llvm/utils/TableGen/CodeEmitterGen.h | 24 | ||||
| -rw-r--r-- | llvm/utils/TableGen/CodeGenWrappers.cpp | 89 | ||||
| -rw-r--r-- | llvm/utils/TableGen/CodeGenWrappers.h | 56 | ||||
| -rw-r--r-- | llvm/utils/TableGen/FileLexer.l | 222 | ||||
| -rw-r--r-- | llvm/utils/TableGen/FileParser.y | 510 | ||||
| -rw-r--r-- | llvm/utils/TableGen/InstrInfoEmitter.cpp | 160 | ||||
| -rw-r--r-- | llvm/utils/TableGen/InstrInfoEmitter.h | 34 | ||||
| -rw-r--r-- | llvm/utils/TableGen/InstrSelectorEmitter.cpp | 1287 | ||||
| -rw-r--r-- | llvm/utils/TableGen/InstrSelectorEmitter.h | 387 | ||||
| -rw-r--r-- | llvm/utils/TableGen/Makefile | 18 | ||||
| -rw-r--r-- | llvm/utils/TableGen/Record.cpp | 676 | ||||
| -rw-r--r-- | llvm/utils/TableGen/Record.h | 849 | ||||
| -rw-r--r-- | llvm/utils/TableGen/RegisterInfoEmitter.cpp | 234 | ||||
| -rw-r--r-- | llvm/utils/TableGen/RegisterInfoEmitter.h | 29 | ||||
| -rw-r--r-- | llvm/utils/TableGen/TableGen.cpp | 482 | ||||
| -rw-r--r-- | llvm/utils/TableGen/TableGenBackend.cpp | 27 | ||||
| -rw-r--r-- | llvm/utils/TableGen/TableGenBackend.h | 34 |
18 files changed, 5335 insertions, 0 deletions
diff --git a/llvm/utils/TableGen/CodeEmitterGen.cpp b/llvm/utils/TableGen/CodeEmitterGen.cpp new file mode 100644 index 00000000000..98976c73363 --- /dev/null +++ b/llvm/utils/TableGen/CodeEmitterGen.cpp @@ -0,0 +1,217 @@ +//===- CodeEmitterGen.cpp - Code Emitter Generator ------------------------===// +// +// FIXME: Document. +// +//===----------------------------------------------------------------------===// + +#include "CodeEmitterGen.h" +#include "Record.h" +#include "Support/Debug.h" + +void CodeEmitterGen::run(std::ostream &o) { + std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction"); + + EmitSourceFileHeader("Machine Code Emitter", o); + + std::string Namespace = "V9::"; + std::string ClassName = "SparcV9CodeEmitter::"; + + //const std::string &Namespace = Inst->getValue("Namespace")->getName(); + o << "unsigned " << ClassName + << "getBinaryCodeForInstr(MachineInstr &MI) {\n" + << " unsigned Value = 0;\n" + << " DEBUG(std::cerr << MI);\n" + << " switch (MI.getOpcode()) {\n"; + for (std::vector<Record*>::iterator I = Insts.begin(), E = Insts.end(); + I != E; ++I) { + Record *R = *I; + o << " case " << Namespace << R->getName() << ": {\n" + << " DEBUG(std::cerr << \"Emitting " << R->getName() << "\\n\");\n"; + + BitsInit *BI = R->getValueAsBitsInit("Inst"); + + unsigned Value = 0; + const std::vector<RecordVal> &Vals = R->getValues(); + + DEBUG(o << " // prefilling: "); + // Start by filling in fixed values... + 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); + DEBUG(o << B->getValue()); + } else { + DEBUG(o << "0"); + } + } + DEBUG(o << "\n"); + + DEBUG(o << " // " << *R->getValue("Inst") << "\n"); + o << " Value = " << Value << "U;\n\n"; + + // Loop over all of the fields in the instruction determining which are the + // operands to the instruction. + // + unsigned op = 0; + std::map<std::string, unsigned> OpOrder; + std::map<std::string, bool> OpContinuous; + 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 BitsInit *InstInit = BI; + int beginBitInVar = -1, endBitInVar = -1; + int beginBitInInst = -1, endBitInInst = -1; + bool continuous = true; + + for (int bit = InstInit->getNumBits()-1; bit >= 0; --bit) { + if (VarBitInit *VBI = + dynamic_cast<VarBitInit*>(InstInit->getBit(bit))) { + TypedInit *TI = VBI->getVariable(); + if (VarInit *VI = dynamic_cast<VarInit*>(TI)) { + // only process the current variable + if (VI->getName() != Vals[i].getName()) + continue; + + if (beginBitInVar == -1) + beginBitInVar = VBI->getBitNum(); + + if (endBitInVar == -1) + endBitInVar = VBI->getBitNum(); + else { + if (endBitInVar == (int)VBI->getBitNum() + 1) + endBitInVar = VBI->getBitNum(); + else { + continuous = false; + break; + } + } + + if (beginBitInInst == -1) + beginBitInInst = bit; + if (endBitInInst == -1) + endBitInInst = bit; + else { + if (endBitInInst == bit + 1) + endBitInInst = bit; + else { + continuous = false; + break; + } + } + + // maintain same distance between bits in field and bits in + // instruction. if the relative distances stay the same + // throughout, + if (beginBitInVar - (int)VBI->getBitNum() != + beginBitInInst - bit) { + continuous = false; + break; + } + } + } + } + + // If we have found no bit in "Inst" which comes from this field, then + // this is not an operand!! + if (beginBitInInst != -1) { + o << " // op" << op << ": " << Vals[i].getName() << "\n" + << " int64_t op" << op + <<" = getMachineOpValue(MI, MI.getOperand("<<op<<"));\n"; + //<< " MachineOperand &op" << op <<" = MI.getOperand("<<op<<");\n"; + OpOrder[Vals[i].getName()] = op++; + + DEBUG(o << " // Var: begin = " << beginBitInVar + << ", end = " << endBitInVar + << "; Inst: begin = " << beginBitInInst + << ", end = " << endBitInInst << "\n"); + + if (continuous) { + DEBUG(o << " // continuous: op" << OpOrder[Vals[i].getName()] + << "\n"); + + // Mask off the right bits + // Low mask (ie. shift, if necessary) + assert(endBitInVar >= 0 && "Negative shift amount in masking!"); + if (endBitInVar != 0) { + o << " op" << OpOrder[Vals[i].getName()] + << " >>= " << endBitInVar << ";\n"; + beginBitInVar -= endBitInVar; + endBitInVar = 0; + } + + // High mask + o << " op" << OpOrder[Vals[i].getName()] + << " &= (1<<" << beginBitInVar+1 << ") - 1;\n"; + + // Shift the value to the correct place (according to place in inst) + assert(endBitInInst >= 0 && "Negative shift amount in inst position!"); + if (endBitInInst != 0) + o << " op" << OpOrder[Vals[i].getName()] + << " <<= " << endBitInInst << ";\n"; + + // Just OR in the result + o << " Value |= op" << OpOrder[Vals[i].getName()] << ";\n"; + } + + // otherwise, will be taken care of in the loop below using this + // value: + OpContinuous[Vals[i].getName()] = continuous; + } + } + } + + for (unsigned f = 0, e = Vals.size(); f != e; ++f) { + if (Vals[f].getPrefix()) { + BitsInit *FieldInitializer = (BitsInit*)Vals[f].getValue(); + + // Scan through the field looking for bit initializers of the current + // variable... + for (int i = FieldInitializer->getNumBits()-1; i >= 0; --i) { + if (BitInit *BI = dynamic_cast<BitInit*>(FieldInitializer->getBit(i))) + { + DEBUG(o << " // bit init: f: " << f << ", i: " << i << "\n"); + } else if (UnsetInit *UI = + dynamic_cast<UnsetInit*>(FieldInitializer->getBit(i))) { + DEBUG(o << " // unset init: f: " << f << ", i: " << i << "\n"); + } else if (VarBitInit *VBI = + dynamic_cast<VarBitInit*>(FieldInitializer->getBit(i))) { + TypedInit *TI = VBI->getVariable(); + if (VarInit *VI = dynamic_cast<VarInit*>(TI)) { + // If the bits of the field are laid out consecutively in the + // instruction, then instead of separately ORing in bits, just + // mask and shift the entire field for efficiency. + if (OpContinuous[VI->getName()]) { + // already taken care of in the loop above, thus there is no + // need to individually OR in the bits + + // for debugging, output the regular version anyway, commented + DEBUG(o << " // Value |= getValueBit(op" + << OpOrder[VI->getName()] << ", " << VBI->getBitNum() + << ")" << " << " << i << ";\n"); + } else { + o << " Value |= getValueBit(op" << OpOrder[VI->getName()] + << ", " << VBI->getBitNum() + << ")" << " << " << i << ";\n"; + } + } else if (FieldInit *FI = dynamic_cast<FieldInit*>(TI)) { + // FIXME: implement this! + o << "FIELD INIT not implemented yet!\n"; + } else { + o << "Error: UNIMPLEMENTED\n"; + } + } + } + } + } + + o << " break;\n" + << " }\n"; + } + + o << " default:\n" + << " std::cerr << \"Not supported instr: \" << MI << \"\\n\";\n" + << " abort();\n" + << " }\n" + << " return Value;\n" + << "}\n"; +} diff --git a/llvm/utils/TableGen/CodeEmitterGen.h b/llvm/utils/TableGen/CodeEmitterGen.h new file mode 100644 index 00000000000..4b87da5067e --- /dev/null +++ b/llvm/utils/TableGen/CodeEmitterGen.h @@ -0,0 +1,24 @@ +//===- CodeEmitterGen.h - Code Emitter Generator ----------------*- C++ -*-===// +// +// FIXME: document +// +//===----------------------------------------------------------------------===// + +#ifndef CODEMITTERGEN_H +#define CODEMITTERGEN_H + +#include "TableGenBackend.h" + +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); +}; + +#endif diff --git a/llvm/utils/TableGen/CodeGenWrappers.cpp b/llvm/utils/TableGen/CodeGenWrappers.cpp new file mode 100644 index 00000000000..61c3abc2971 --- /dev/null +++ b/llvm/utils/TableGen/CodeGenWrappers.cpp @@ -0,0 +1,89 @@ +//===- CodeGenWrappers.cpp - Code Generation Class Wrappers -----*- C++ -*-===// +// +// These classes wrap 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 "CodeGenWrappers.h" +#include "Record.h" + +/// getValueType - Return the MCV::ValueType that the specified TableGen record +/// corresponds to. +MVT::ValueType getValueType(Record *Rec) { + return (MVT::ValueType)Rec->getValueAsInt("Value"); +} + +std::string getName(MVT::ValueType T) { + switch (T) { + case MVT::Other: return "UNKNOWN"; + case MVT::i1: return "i1"; + case MVT::i8: return "i8"; + case MVT::i16: return "i16"; + case MVT::i32: return "i32"; + case MVT::i64: return "i64"; + case MVT::i128: return "i128"; + case MVT::f32: return "f32"; + case MVT::f64: return "f64"; + case MVT::f80: return "f80"; + case MVT::f128: return "f128"; + case MVT::isVoid:return "void"; + default: assert(0 && "ILLEGAL VALUE TYPE!"); return ""; + } +} + +std::string getEnumName(MVT::ValueType T) { + switch (T) { + case MVT::Other: return "Other"; + case MVT::i1: return "i1"; + case MVT::i8: return "i8"; + case MVT::i16: return "i16"; + case MVT::i32: return "i32"; + case MVT::i64: return "i64"; + case MVT::i128: return "i128"; + case MVT::f32: return "f32"; + case MVT::f64: return "f64"; + case MVT::f80: return "f80"; + case MVT::f128: return "f128"; + case MVT::isVoid:return "isVoid"; + default: assert(0 && "ILLEGAL VALUE TYPE!"); return ""; + } +} + + +std::ostream &operator<<(std::ostream &OS, MVT::ValueType T) { + return OS << getName(T); +} + + + +/// getTarget - Return the current instance of the Target class. +/// +CodeGenTarget::CodeGenTarget() { + std::vector<Record*> Targets = Records.getAllDerivedDefinitions("Target"); + if (Targets.size() != 1) + throw std::string("ERROR: Multiple subclasses of Target defined!"); + TargetRec = Targets[0]; + + // Read in all of the CalleeSavedRegisters... + ListInit *LI = TargetRec->getValueAsListInit("CalleeSavedRegisters"); + for (unsigned i = 0, e = LI->getSize(); i != e; ++i) + if (DefInit *DI = dynamic_cast<DefInit*>(LI->getElement(i))) + CalleeSavedRegisters.push_back(DI->getDef()); + else + throw "Target: " + TargetRec->getName() + + " expected register definition in CalleeSavedRegisters list!"; + + PointerType = getValueType(TargetRec->getValueAsDef("PointerType")); +} + + +const std::string &CodeGenTarget::getName() const { + return TargetRec->getName(); +} + +Record *CodeGenTarget::getInstructionSet() const { + return TargetRec->getValueAsDef("InstructionSet"); +} diff --git a/llvm/utils/TableGen/CodeGenWrappers.h b/llvm/utils/TableGen/CodeGenWrappers.h new file mode 100644 index 00000000000..00ca3fcc603 --- /dev/null +++ b/llvm/utils/TableGen/CodeGenWrappers.h @@ -0,0 +1,56 @@ +//===- CodeGenWrappers.h - Code Generation Class Wrappers -------*- C++ -*-===// +// +// These classes wrap 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. +// +//===----------------------------------------------------------------------===// + +#ifndef CODEGENWRAPPERS_H +#define CODEGENWRAPPERS_H + +#include "llvm/CodeGen/ValueTypes.h" +#include <iosfwd> +#include <string> +#include <vector> +class Record; +class RecordKeeper; + +/// getValueType - Return the MVT::ValueType that the specified TableGen record +/// corresponds to. +MVT::ValueType getValueType(Record *Rec); + +std::ostream &operator<<(std::ostream &OS, MVT::ValueType T); +std::string getName(MVT::ValueType T); +std::string getEnumName(MVT::ValueType T); + + +/// CodeGenTarget - This class corresponds to the Target class in the .td files. +/// +class CodeGenTarget { + Record *TargetRec; + std::vector<Record*> CalleeSavedRegisters; + MVT::ValueType PointerType; + +public: + CodeGenTarget(); + + Record *getTargetRecord() const { return TargetRec; } + const std::string &getName() const; + + const std::vector<Record*> &getCalleeSavedRegisters() const { + return CalleeSavedRegisters; + } + + MVT::ValueType getPointerType() const { return PointerType; } + + // getInstructionSet - Return the InstructionSet object... + Record *getInstructionSet() const; + + // getInstructionSet - Return the CodeGenInstructionSet object for this + // target, lazily reading it from the record keeper as needed. + // CodeGenInstructionSet *getInstructionSet - +}; + +#endif diff --git a/llvm/utils/TableGen/FileLexer.l b/llvm/utils/TableGen/FileLexer.l new file mode 100644 index 00000000000..64ed4c625a9 --- /dev/null +++ b/llvm/utils/TableGen/FileLexer.l @@ -0,0 +1,222 @@ +/*===-- FileLexer.l - Scanner for TableGen Files ----------------*- C++ -*-===// +// +// This file defines a simple flex scanner for TableGen files. This is pretty +// straight-forward, except for the magic to handle file inclusion. +// +//===----------------------------------------------------------------------===*/ + +%option prefix="File" +%option yylineno +%option nostdinit +%option never-interactive +%option batch +%option nodefault +%option 8bit +%option outfile="Lexer.cpp" +%option ecs +%option noreject +%option noyymore + +%x comment + +%{ +#include "Record.h" +typedef std::pair<Record*, std::vector<Init*>*> SubClassRefTy; +#include "FileParser.h" + +// Global variable recording the location of the include directory +std::string IncludeDirectory; + +// ParseInt - This has to handle the special case of binary numbers 0b0101 +static int ParseInt(const char *Str) { + if (Str[0] == '0' && Str[1] == 'b') + return strtol(Str+2, 0, 2); + return strtol(Str, 0, 0); +} + +static int CommentDepth = 0; + +struct IncludeRec { + std::string Filename; + FILE *File; + unsigned LineNo; + YY_BUFFER_STATE Buffer; + + IncludeRec(const std::string &FN, FILE *F) + : Filename(FN), File(F), LineNo(0){ + } +}; + +static std::vector<IncludeRec> IncludeStack; + + +std::ostream &err() { + if (IncludeStack.empty()) + return std::cerr << "At end of input: "; + + for (unsigned i = 0, e = IncludeStack.size()-1; i != e; ++i) + std::cerr << "Included from " << IncludeStack[i].Filename << ":" + << IncludeStack[i].LineNo << ":\n"; + return std::cerr << "Parsing " << IncludeStack.back().Filename << ":" + << Filelineno << ": "; +} + + +int Fileparse(); + +// +// Function: ParseFile() +// +// Description: +// This function begins the parsing of the specified tablegen file. +// +// Inputs: +// Filename - A string containing the name of the file to parse. +// IncludeDir - A string containing the directory from which include +// files can be found. +// +void ParseFile(const std::string &Filename, const std::string & IncludeDir) { + FILE *F = stdin; + if (Filename != "-") { + F = fopen(Filename.c_str(), "r"); + + if (F == 0) { + std::cerr << "Could not open input file '" + Filename + "'!\n"; + exit (1); + } + IncludeStack.push_back(IncludeRec(Filename, F)); + } else { + IncludeStack.push_back(IncludeRec("<stdin>", stdin)); + } + + // + // Record the location of the include directory so that the lexer can find + // it later. + // + IncludeDirectory = IncludeDir; + + Filein = F; + Filelineno = 1; + Fileparse(); + Filein = stdin; +} + +// HandleInclude - This function is called when an include directive is +// encountered in the input stream... +static void HandleInclude(const char *Buffer) { + unsigned Length = yyleng; + assert(Buffer[Length-1] == '"'); + Buffer += strlen("include "); + Length -= strlen("include "); + while (*Buffer != '"') { + ++Buffer; + --Length; + } + assert(Length >= 2 && "Double quotes not found?"); + std::string Filename(Buffer+1, Buffer+Length-1); + //std::cerr << "Filename = '" << Filename << "'\n"; + + // Save the line number and lex buffer of the includer... + IncludeStack.back().LineNo = Filelineno; + IncludeStack.back().Buffer = YY_CURRENT_BUFFER; + + // Open the new input file... + yyin = fopen(Filename.c_str(), "r"); + if (yyin == 0) { + // + // If we couldn't find the file in the current directory, look for it in + // the include directories. + // + // NOTE: + // Right now, there is only one directory. We need to eventually add + // support for more. + // + Filename = IncludeDirectory + "/" + Filename; + yyin = fopen(Filename.c_str(), "r"); + if (yyin == 0) { + err() << "Could not find include file '" << Filename << "'!\n"; + abort(); + } + } + + // Add the file to our include stack... + IncludeStack.push_back(IncludeRec(Filename, yyin)); + Filelineno = 1; // Reset line numbering... + //yyrestart(yyin); // Start lexing the new file... + + yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); +} + + +// yywrap - This is called when the lexer runs out of input in one of the files. +// Switch back to an includer if an includee has run out of input. +// +extern "C" +int yywrap() { + if (IncludeStack.back().File != stdin) + fclose(IncludeStack.back().File); + IncludeStack.pop_back(); + if (IncludeStack.empty()) return 1; // Top-level file is done. + + // Otherwise, we need to switch back to a file which included the current one. + Filelineno = IncludeStack.back().LineNo; // Restore current line number + yy_switch_to_buffer(IncludeStack.back().Buffer); + return 0; +} + +%} + +Comment \/\/.* + +Identifier [a-zA-Z_][0-9a-zA-Z_]* +Integer [-+]?[0-9]+|0x[0-9a-fA-F]+|0b[01]+ +CodeFragment \[\{([^}]+|\}[^\]])*\}\] +StringVal \"[^"]*\" +IncludeStr include[ \t\n]+\"[^"]*\" + +%% + +{Comment} { /* Ignore comments */ } + +{IncludeStr} { HandleInclude(yytext); } +{CodeFragment} { Filelval.StrVal = new std::string(yytext+2, yytext+yyleng-2); + return CODEFRAGMENT; } + +int { return INT; } +bit { return BIT; } +bits { return BITS; } +string { return STRING; } +list { return LIST; } +code { return CODE; } +dag { return DAG; } + +class { return CLASS; } +def { return DEF; } +field { return FIELD; } +let { return LET; } +in { return IN; } + +{Identifier} { Filelval.StrVal = new std::string(yytext, yytext+yyleng); + return ID; } +${Identifier} { Filelval.StrVal = new std::string(yytext+1, yytext+yyleng); + return VARNAME; } + +{StringVal} { Filelval.StrVal = new std::string(yytext+1, yytext+yyleng-1); + return STRVAL; } + +{Integer} { Filelval.IntVal = ParseInt(Filetext); return INTVAL; } + +[ \t\n]+ { /* Ignore whitespace */ } + + +"/*" { BEGIN(comment); CommentDepth++; } +<comment>[^*/]* /* eat anything that's not a '*' or '/' */ +<comment>"*"+[^*/]* /* eat up '*'s not followed by '/'s */ +<comment>"/*" { ++CommentDepth; } +<comment>"/"+[^*]* /* eat up /'s not followed by *'s */ +<comment>"*"+"/" { if (!--CommentDepth) { BEGIN(INITIAL); } } +<comment><<EOF>> { err() << "Unterminated comment!\n"; abort(); } + +. { return Filetext[0]; } + +%% diff --git a/llvm/utils/TableGen/FileParser.y b/llvm/utils/TableGen/FileParser.y new file mode 100644 index 00000000000..728fcf222c6 --- /dev/null +++ b/llvm/utils/TableGen/FileParser.y @@ -0,0 +1,510 @@ +//===-- FileParser.y - Parser for TableGen files ----------------*- C++ -*-===// +// +// This file implements the bison parser for Table Generator files... +// +//===------------------------------------------------------------------------=// + +%{ +#include "Record.h" +#include "Support/StringExtras.h" +#include <algorithm> +#include <cstdio> +#define YYERROR_VERBOSE 1 + +int yyerror(const char *ErrorMsg); +int yylex(); +extern int Filelineno; +static Record *CurRec = 0; + +typedef std::pair<Record*, std::vector<Init*>*> SubClassRefTy; + +struct LetRecord { + std::string Name; + std::vector<unsigned> Bits; + Init *Value; + bool HasBits; + LetRecord(const std::string &N, std::vector<unsigned> *B, Init *V) + : Name(N), Value(V), HasBits(B != 0) { + if (HasBits) Bits = *B; + } +}; + +static std::vector<std::vector<LetRecord> > LetStack; + + +extern std::ostream &err(); + +static void addValue(const RecordVal &RV) { + if (RecordVal *ERV = CurRec->getValue(RV.getName())) { + // The value already exists in the class, treat this as a set... + if (ERV->setValue(RV.getValue())) { + err() << "New definition of '" << RV.getName() << "' of type '" + << *RV.getType() << "' is incompatible with previous " + << "definition of type '" << *ERV->getType() << "'!\n"; + abort(); + } + } else { + CurRec->addValue(RV); + } +} + +static void addSuperClass(Record *SC) { + if (CurRec->isSubClassOf(SC)) { + err() << "Already subclass of '" << SC->getName() << "'!\n"; + abort(); + } + CurRec->addSuperClass(SC); +} + +static void setValue(const std::string &ValName, + std::vector<unsigned> *BitList, Init *V) { + if (!V) return ; + + RecordVal *RV = CurRec->getValue(ValName); + if (RV == 0) { + err() << "Value '" << ValName << "' unknown!\n"; + abort(); + } + + // 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) { + BitsInit *CurVal = dynamic_cast<BitsInit*>(RV->getValue()); + if (CurVal == 0) { + err() << "Value '" << ValName << "' is not a bits type!\n"; + abort(); + } + + // 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())); + err() << "Initializer '" << *V << "' not compatible with bit range!\n"; + abort(); + } + + // We should have a BitsInit type now... + assert(dynamic_cast<BitsInit*>(BI) != 0 || &(std::cerr << *BI) == 0); + BitsInit *BInit = (BitsInit*)BI; + + 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)) { + err() << "Cannot set bit #" << Bit << " of value '" << ValName + << "' more than once!\n"; + abort(); + } + 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)) { + err() << "Value '" << ValName << "' of type '" << *RV->getType() + << "' is incompatible with initializer '" << *V << "'!\n"; + abort(); + } +} + +static void addSubClass(Record *SC, const std::vector<Init*> &TemplateArgs) { + // 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) + addValue(Vals[i]); + + const std::vector<std::string> &TArgs = SC->getTemplateArgs(); + + // Ensure that an appropriate number of template arguments are specified... + if (TArgs.size() < TemplateArgs.size()) { + err() << "ERROR: More template args specified than expected!\n"; + abort(); + } else { // This class expects template arguments... + // Loop over all of the template arguments, setting them to the specified + // value or leaving them as the default as necessary. + for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { + if (i < TemplateArgs.size()) { // A value is specified for this temp-arg? + // Set it now. + setValue(TArgs[i], 0, TemplateArgs[i]); + } else if (!CurRec->getValue(TArgs[i])->getValue()->isComplete()) { + err() << "ERROR: Value not specified for template argument #" + << i << " (" << TArgs[i] << ") of subclass '" << SC->getName() + << "'!\n"; + abort(); + } + } + } + + + // 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) + addSuperClass(SCs[i]); + addSuperClass(SC); +} + + +%} + +%union { + std::string *StrVal; + int IntVal; + RecTy *Ty; + Init *Initializer; + std::vector<Init*> *FieldList; + std::vector<unsigned>*BitList; + Record *Rec; + SubClassRefTy *SubClassRef; + std::vector<SubClassRefTy> *SubClassList; + std::vector<std::pair<Init*, std::string> > *DagValueList; +}; + +%token INT BIT STRING BITS LIST CODE DAG CLASS DEF FIELD LET IN +%token <IntVal> INTVAL +%token <StrVal> ID VARNAME STRVAL CODEFRAGMENT + +%type <Ty> Type +%type <Rec> ClassInst DefInst Object ObjectBody ClassID + +%type <SubClassRef> SubClassRef +%type <SubClassList> ClassList ClassListNE +%type <IntVal> OptPrefix +%type <Initializer> Value OptValue +%type <DagValueList> DagArgList DagArgListNE +%type <FieldList> ValueList ValueListNE +%type <BitList> BitList OptBitList RBitList +%type <StrVal> Declaration OptID OptVarName + +%start File +%% + +ClassID : ID { + $$ = Records.getClass(*$1); + if ($$ == 0) { + err() << "Couldn't find class '" << *$1 << "'!\n"; + abort(); + } + delete $1; + }; + + +// TableGen types... +Type : STRING { // string type + $$ = new StringRecTy(); + } | BIT { // bit type + $$ = new BitRecTy(); + } | BITS '<' INTVAL '>' { // bits<x> type + $$ = new BitsRecTy($3); + } | INT { // int type + $$ = new IntRecTy(); + } | LIST '<' Type '>' { // list<x> type + $$ = new ListRecTy($3); + } | CODE { // code type + $$ = new CodeRecTy(); + } | DAG { // dag type + $$ = new DagRecTy(); + } | ClassID { // Record Type + $$ = new RecordRecTy($1); + }; + +OptPrefix : /*empty*/ { $$ = 0; } | FIELD { $$ = 1; }; + +OptValue : /*empty*/ { $$ = 0; } | '=' Value { $$ = $2; }; + +Value : INTVAL { + $$ = new IntInit($1); + } | STRVAL { + $$ = new StringInit(*$1); + delete $1; + } | CODEFRAGMENT { + $$ = new CodeInit(*$1); + delete $1; + } | '?' { + $$ = new UnsetInit(); + } | '{' ValueList '}' { + BitsInit *Init = new BitsInit($2->size()); + for (unsigned i = 0, e = $2->size(); i != e; ++i) { + struct Init *Bit = (*$2)[i]->convertInitializerTo(new BitRecTy()); + if (Bit == 0) { + err() << "Element #" << i << " (" << *(*$2)[i] + << ") is not convertable to a bit!\n"; + abort(); + } + Init->setBit($2->size()-i-1, Bit); + } + $$ = Init; + delete $2; + } | ID { + if (const RecordVal *RV = (CurRec ? CurRec->getValue(*$1) : 0)) { + $$ = new VarInit(*$1, RV->getType()); + } else if (Record *D = Records.getDef(*$1)) { + $$ = new DefInit(D); + } else { + err() << "Variable not defined: '" << *$1 << "'!\n"; + abort(); + } + + delete $1; + } | Value '{' BitList '}' { + $$ = $1->convertInitializerBitRange(*$3); + if ($$ == 0) { + err() << "Invalid bit range for value '" << *$1 << "'!\n"; + abort(); + } + delete $3; + } | '[' ValueList ']' { + $$ = new ListInit(*$2); + delete $2; + } | Value '.' ID { + if (!$1->getFieldType(*$3)) { + err() << "Cannot access field '" << *$3 << "' of value '" << *$1 << "!\n"; + abort(); + } + $$ = new FieldInit($1, *$3); + delete $3; + } | '(' ID DagArgList ')' { + Record *D = Records.getDef(*$2); + if (D == 0) { + err() << "Invalid def '" << *$2 << "'!\n"; + abort(); + } + $$ = new DagInit(D, *$3); + delete $2; delete $3; + }; + +OptVarName : /* empty */ { + $$ = new std::string(); + } + | ':' VARNAME { + $$ = $2; + }; + +DagArgListNE : Value OptVarName { + $$ = new std::vector<std::pair<Init*, std::string> >(); + $$->push_back(std::make_pair($1, *$2)); + delete $2; + } + | DagArgListNE ',' Value OptVarName { + $1->push_back(std::make_pair($3, *$4)); + delete $4; + $$ = $1; + }; + +DagArgList : /*empty*/ { + $$ = new std::vector<std::pair<Init*, std::string> >(); + } + | DagArgListNE { $$ = $1; }; + + +RBitList : INTVAL { + $$ = new std::vector<unsigned>(); + $$->push_back($1); + } | INTVAL '-' INTVAL { + if ($1 < $3 || $1 < 0 || $3 < 0) { + err() << "Invalid bit range: " << $1 << "-" << $3 << "!\n"; + abort(); + } + $$ = new std::vector<unsigned>(); + for (int i = $1; i >= $3; --i) + $$->push_back(i); + } | INTVAL INTVAL { + $2 = -$2; + if ($1 < $2 || $1 < 0 || $2 < 0) { + err() << "Invalid bit range: " << $1 << "-" << $2 << "!\n"; + abort(); + } + $$ = new std::vector<unsigned>(); + for (int i = $1; i >= $2; --i) + $$->push_back(i); + } | RBitList ',' INTVAL { + ($$=$1)->push_back($3); + } | RBitList ',' INTVAL '-' INTVAL { + if ($3 < $5 || $3 < 0 || $5 < 0) { + err() << "Invalid bit range: " << $3 << "-" << $5 << "!\n"; + abort(); + } + $$ = $1; + for (int i = $3; i >= $5; --i) + $$->push_back(i); + } | RBitList ',' INTVAL INTVAL { + $4 = -$4; + if ($3 < $4 || $3 < 0 || $4 < 0) { + err() << "Invalid bit range: " << $3 << "-" << $4 << "!\n"; + abort(); + } + $$ = $1; + for (int i = $3; i >= $4; --i) + $$->push_back(i); + }; + +BitList : RBitList { $$ = $1; std::reverse($1->begin(), $1->end()); }; + +OptBitList : /*empty*/ { $$ = 0; } | '{' BitList '}' { $$ = $2; }; + + + +ValueList : /*empty*/ { + $$ = new std::vector<Init*>(); + } | ValueListNE { + $$ = $1; + }; + +ValueListNE : Value { + $$ = new std::vector<Init*>(); + $$->push_back($1); + } | ValueListNE ',' Value { + ($$ = $1)->push_back($3); + }; + +Declaration : OptPrefix Type ID OptValue { + addValue(RecordVal(*$3, $2, $1)); + setValue(*$3, 0, $4); + $$ = $3; +}; + +BodyItem : Declaration ';' { + delete $1; +} | LET ID OptBitList '=' Value ';' { + setValue(*$2, $3, $5); + delete $2; + delete $3; +}; + +BodyList : /*empty*/ | BodyList BodyItem; +Body : ';' | '{' BodyList '}'; + +SubClassRef : ClassID { + $$ = new SubClassRefTy($1, new std::vector<Init*>()); + } | ClassID '<' ValueListNE '>' { + $$ = new SubClassRefTy($1, $3); + }; + +ClassListNE : SubClassRef { + $$ = new std::vector<SubClassRefTy>(); + $$->push_back(*$1); + delete $1; + } + | ClassListNE ',' SubClassRef { + ($$=$1)->push_back(*$3); + delete $3; + }; + +ClassList : /*empty */ { + $$ = new std::vector<SubClassRefTy>(); + } + | ':' ClassListNE { + $$ = $2; + }; + +DeclListNE : Declaration { + CurRec->addTemplateArg(*$1); + delete $1; +} | DeclListNE ',' Declaration { + CurRec->addTemplateArg(*$3); + delete $3; +}; + +TemplateArgList : '<' DeclListNE '>' {}; +OptTemplateArgList : /*empty*/ | TemplateArgList; + +OptID : ID { $$ = $1; } | /*empty*/ { $$ = new std::string(); }; + +ObjectBody : OptID { + static unsigned AnonCounter = 0; + if ($1->empty()) + *$1 = "anonymous."+utostr(AnonCounter++); + CurRec = new Record(*$1); + delete $1; + } OptTemplateArgList ClassList { + for (unsigned i = 0, e = $4->size(); i != e; ++i) { + addSubClass((*$4)[i].first, *(*$4)[i].second); + // Delete the template arg values for the class + delete (*$4)[i].second; + } + + // Process any variables on the set stack... + for (unsigned i = 0, e = LetStack.size(); i != e; ++i) + for (unsigned j = 0, e = LetStack[i].size(); j != e; ++j) + setValue(LetStack[i][j].Name, + LetStack[i][j].HasBits ? &LetStack[i][j].Bits : 0, + LetStack[i][j].Value); + } Body { + CurRec->resolveReferences(); + + // Now that all of the references have been resolved, we can delete template + // arguments for superclasses, so they don't pollute our record, and so that + // their names won't conflict with later uses of the name... + for (unsigned i = 0, e = $4->size(); i != e; ++i) { + Record *SuperClass = (*$4)[i].first; + for (unsigned i = 0, e = SuperClass->getTemplateArgs().size(); i != e; ++i) + CurRec->removeValue(SuperClass->getTemplateArgs()[i]); + } + delete $4; // Delete the class list... + + $$ = CurRec; + CurRec = 0; +}; + +ClassInst : CLASS ObjectBody { + if (Records.getClass($2->getName())) { + err() << "Class '" << $2->getName() << "' already defined!\n"; + abort(); + } + Records.addClass($$ = $2); +}; + +DefInst : DEF ObjectBody { + if (!$2->getTemplateArgs().empty()) { + err() << "Def '" << $2->getName() + << "' is not permitted to have template arguments!\n"; + abort(); + } + // If ObjectBody has template arguments, it's an error. + if (Records.getDef($2->getName())) { + err() << "Def '" << $2->getName() << "' already defined!\n"; + abort(); + } + Records.addDef($$ = $2); +}; + + +Object : ClassInst | DefInst; + +LETItem : ID OptBitList '=' Value { + LetStack.back().push_back(LetRecord(*$1, $2, $4)); + delete $1; delete $2; +}; + +LETList : LETItem | LETList ',' LETItem; + +// LETCommand - A 'LET' statement start... +LETCommand : LET { LetStack.push_back(std::vector<LetRecord>()); } LETList IN; + +// Support Set commands wrapping objects... both with and without braces. +Object : LETCommand '{' ObjectList '}' { + LetStack.pop_back(); + } + | LETCommand Object { + LetStack.pop_back(); + }; + +ObjectList : Object {} | ObjectList Object {}; + +File : ObjectList {}; + +%% + +int yyerror(const char *ErrorMsg) { + err() << "Error parsing: " << ErrorMsg << "\n"; + abort(); +} diff --git a/llvm/utils/TableGen/InstrInfoEmitter.cpp b/llvm/utils/TableGen/InstrInfoEmitter.cpp new file mode 100644 index 00000000000..c794cd04418 --- /dev/null +++ b/llvm/utils/TableGen/InstrInfoEmitter.cpp @@ -0,0 +1,160 @@ +//===- InstrInfoEmitter.cpp - Generate a Instruction Set Desc. ------------===// +// +// This tablegen backend is responsible for emitting a description of the target +// instruction set for the code generator. +// +//===----------------------------------------------------------------------===// + +#include "InstrInfoEmitter.h" +#include "CodeGenWrappers.h" +#include "Record.h" + +// runEnums - Print out enum values for all of the instructions. +void InstrInfoEmitter::runEnums(std::ostream &OS) { + std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction"); + + if (Insts.size() == 0) + throw std::string("No 'Instruction' subclasses defined!"); + + std::string Namespace = Insts[0]->getValueAsString("Namespace"); + + EmitSourceFileHeader("Target Instruction Enum Values", OS); + + if (!Namespace.empty()) + OS << "namespace " << Namespace << " {\n"; + OS << " enum {\n"; + + CodeGenTarget Target; + + // We must emit the PHI opcode first... + Record *InstrInfo = Target.getInstructionSet(); + Record *PHI = InstrInfo->getValueAsDef("PHIInst"); + + OS << " " << PHI->getName() << ", \t// 0 (fixed for all targets)\n"; + + // Print out the rest of the instructions now... + for (unsigned i = 0, e = Insts.size(); i != e; ++i) + if (Insts[i] != PHI) + OS << " " << Insts[i]->getName() << ", \t// " << i+1 << "\n"; + + OS << " };\n"; + if (!Namespace.empty()) + OS << "}\n"; +} + +void InstrInfoEmitter::printDefList(ListInit *LI, const std::string &Name, + std::ostream &OS) const { + OS << "static const unsigned " << Name << "[] = { "; + for (unsigned j = 0, e = LI->getSize(); j != e; ++j) + if (DefInit *DI = dynamic_cast<DefInit*>(LI->getElement(j))) + OS << getQualifiedName(DI->getDef()) << ", "; + else + throw "Illegal value in '" + Name + "' list!"; + OS << "0 };\n"; +} + + +// run - Emit the main instruction description records for the target... +void InstrInfoEmitter::run(std::ostream &OS) { + EmitSourceFileHeader("Target Instruction Descriptors", OS); + CodeGenTarget Target; + const std::string &TargetName = Target.getName(); + Record *InstrInfo = Target.getInstructionSet(); + Record *PHI = InstrInfo->getValueAsDef("PHIInst"); + + std::vector<Record*> Instructions = + Records.getAllDerivedDefinitions("Instruction"); + + // Emit all of the instruction's implicit uses and defs... + for (unsigned i = 0, e = Instructions.size(); i != e; ++i) { + Record *Inst = Instructions[i]; + ListInit *LI = Inst->getValueAsListInit("Uses"); + if (LI->getSize()) printDefList(LI, Inst->getName()+"ImpUses", OS); + LI = Inst->getValueAsListInit("Defs"); + if (LI->getSize()) printDefList(LI, Inst->getName()+"ImpDefs", OS); + } + + OS << "\nstatic const TargetInstrDescriptor " << TargetName + << "Insts[] = {\n"; + emitRecord(PHI, 0, InstrInfo, OS); + + for (unsigned i = 0, e = Instructions.size(); i != e; ++i) + if (Instructions[i] != PHI) + emitRecord(Instructions[i], i+1, InstrInfo, OS); + OS << "};\n"; +} + +void InstrInfoEmitter::emitRecord(Record *R, unsigned Num, Record *InstrInfo, + std::ostream &OS) { + OS << " { \"" << R->getValueAsString("Name") + << "\",\t-1, -1, 0, false, 0, 0, 0, 0"; + + // Emit all of the target indepedent flags... + if (R->getValueAsBit("isReturn")) OS << "|M_RET_FLAG"; + if (R->getValueAsBit("isBranch")) OS << "|M_BRANCH_FLAG"; + if (R->getValueAsBit("isCall" )) OS << "|M_CALL_FLAG"; + if (R->getValueAsBit("isTwoAddress")) OS << "|M_2_ADDR_FLAG"; + if (R->getValueAsBit("isTerminator")) OS << "|M_TERMINATOR_FLAG"; + 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(R, dynamic_cast<StringInit*>(LI->getElement(i)), + dynamic_cast<IntInit*>(Shift->getElement(i)), OS); + + OS << ", "; + + // Emit the implicit uses and defs lists... + LI = R->getValueAsListInit("Uses"); + if (!LI->getSize()) + OS << "0, "; + else + OS << R->getName() << "ImpUses, "; + + LI = R->getValueAsListInit("Defs"); + if (!LI->getSize()) + OS << "0 "; + else + OS << R->getName() << "ImpDefs "; + + OS << " }, // Inst #" << Num << " = " << R->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) + throw R->getName() + " doesn't have a field named '" + Val->getValue()+"'!"; + + 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()) + OS << "|(" << II->getValue() << "<<" << Shift << ")"; + return; + } + + } else if (IntInit *II = dynamic_cast<IntInit*>(Value)) { + if (II->getValue()) OS << "|(" << II->getValue() << "<<" << Shift << ")"; + return; + } + + std::cerr << "Unhandled initializer: " << *Val << "\n"; + throw "In record '" + R->getName() + "' for TSFlag emission."; +} diff --git a/llvm/utils/TableGen/InstrInfoEmitter.h b/llvm/utils/TableGen/InstrInfoEmitter.h new file mode 100644 index 00000000000..400c0db16c6 --- /dev/null +++ b/llvm/utils/TableGen/InstrInfoEmitter.h @@ -0,0 +1,34 @@ +//===- InstrInfoEmitter.h - Generate a Instruction Set Desc. ----*- C++ -*-===// +// +// 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" +class StringInit; +class IntInit; +class ListInit; + +class InstrInfoEmitter : public TableGenBackend { + RecordKeeper &Records; +public: + InstrInfoEmitter(RecordKeeper &R) : Records(R) {} + + // run - Output the instruction set description, returning true on failure. + void run(std::ostream &OS); + + // runEnums - Print out enum values for all of the instructions. + void runEnums(std::ostream &OS); +private: + void printDefList(ListInit *LI, const std::string &Name, + std::ostream &OS) const; + void emitRecord(Record *R, unsigned Num, Record *InstrInfo, std::ostream &OS); + void emitShiftedValue(Record *R, StringInit *Val, IntInit *Shift, + std::ostream &OS); +}; + +#endif diff --git a/llvm/utils/TableGen/InstrSelectorEmitter.cpp b/llvm/utils/TableGen/InstrSelectorEmitter.cpp new file mode 100644 index 00000000000..a3c535cad4e --- /dev/null +++ b/llvm/utils/TableGen/InstrSelectorEmitter.cpp @@ -0,0 +1,1287 @@ +//===- InstrInfoEmitter.cpp - Generate a Instruction Set Desc. ------------===// +// +// This tablegen backend is responsible for emitting a description of the target +// instruction set for the code generator. +// +//===----------------------------------------------------------------------===// + +#include "InstrSelectorEmitter.h" +#include "CodeGenWrappers.h" +#include "Record.h" +#include "Support/Debug.h" +#include "Support/StringExtras.h" +#include <set> + +NodeType::ArgResultTypes NodeType::Translate(Record *R) { + const std::string &Name = R->getName(); + if (Name == "DNVT_any") return Any; + if (Name == "DNVT_void") return Void; + if (Name == "DNVT_val" ) return Val; + if (Name == "DNVT_arg0") return Arg0; + if (Name == "DNVT_arg1") return Arg1; + if (Name == "DNVT_ptr" ) return Ptr; + if (Name == "DNVT_i8" ) return I8; + throw "Unknown DagNodeValType '" + Name + "'!"; +} + + +//===----------------------------------------------------------------------===// +// TreePatternNode implementation +// + +/// getValueRecord - Returns the value of this tree node as a record. For now +/// we only allow DefInit's as our leaf values, so this is used. +Record *TreePatternNode::getValueRecord() const { + DefInit *DI = dynamic_cast<DefInit*>(getValue()); + assert(DI && "Instruction Selector does not yet support non-def leaves!"); + return DI->getDef(); +} + + +// updateNodeType - Set the node type of N to VT if VT contains information. If +// N already contains a conflicting type, then throw an exception +// +bool TreePatternNode::updateNodeType(MVT::ValueType VT, + const std::string &RecName) { + if (VT == MVT::Other || getType() == VT) return false; + if (getType() == MVT::Other) { + setType(VT); + return true; + } + + throw "Type inferfence contradiction found for pattern " + RecName; +} + +/// InstantiateNonterminals - If this pattern refers to any nonterminals which +/// are not themselves completely resolved, clone the nonterminal and resolve it +/// with the using context we provide. +/// +void TreePatternNode::InstantiateNonterminals(InstrSelectorEmitter &ISE) { + if (!isLeaf()) { + for (unsigned i = 0, e = getNumChildren(); i != e; ++i) + getChild(i)->InstantiateNonterminals(ISE); + return; + } + + // If this is a leaf, it might be a reference to a nonterminal! Check now. + Record *R = getValueRecord(); + if (R->isSubClassOf("Nonterminal")) { + Pattern *NT = ISE.getPattern(R); + if (!NT->isResolved()) { + // We found an unresolved nonterminal reference. Ask the ISE to clone + // it for us, then update our reference to the fresh, new, resolved, + // nonterminal. + + Value = new DefInit(ISE.InstantiateNonterminal(NT, getType())); + } + } +} + + +/// clone - Make a copy of this tree and all of its children. +/// +TreePatternNode *TreePatternNode::clone() const { + TreePatternNode *New; + if (isLeaf()) { + New = new TreePatternNode(Value); + } else { + std::vector<std::pair<TreePatternNode*, std::string> > CChildren; + CChildren.reserve(Children.size()); + for (unsigned i = 0, e = getNumChildren(); i != e; ++i) + CChildren.push_back(std::make_pair(getChild(i)->clone(),getChildName(i))); + New = new TreePatternNode(Operator, CChildren); + } + New->setType(Type); + return New; +} + +std::ostream &operator<<(std::ostream &OS, const TreePatternNode &N) { + if (N.isLeaf()) + return OS << N.getType() << ":" << *N.getValue(); + OS << "(" << N.getType() << ":"; + OS << N.getOperator()->getName(); + + if (N.getNumChildren() != 0) { + OS << " " << *N.getChild(0); + for (unsigned i = 1, e = N.getNumChildren(); i != e; ++i) + OS << ", " << *N.getChild(i); + } + return OS << ")"; +} + +void TreePatternNode::dump() const { std::cerr << *this; } + +//===----------------------------------------------------------------------===// +// Pattern implementation +// + +// Parse the specified DagInit into a TreePattern which we can use. +// +Pattern::Pattern(PatternType pty, DagInit *RawPat, Record *TheRec, + InstrSelectorEmitter &ise) + : PTy(pty), ResultNode(0), TheRecord(TheRec), ISE(ise) { + + // First, parse the pattern... + Tree = ParseTreePattern(RawPat); + + // Run the type-inference engine... + InferAllTypes(); + + if (PTy == Instruction || PTy == Expander) { + // Check to make sure there is not any unset types in the tree pattern... + if (!isResolved()) { + std::cerr << "In pattern: " << *Tree << "\n"; + error("Could not infer all types!"); + } + + // Check to see if we have a top-level (set) of a register. + if (Tree->getOperator()->getName() == "set") { + assert(Tree->getNumChildren() == 2 && "Set with != 2 arguments?"); + if (!Tree->getChild(0)->isLeaf()) + error("Arg #0 of set should be a register or register class!"); + ResultNode = Tree->getChild(0); + ResultName = Tree->getChildName(0); + Tree = Tree->getChild(1); + } + } + + calculateArgs(Tree, ""); +} + +void Pattern::error(const std::string &Msg) const { + std::string M = "In "; + switch (PTy) { + case Nonterminal: M += "nonterminal "; break; + case Instruction: M += "instruction "; break; + case Expander : M += "expander "; break; + } + throw M + TheRecord->getName() + ": " + Msg; +} + +/// calculateArgs - Compute the list of all of the arguments to this pattern, +/// which are the non-void leaf nodes in this pattern. +/// +void Pattern::calculateArgs(TreePatternNode *N, const std::string &Name) { + if (N->isLeaf() || N->getNumChildren() == 0) { + if (N->getType() != MVT::isVoid) + Args.push_back(std::make_pair(N, Name)); + } else { + for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) + calculateArgs(N->getChild(i), N->getChildName(i)); + } +} + +/// getIntrinsicType - Check to see if the specified record has an intrinsic +/// type which should be applied to it. This infer the type of register +/// references from the register file information, for example. +/// +MVT::ValueType Pattern::getIntrinsicType(Record *R) const { + // Check to see if this is a register or a register class... + if (R->isSubClassOf("RegisterClass")) + return getValueType(R->getValueAsDef("RegType")); + else if (R->isSubClassOf("Nonterminal")) + return ISE.ReadNonterminal(R)->getTree()->getType(); + else if (R->isSubClassOf("Register")) { + std::cerr << "WARNING: Explicit registers not handled yet!\n"; + return MVT::Other; + } + + error("Unknown value used: " + R->getName()); + return MVT::Other; +} + +TreePatternNode *Pattern::ParseTreePattern(DagInit *Dag) { + Record *Operator = Dag->getNodeType(); + + 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 valid for a leaf node!"); + + Init *Arg = Dag->getArg(0); + TreePatternNode *New; + if (DefInit *DI = dynamic_cast<DefInit*>(Arg)) { + New = new TreePatternNode(DI); + // If it's a regclass or something else known, set the type. + New->setType(getIntrinsicType(DI->getDef())); + } else if (DagInit *DI = dynamic_cast<DagInit*>(Arg)) { + New = ParseTreePattern(DI); + } else { + Arg->dump(); + error("Unknown leaf value for tree pattern!"); + return 0; + } + + // Apply the type cast... + New->updateNodeType(getValueType(Operator), TheRecord->getName()); + return New; + } + + if (!ISE.getNodeTypes().count(Operator)) + error("Unrecognized node '" + Operator->getName() + "'!"); + + std::vector<std::pair<TreePatternNode*, std::string> > 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(std::make_pair(ParseTreePattern(DI), + Dag->getArgName(i))); + } else if (DefInit *DefI = dynamic_cast<DefInit*>(Arg)) { + Record *R = DefI->getDef(); + // Direct reference to a leaf DagNode? Turn it into a DagNode if its own. + if (R->isSubClassOf("DagNode")) { + Dag->setArg(i, new DagInit(R, + std::vector<std::pair<Init*, std::string> >())); + --i; // Revisit this node... + } else { + Children.push_back(std::make_pair(new TreePatternNode(DefI), + Dag->getArgName(i))); + // If it's a regclass or something else known, set the type. + Children.back().first->setType(getIntrinsicType(R)); + } + } else { + Arg->dump(); + error("Unknown leaf value for tree pattern!"); + } + } + + return new TreePatternNode(Operator, Children); +} + +void Pattern::InferAllTypes() { + bool MadeChange, AnyUnset; + do { + MadeChange = false; + AnyUnset = InferTypes(Tree, MadeChange); + } while ((AnyUnset || MadeChange) && !(AnyUnset && !MadeChange)); + Resolved = !AnyUnset; +} + + +// InferTypes - Perform type inference on the tree, returning true if there +// are any remaining untyped nodes and setting MadeChange if any changes were +// made. +bool Pattern::InferTypes(TreePatternNode *N, bool &MadeChange) { + if (N->isLeaf()) return N->getType() == MVT::Other; + + bool AnyUnset = false; + Record *Operator = N->getOperator(); + const NodeType &NT = ISE.getNodeType(Operator); + + // Check to see if we can infer anything about the argument types from the + // return types... + if (N->getNumChildren() != NT.ArgTypes.size()) + error("Incorrect number of children for " + Operator->getName() + " node!"); + + for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) { + TreePatternNode *Child = N->getChild(i); + AnyUnset |= InferTypes(Child, MadeChange); + + switch (NT.ArgTypes[i]) { + case NodeType::Any: break; + case NodeType::I8: + MadeChange |= Child->updateNodeType(MVT::i1, TheRecord->getName()); + break; + case NodeType::Arg0: + MadeChange |= Child->updateNodeType(N->getChild(0)->getType(), + TheRecord->getName()); + break; + case NodeType::Arg1: + MadeChange |= Child->updateNodeType(N->getChild(1)->getType(), + TheRecord->getName()); + break; + case NodeType::Val: + if (Child->getType() == MVT::isVoid) + error("Inferred a void node in an illegal place!"); + break; + case NodeType::Ptr: + MadeChange |= Child->updateNodeType(ISE.getTarget().getPointerType(), + TheRecord->getName()); + break; + case NodeType::Void: + MadeChange |= Child->updateNodeType(MVT::isVoid, TheRecord->getName()); + break; + default: assert(0 && "Invalid argument ArgType!"); + } + } + + // See if we can infer anything about the return type now... + switch (NT.ResultType) { + case NodeType::Any: break; + case NodeType::Void: + MadeChange |= N->updateNodeType(MVT::isVoid, TheRecord->getName()); + break; + case NodeType::I8: + MadeChange |= N->updateNodeType(MVT::i1, TheRecord->getName()); + break; + case NodeType::Arg0: + MadeChange |= N->updateNodeType(N->getChild(0)->getType(), + TheRecord->getName()); + break; + case NodeType::Arg1: + MadeChange |= N->updateNodeType(N->getChild(1)->getType(), + TheRecord->getName()); + break; + case NodeType::Ptr: + MadeChange |= N->updateNodeType(ISE.getTarget().getPointerType(), + TheRecord->getName()); + break; + case NodeType::Val: + if (N->getType() == MVT::isVoid) + error("Inferred a void node in an illegal place!"); + break; + default: + assert(0 && "Unhandled type constraint!"); + break; + } + + return AnyUnset | N->getType() == MVT::Other; +} + +/// clone - This method is used to make an exact copy of the current pattern, +/// then change the "TheRecord" instance variable to the specified record. +/// +Pattern *Pattern::clone(Record *R) const { + assert(PTy == Nonterminal && "Can only clone nonterminals"); + return new Pattern(Tree->clone(), R, Resolved, ISE); +} + + + +std::ostream &operator<<(std::ostream &OS, const Pattern &P) { + switch (P.getPatternType()) { + case Pattern::Nonterminal: OS << "Nonterminal pattern "; break; + case Pattern::Instruction: OS << "Instruction pattern "; break; + case Pattern::Expander: OS << "Expander pattern "; break; + } + + OS << P.getRecord()->getName() << ":\t"; + + if (Record *Result = P.getResult()) + OS << Result->getName() << " = "; + OS << *P.getTree(); + + if (!P.isResolved()) + OS << " [not completely resolved]"; + return OS; +} + +void Pattern::dump() const { std::cerr << *this; } + + + +/// getSlotName - If this is a leaf node, return the slot name that the operand +/// will update. +std::string Pattern::getSlotName() const { + if (getPatternType() == Pattern::Nonterminal) { + // Just use the nonterminal name, which will already include the type if + // it has been cloned. + return getRecord()->getName(); + } else { + std::string SlotName; + if (getResult()) + SlotName = getResult()->getName()+"_"; + else + SlotName = "Void_"; + return SlotName + getName(getTree()->getType()); + } +} + +/// getSlotName - If this is a leaf node, return the slot name that the +/// operand will update. +std::string Pattern::getSlotName(Record *R) { + if (R->isSubClassOf("Nonterminal")) { + // Just use the nonterminal name, which will already include the type if + // it has been cloned. + return R->getName(); + } else if (R->isSubClassOf("RegisterClass")) { + MVT::ValueType Ty = getValueType(R->getValueAsDef("RegType")); + return R->getName() + "_" + getName(Ty); + } else { + assert(0 && "Don't know how to get a slot name for this!"); + } + return ""; +} + +//===----------------------------------------------------------------------===// +// PatternOrganizer implementation +// + +/// addPattern - Add the specified pattern to the appropriate location in the +/// collection. +void PatternOrganizer::addPattern(Pattern *P) { + NodesForSlot &Nodes = AllPatterns[P->getSlotName()]; + if (!P->getTree()->isLeaf()) + Nodes[P->getTree()->getOperator()].push_back(P); + else { + // Right now we only support DefInit's with node types... + Nodes[P->getTree()->getValueRecord()].push_back(P); + } +} + + + +//===----------------------------------------------------------------------===// +// InstrSelectorEmitter implementation +// + +/// ReadNodeTypes - Read in all of the node types in the current RecordKeeper, +/// turning them into the more accessible NodeTypes data structure. +/// +void InstrSelectorEmitter::ReadNodeTypes() { + std::vector<Record*> Nodes = Records.getAllDerivedDefinitions("DagNode"); + DEBUG(std::cerr << "Getting node types: "); + for (unsigned i = 0, e = Nodes.size(); i != e; ++i) { + Record *Node = Nodes[i]; + + // Translate the return type... + NodeType::ArgResultTypes RetTy = + NodeType::Translate(Node->getValueAsDef("RetType")); + + // Translate the arguments... + ListInit *Args = Node->getValueAsListInit("ArgTypes"); + std::vector<NodeType::ArgResultTypes> ArgTypes; + + for (unsigned a = 0, e = Args->getSize(); a != e; ++a) { + if (DefInit *DI = dynamic_cast<DefInit*>(Args->getElement(a))) + ArgTypes.push_back(NodeType::Translate(DI->getDef())); + else + throw "In node " + Node->getName() + ", argument is not a Def!"; + + if (a == 0 && ArgTypes.back() == NodeType::Arg0) + throw "In node " + Node->getName() + ", arg 0 cannot have type 'arg0'!"; + if (a == 1 && ArgTypes.back() == NodeType::Arg1) + throw "In node " + Node->getName() + ", arg 1 cannot have type 'arg1'!"; + } + if ((RetTy == NodeType::Arg0 && Args->getSize() == 0) || + (RetTy == NodeType::Arg1 && Args->getSize() < 2)) + throw "In node " + Node->getName() + + ", invalid return type for node with this many operands!"; + + // Add the node type mapping now... + NodeTypes[Node] = NodeType(RetTy, ArgTypes); + DEBUG(std::cerr << Node->getName() << ", "); + } + DEBUG(std::cerr << "DONE!\n"); +} + +Pattern *InstrSelectorEmitter::ReadNonterminal(Record *R) { + Pattern *&P = Patterns[R]; + if (P) return P; // Don't reread it! + + DagInit *DI = R->getValueAsDag("Pattern"); + P = new Pattern(Pattern::Nonterminal, DI, R, *this); + DEBUG(std::cerr << "Parsed " << *P << "\n"); + return P; +} + + +// ReadNonTerminals - Read in all nonterminals and incorporate them into our +// pattern database. +void InstrSelectorEmitter::ReadNonterminals() { + std::vector<Record*> NTs = Records.getAllDerivedDefinitions("Nonterminal"); + for (unsigned i = 0, e = NTs.size(); i != e; ++i) + ReadNonterminal(NTs[i]); +} + + +/// ReadInstructionPatterns - Read in all subclasses of Instruction, and process +/// those with a useful Pattern field. +/// +void InstrSelectorEmitter::ReadInstructionPatterns() { + std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction"); + for (unsigned i = 0, e = Insts.size(); i != e; ++i) { + Record *Inst = Insts[i]; + if (DagInit *DI = dynamic_cast<DagInit*>(Inst->getValueInit("Pattern"))) { + Patterns[Inst] = new Pattern(Pattern::Instruction, DI, Inst, *this); + DEBUG(std::cerr << "Parsed " << *Patterns[Inst] << "\n"); + } + } +} + +/// ReadExpanderPatterns - Read in all expander patterns... +/// +void InstrSelectorEmitter::ReadExpanderPatterns() { + std::vector<Record*> Expanders = Records.getAllDerivedDefinitions("Expander"); + for (unsigned i = 0, e = Expanders.size(); i != e; ++i) { + Record *Expander = Expanders[i]; + DagInit *DI = Expander->getValueAsDag("Pattern"); + Patterns[Expander] = new Pattern(Pattern::Expander, DI, Expander, *this); + DEBUG(std::cerr << "Parsed " << *Patterns[Expander] << "\n"); + } +} + + +// InstantiateNonterminals - Instantiate any unresolved nonterminals with +// information from the context that they are used in. +// +void InstrSelectorEmitter::InstantiateNonterminals() { + DEBUG(std::cerr << "Instantiating nonterminals:\n"); + for (std::map<Record*, Pattern*>::iterator I = Patterns.begin(), + E = Patterns.end(); I != E; ++I) + if (I->second->isResolved()) + I->second->InstantiateNonterminals(); +} + +/// InstantiateNonterminal - This method takes the nonterminal specified by +/// NT, which should not be completely resolved, clones it, applies ResultTy +/// to its root, then runs the type inference stuff on it. This should +/// produce a newly resolved nonterminal, which we make a record for and +/// return. To be extra fancy and efficient, this only makes one clone for +/// each type it is instantiated with. +Record *InstrSelectorEmitter::InstantiateNonterminal(Pattern *NT, + MVT::ValueType ResultTy) { + assert(!NT->isResolved() && "Nonterminal is already resolved!"); + + // Check to see if we have already instantiated this pair... + Record* &Slot = InstantiatedNTs[std::make_pair(NT, ResultTy)]; + if (Slot) return Slot; + + Record *New = new Record(NT->getRecord()->getName()+"_"+getName(ResultTy)); + + // Copy over the superclasses... + const std::vector<Record*> &SCs = NT->getRecord()->getSuperClasses(); + for (unsigned i = 0, e = SCs.size(); i != e; ++i) + New->addSuperClass(SCs[i]); + + DEBUG(std::cerr << " Nonterminal '" << NT->getRecord()->getName() + << "' for type '" << getName(ResultTy) << "', producing '" + << New->getName() << "'\n"); + + // Copy the pattern... + Pattern *NewPat = NT->clone(New); + + // Apply the type to the root... + NewPat->getTree()->updateNodeType(ResultTy, New->getName()); + + // Infer types... + NewPat->InferAllTypes(); + + // Make sure everything is good to go now... + if (!NewPat->isResolved()) + NewPat->error("Instantiating nonterminal did not resolve all types!"); + + // Add the pattern to the patterns map, add the record to the RecordKeeper, + // return the new record. + Patterns[New] = NewPat; + Records.addDef(New); + return Slot = New; +} + +// CalculateComputableValues - Fill in the ComputableValues map through +// analysis of the patterns we are playing with. +void InstrSelectorEmitter::CalculateComputableValues() { + // Loop over all of the patterns, adding them to the ComputableValues map + for (std::map<Record*, Pattern*>::iterator I = Patterns.begin(), + E = Patterns.end(); I != E; ++I) + if (I->second->isResolved()) { + // We don't want to add patterns like R32 = R32. This is a hack working + // around a special case of a general problem, but for now we explicitly + // forbid these patterns. They can never match anyway. + Pattern *P = I->second; + if (!P->getResult() || !P->getTree()->isLeaf() || + P->getResult() != P->getTree()->getValueRecord()) + ComputableValues.addPattern(P); + } +} + +#if 0 +// MoveIdenticalPatterns - Given a tree pattern 'P', move all of the tree +// patterns which have the same top-level structure as P from the 'From' list to +// the 'To' list. +static void MoveIdenticalPatterns(TreePatternNode *P, + std::vector<std::pair<Pattern*, TreePatternNode*> > &From, + std::vector<std::pair<Pattern*, TreePatternNode*> > &To) { + assert(!P->isLeaf() && "All leaves are identical!"); + + const std::vector<TreePatternNode*> &PChildren = P->getChildren(); + for (unsigned i = 0; i != From.size(); ++i) { + TreePatternNode *N = From[i].second; + assert(P->getOperator() == N->getOperator() &&"Differing operators?"); + assert(PChildren.size() == N->getChildren().size() && + "Nodes with different arity??"); + bool isDifferent = false; + for (unsigned c = 0, e = PChildren.size(); c != e; ++c) { + TreePatternNode *PC = PChildren[c]; + TreePatternNode *NC = N->getChild(c); + if (PC->isLeaf() != NC->isLeaf()) { + isDifferent = true; + break; + } + + if (!PC->isLeaf()) { + if (PC->getOperator() != NC->getOperator()) { + isDifferent = true; + break; + } + } else { // It's a leaf! + if (PC->getValueRecord() != NC->getValueRecord()) { + isDifferent = true; + break; + } + } + } + // If it's the same as the reference one, move it over now... + if (!isDifferent) { + To.push_back(std::make_pair(From[i].first, N)); + From.erase(From.begin()+i); + --i; // Don't skip an entry... + } + } +} +#endif + +static std::string getNodeName(Record *R) { + RecordVal *RV = R->getValue("EnumName"); + if (RV) + if (Init *I = RV->getValue()) + if (StringInit *SI = dynamic_cast<StringInit*>(I)) + return SI->getValue(); + return R->getName(); +} + + +static void EmitPatternPredicates(TreePatternNode *Tree, + const std::string &VarName, std::ostream &OS){ + OS << " && " << VarName << "->getNodeType() == ISD::" + << getNodeName(Tree->getOperator()); + + for (unsigned c = 0, e = Tree->getNumChildren(); c != e; ++c) + if (!Tree->getChild(c)->isLeaf()) + EmitPatternPredicates(Tree->getChild(c), + VarName + "->getUse(" + utostr(c)+")", OS); +} + +static void EmitPatternCosts(TreePatternNode *Tree, const std::string &VarName, + std::ostream &OS) { + for (unsigned c = 0, e = Tree->getNumChildren(); c != e; ++c) + if (Tree->getChild(c)->isLeaf()) { + OS << " + Match_" + << Pattern::getSlotName(Tree->getChild(c)->getValueRecord()) << "(" + << VarName << "->getUse(" << c << "))"; + } else { + EmitPatternCosts(Tree->getChild(c), + VarName + "->getUse(" + utostr(c) + ")", OS); + } +} + + +// EmitMatchCosters - Given a list of patterns, which all have the same root +// pattern operator, emit an efficient decision tree to decide which one to +// pick. This is structured this way to avoid reevaluations of non-obvious +// subexpressions. +void InstrSelectorEmitter::EmitMatchCosters(std::ostream &OS, + const std::vector<std::pair<Pattern*, TreePatternNode*> > &Patterns, + const std::string &VarPrefix, + unsigned IndentAmt) { + assert(!Patterns.empty() && "No patterns to emit matchers for!"); + std::string Indent(IndentAmt, ' '); + + // Load all of the operands of the root node into scalars for fast access + const NodeType &ONT = getNodeType(Patterns[0].second->getOperator()); + for (unsigned i = 0, e = ONT.ArgTypes.size(); i != e; ++i) + OS << Indent << "SelectionDAGNode *" << VarPrefix << "_Op" << i + << " = N->getUse(" << i << ");\n"; + + // Compute the costs of computing the various nonterminals/registers, which + // are directly used at this level. + OS << "\n" << Indent << "// Operand matching costs...\n"; + std::set<std::string> ComputedValues; // Avoid duplicate computations... + for (unsigned i = 0, e = Patterns.size(); i != e; ++i) { + TreePatternNode *NParent = Patterns[i].second; + for (unsigned c = 0, e = NParent->getNumChildren(); c != e; ++c) { + TreePatternNode *N = NParent->getChild(c); + if (N->isLeaf()) { + Record *VR = N->getValueRecord(); + const std::string &LeafName = VR->getName(); + std::string OpName = VarPrefix + "_Op" + utostr(c); + std::string ValName = OpName + "_" + LeafName + "_Cost"; + if (!ComputedValues.count(ValName)) { + OS << Indent << "unsigned " << ValName << " = Match_" + << Pattern::getSlotName(VR) << "(" << OpName << ");\n"; + ComputedValues.insert(ValName); + } + } + } + } + OS << "\n"; + + + std::string LocCostName = VarPrefix + "_Cost"; + OS << Indent << "unsigned " << LocCostName << "Min = ~0U >> 1;\n" + << Indent << "unsigned " << VarPrefix << "_PatternMin = NoMatchPattern;\n"; + +#if 0 + // Separate out all of the patterns into groups based on what their top-level + // signature looks like... + std::vector<std::pair<Pattern*, TreePatternNode*> > PatternsLeft(Patterns); + while (!PatternsLeft.empty()) { + // Process all of the patterns that have the same signature as the last + // element... + std::vector<std::pair<Pattern*, TreePatternNode*> > Group; + MoveIdenticalPatterns(PatternsLeft.back().second, PatternsLeft, Group); + assert(!Group.empty() && "Didn't at least pick the source pattern?"); + +#if 0 + OS << "PROCESSING GROUP:\n"; + for (unsigned i = 0, e = Group.size(); i != e; ++i) + OS << " " << *Group[i].first << "\n"; + OS << "\n\n"; +#endif + + OS << Indent << "{ // "; + + if (Group.size() != 1) { + OS << Group.size() << " size group...\n"; + OS << Indent << " unsigned " << VarPrefix << "_Pattern = NoMatch;\n"; + } else { + OS << *Group[0].first << "\n"; + OS << Indent << " unsigned " << VarPrefix << "_Pattern = " + << Group[0].first->getRecord()->getName() << "_Pattern;\n"; + } + + OS << Indent << " unsigned " << LocCostName << " = "; + if (Group.size() == 1) + OS << "1;\n"; // Add inst cost if at individual rec + else + OS << "0;\n"; + + // Loop over all of the operands, adding in their costs... + TreePatternNode *N = Group[0].second; + const std::vector<TreePatternNode*> &Children = N->getChildren(); + + // If necessary, emit conditionals to check for the appropriate tree + // structure here... + for (unsigned i = 0, e = Children.size(); i != e; ++i) { + TreePatternNode *C = Children[i]; + if (C->isLeaf()) { + // We already calculated the cost for this leaf, add it in now... + OS << Indent << " " << LocCostName << " += " + << VarPrefix << "_Op" << utostr(i) << "_" + << C->getValueRecord()->getName() << "_Cost;\n"; + } else { + // If it's not a leaf, we have to check to make sure that the current + // node has the appropriate structure, then recurse into it... + OS << Indent << " if (" << VarPrefix << "_Op" << i + << "->getNodeType() == ISD::" << getNodeName(C->getOperator()) + << ") {\n"; + std::vector<std::pair<Pattern*, TreePatternNode*> > SubPatterns; + for (unsigned n = 0, e = Group.size(); n != e; ++n) + SubPatterns.push_back(std::make_pair(Group[n].first, + Group[n].second->getChild(i))); + EmitMatchCosters(OS, SubPatterns, VarPrefix+"_Op"+utostr(i), + IndentAmt + 4); + OS << Indent << " }\n"; + } + } + + // If the cost for this match is less than the minimum computed cost so far, + // update the minimum cost and selected pattern. + OS << Indent << " if (" << LocCostName << " < " << LocCostName << "Min) { " + << LocCostName << "Min = " << LocCostName << "; " << VarPrefix + << "_PatternMin = " << VarPrefix << "_Pattern; }\n"; + + OS << Indent << "}\n"; + } +#endif + + for (unsigned i = 0, e = Patterns.size(); i != e; ++i) { + Pattern *P = Patterns[i].first; + TreePatternNode *PTree = P->getTree(); + unsigned PatternCost = 1; + + // Check to see if there are any non-leaf elements in the pattern. If so, + // we need to emit a predicate for this match. + bool AnyNonLeaf = false; + for (unsigned c = 0, e = PTree->getNumChildren(); c != e; ++c) + if (!PTree->getChild(c)->isLeaf()) { + AnyNonLeaf = true; + break; + } + + if (!AnyNonLeaf) { // No predicate necessary, just output a scope... + OS << " {// " << *P << "\n"; + } else { + // We need to emit a predicate to make sure the tree pattern matches, do + // so now... + OS << " if (1"; + for (unsigned c = 0, e = PTree->getNumChildren(); c != e; ++c) + if (!PTree->getChild(c)->isLeaf()) + EmitPatternPredicates(PTree->getChild(c), + VarPrefix + "_Op" + utostr(c), OS); + + OS << ") {\n // " << *P << "\n"; + } + + OS << " unsigned PatCost = " << PatternCost; + + for (unsigned c = 0, e = PTree->getNumChildren(); c != e; ++c) + if (PTree->getChild(c)->isLeaf()) { + OS << " + " << VarPrefix << "_Op" << c << "_" + << PTree->getChild(c)->getValueRecord()->getName() << "_Cost"; + } else { + EmitPatternCosts(PTree->getChild(c), VarPrefix + "_Op" + utostr(c), OS); + } + OS << ";\n"; + OS << " if (PatCost < MinCost) { MinCost = PatCost; Pattern = " + << P->getRecord()->getName() << "_Pattern; }\n" + << " }\n"; + } +} + +static void ReduceAllOperands(TreePatternNode *N, const std::string &Name, + std::vector<std::pair<TreePatternNode*, std::string> > &Operands, + std::ostream &OS) { + if (N->isLeaf()) { + // If this is a leaf, register or nonterminal reference... + std::string SlotName = Pattern::getSlotName(N->getValueRecord()); + OS << " ReducedValue_" << SlotName << " *" << Name << "Val = Reduce_" + << SlotName << "(" << Name << ", MBB);\n"; + Operands.push_back(std::make_pair(N, Name+"Val")); + } else if (N->getNumChildren() == 0) { + // This is a reference to a leaf tree node, like an immediate or frame + // index. + if (N->getType() != MVT::isVoid) { + std::string SlotName = + getNodeName(N->getOperator()) + "_" + getName(N->getType()); + OS << " ReducedValue_" << SlotName << " *" << Name << "Val = " + << Name << "->getValue<ReducedValue_" << SlotName << ">(ISD::" + << SlotName << "_Slot);\n"; + Operands.push_back(std::make_pair(N, Name+"Val")); + } + } else { + // Otherwise this is an interior node... + for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) { + std::string ChildName = Name + "_Op" + utostr(i); + OS << " SelectionDAGNode *" << ChildName << " = " << Name + << "->getUse(" << i << ");\n"; + ReduceAllOperands(N->getChild(i), ChildName, Operands, OS); + } + } +} + +/// PrintExpanderOperand - Print out Arg as part of the instruction emission +/// process for the expander pattern P. This argument may be referencing some +/// values defined in P, or may just be physical register references or +/// something like that. If PrintArg is true, we are printing out arguments to +/// the BuildMI call. If it is false, we are printing the result register +/// name. +void InstrSelectorEmitter::PrintExpanderOperand(Init *Arg, + const std::string &NameVar, + TreePatternNode *ArgDeclNode, + Pattern *P, bool PrintArg, + std::ostream &OS) { + if (DefInit *DI = dynamic_cast<DefInit*>(Arg)) { + Record *Arg = DI->getDef(); + if (!ArgDeclNode->isLeaf() && ArgDeclNode->getNumChildren() != 0) + P->error("Expected leaf node as argument!"); + Record *ArgDecl = ArgDeclNode->isLeaf() ? ArgDeclNode->getValueRecord() : + ArgDeclNode->getOperator(); + if (Arg->isSubClassOf("Register")) { + // This is a physical register reference... make sure that the instruction + // requested a register! + if (!ArgDecl->isSubClassOf("RegisterClass")) + P->error("Argument mismatch for instruction pattern!"); + + // FIXME: This should check to see if the register is in the specified + // register class! + if (PrintArg) OS << ".addReg("; + OS << getQualifiedName(Arg); + if (PrintArg) OS << ")"; + return; + } else if (Arg->isSubClassOf("RegisterClass")) { + // If this is a symbolic register class reference, we must be using a + // named value. + if (NameVar.empty()) P->error("Did not specify WHICH register to pass!"); + if (Arg != ArgDecl) P->error("Instruction pattern mismatch!"); + + if (PrintArg) OS << ".addReg("; + OS << NameVar; + if (PrintArg) OS << ")"; + return; + } else if (Arg->getName() == "frameidx") { + if (!PrintArg) P->error("Cannot define a new frameidx value!"); + OS << ".addFrameIndex(" << NameVar << ")"; + return; + } else if (Arg->getName() == "basicblock") { + if (!PrintArg) P->error("Cannot define a new basicblock value!"); + OS << ".addMBB(" << NameVar << ")"; + return; + } + P->error("Unknown operand type '" + Arg->getName() + "' to expander!"); + } else if (IntInit *II = dynamic_cast<IntInit*>(Arg)) { + if (!NameVar.empty()) + P->error("Illegal to specify a name for a constant initializer arg!"); + + // Hack this check to allow R32 values with 0 as the initializer for memory + // references... FIXME! + if (ArgDeclNode->isLeaf() && II->getValue() == 0 && + ArgDeclNode->getValueRecord()->getName() == "R32") { + OS << ".addReg(0)"; + } else { + if (ArgDeclNode->isLeaf() || ArgDeclNode->getOperator()->getName()!="imm") + P->error("Illegal immediate int value '" + itostr(II->getValue()) + + "' operand!"); + OS << ".addZImm(" << II->getValue() << ")"; + } + return; + } + P->error("Unknown operand type to expander!"); +} + +static std::string getArgName(Pattern *P, const std::string &ArgName, + const std::vector<std::pair<TreePatternNode*, std::string> > &Operands) { + assert(P->getNumArgs() == Operands.size() &&"Argument computation mismatch!"); + if (ArgName.empty()) return ""; + + for (unsigned i = 0, e = P->getNumArgs(); i != e; ++i) + if (P->getArgName(i) == ArgName) + return Operands[i].second + "->Val"; + + if (ArgName == P->getResultName()) + return "NewReg"; + P->error("Pattern does not define a value named $" + ArgName + "!"); + return ""; +} + + +void InstrSelectorEmitter::run(std::ostream &OS) { + // Type-check all of the node types to ensure we "understand" them. + ReadNodeTypes(); + + // Read in all of the nonterminals, instructions, and expanders... + ReadNonterminals(); + ReadInstructionPatterns(); + ReadExpanderPatterns(); + + // Instantiate any unresolved nonterminals with information from the context + // that they are used in. + InstantiateNonterminals(); + + // Clear InstantiatedNTs, we don't need it anymore... + InstantiatedNTs.clear(); + + DEBUG(std::cerr << "Patterns acquired:\n"); + for (std::map<Record*, Pattern*>::iterator I = Patterns.begin(), + E = Patterns.end(); I != E; ++I) + if (I->second->isResolved()) + DEBUG(std::cerr << " " << *I->second << "\n"); + + CalculateComputableValues(); + + EmitSourceFileHeader("Instruction Selector for the " + Target.getName() + + " target", OS); + OS << "#include \"llvm/CodeGen/MachineInstrBuilder.h\"\n"; + + // Output the slot number enums... + OS << "\nenum { // Slot numbers...\n" + << " LastBuiltinSlot = ISD::NumBuiltinSlots-1, // Start numbering here\n"; + for (PatternOrganizer::iterator I = ComputableValues.begin(), + E = ComputableValues.end(); I != E; ++I) + OS << " " << I->first << "_Slot,\n"; + OS << " NumSlots\n};\n\n// Reduction value typedefs...\n"; + + // Output the reduction value typedefs... + for (PatternOrganizer::iterator I = ComputableValues.begin(), + E = ComputableValues.end(); I != E; ++I) { + + OS << "typedef ReducedValue<unsigned, " << I->first + << "_Slot> ReducedValue_" << I->first << ";\n"; + } + + // Output the pattern enums... + OS << "\n\n" + << "enum { // Patterns...\n" + << " NotComputed = 0,\n" + << " NoMatchPattern, \n"; + for (PatternOrganizer::iterator I = ComputableValues.begin(), + E = ComputableValues.end(); I != E; ++I) { + OS << " // " << I->first << " patterns...\n"; + for (PatternOrganizer::NodesForSlot::iterator J = I->second.begin(), + E = I->second.end(); J != E; ++J) + for (unsigned i = 0, e = J->second.size(); i != e; ++i) + OS << " " << J->second[i]->getRecord()->getName() << "_Pattern,\n"; + } + OS << "};\n\n"; + + //===--------------------------------------------------------------------===// + // Emit the class definition... + // + OS << "namespace {\n" + << " class " << Target.getName() << "ISel {\n" + << " SelectionDAG &DAG;\n" + << " public:\n" + << " X86ISel(SelectionDAG &D) : DAG(D) {}\n" + << " void generateCode();\n" + << " private:\n" + << " unsigned makeAnotherReg(const TargetRegisterClass *RC) {\n" + << " return DAG.getMachineFunction().getSSARegMap()->createVirt" + "ualRegister(RC);\n" + << " }\n\n" + << " // DAG matching methods for classes... all of these methods" + " return the cost\n" + << " // of producing a value of the specified class and type, which" + " also gets\n" + << " // added to the DAG node.\n"; + + // Output all of the matching prototypes for slots... + for (PatternOrganizer::iterator I = ComputableValues.begin(), + E = ComputableValues.end(); I != E; ++I) + OS << " unsigned Match_" << I->first << "(SelectionDAGNode *N);\n"; + OS << "\n // DAG matching methods for DAG nodes...\n"; + + // Output all of the matching prototypes for slot/node pairs + for (PatternOrganizer::iterator I = ComputableValues.begin(), + E = ComputableValues.end(); I != E; ++I) + for (PatternOrganizer::NodesForSlot::iterator J = I->second.begin(), + E = I->second.end(); J != E; ++J) + OS << " unsigned Match_" << I->first << "_" << getNodeName(J->first) + << "(SelectionDAGNode *N);\n"; + + // Output all of the dag reduction methods prototypes... + OS << "\n // DAG reduction methods...\n"; + for (PatternOrganizer::iterator I = ComputableValues.begin(), + E = ComputableValues.end(); I != E; ++I) + OS << " ReducedValue_" << I->first << " *Reduce_" << I->first + << "(SelectionDAGNode *N,\n" << std::string(27+2*I->first.size(), ' ') + << "MachineBasicBlock *MBB);\n"; + OS << " };\n}\n\n"; + + // Emit the generateCode entry-point... + OS << "void X86ISel::generateCode() {\n" + << " SelectionDAGNode *Root = DAG.getRoot();\n" + << " assert(Root->getValueType() == MVT::isVoid && " + "\"Root of DAG produces value??\");\n\n" + << " std::cerr << \"\\n\";\n" + << " unsigned Cost = Match_Void_void(Root);\n" + << " if (Cost >= ~0U >> 1) {\n" + << " std::cerr << \"Match failed!\\n\";\n" + << " Root->dump();\n" + << " abort();\n" + << " }\n\n" + << " std::cerr << \"Total DAG Cost: \" << Cost << \"\\n\\n\";\n\n" + << " Reduce_Void_void(Root, 0);\n" + << "}\n\n" + << "//===" << std::string(70, '-') << "===//\n" + << "// Matching methods...\n" + << "//\n\n"; + + //===--------------------------------------------------------------------===// + // Emit all of the matcher methods... + // + for (PatternOrganizer::iterator I = ComputableValues.begin(), + E = ComputableValues.end(); I != E; ++I) { + const std::string &SlotName = I->first; + OS << "unsigned " << Target.getName() << "ISel::Match_" << SlotName + << "(SelectionDAGNode *N) {\n" + << " assert(N->getValueType() == MVT::" + << getEnumName((*I->second.begin()).second[0]->getTree()->getType()) + << ");\n" << " // If we already have a cost available for " << SlotName + << " use it!\n" + << " if (N->getPatternFor(" << SlotName << "_Slot))\n" + << " return N->getCostFor(" << SlotName << "_Slot);\n\n" + << " unsigned Cost;\n" + << " switch (N->getNodeType()) {\n" + << " default: Cost = ~0U >> 1; // Match failed\n" + << " N->setPatternCostFor(" << SlotName << "_Slot, NoMatchPattern, Cost, NumSlots);\n" + << " break;\n"; + + for (PatternOrganizer::NodesForSlot::iterator J = I->second.begin(), + E = I->second.end(); J != E; ++J) + if (!J->first->isSubClassOf("Nonterminal")) + OS << " case ISD::" << getNodeName(J->first) << ":\tCost = Match_" + << SlotName << "_" << getNodeName(J->first) << "(N); break;\n"; + OS << " }\n"; // End of the switch statement + + // Emit any patterns which have a nonterminal leaf as the RHS. These may + // match multiple root nodes, so they cannot be handled with the switch... + for (PatternOrganizer::NodesForSlot::iterator J = I->second.begin(), + E = I->second.end(); J != E; ++J) + if (J->first->isSubClassOf("Nonterminal")) { + OS << " unsigned " << J->first->getName() << "_Cost = Match_" + << getNodeName(J->first) << "(N);\n" + << " if (" << getNodeName(J->first) << "_Cost < Cost) Cost = " + << getNodeName(J->first) << "_Cost;\n"; + } + + OS << " return Cost;\n}\n\n"; + + for (PatternOrganizer::NodesForSlot::iterator J = I->second.begin(), + E = I->second.end(); J != E; ++J) { + Record *Operator = J->first; + bool isNonterm = Operator->isSubClassOf("Nonterminal"); + if (!isNonterm) { + OS << "unsigned " << Target.getName() << "ISel::Match_"; + if (!isNonterm) OS << SlotName << "_"; + OS << getNodeName(Operator) << "(SelectionDAGNode *N) {\n" + << " unsigned Pattern = NoMatchPattern;\n" + << " unsigned MinCost = ~0U >> 1;\n"; + + std::vector<std::pair<Pattern*, TreePatternNode*> > Patterns; + for (unsigned i = 0, e = J->second.size(); i != e; ++i) + Patterns.push_back(std::make_pair(J->second[i], + J->second[i]->getTree())); + EmitMatchCosters(OS, Patterns, "N", 2); + + OS << "\n N->setPatternCostFor(" << SlotName + << "_Slot, Pattern, MinCost, NumSlots);\n" + << " return MinCost;\n" + << "}\n"; + } + } + } + + //===--------------------------------------------------------------------===// + // Emit all of the reducer methods... + // + OS << "\n\n//===" << std::string(70, '-') << "===//\n" + << "// Reducer methods...\n" + << "//\n"; + + for (PatternOrganizer::iterator I = ComputableValues.begin(), + E = ComputableValues.end(); I != E; ++I) { + const std::string &SlotName = I->first; + OS << "ReducedValue_" << SlotName << " *" << Target.getName() + << "ISel::Reduce_" << SlotName + << "(SelectionDAGNode *N, MachineBasicBlock *MBB) {\n" + << " ReducedValue_" << SlotName << " *Val = N->hasValue<ReducedValue_" + << SlotName << ">(" << SlotName << "_Slot);\n" + << " if (Val) return Val;\n" + << " if (N->getBB()) MBB = N->getBB();\n\n" + << " switch (N->getPatternFor(" << SlotName << "_Slot)) {\n"; + + // Loop over all of the patterns that can produce a value for this slot... + PatternOrganizer::NodesForSlot &NodesForSlot = I->second; + for (PatternOrganizer::NodesForSlot::iterator J = NodesForSlot.begin(), + E = NodesForSlot.end(); J != E; ++J) + for (unsigned i = 0, e = J->second.size(); i != e; ++i) { + Pattern *P = J->second[i]; + OS << " case " << P->getRecord()->getName() << "_Pattern: {\n" + << " // " << *P << "\n"; + // Loop over the operands, reducing them... + std::vector<std::pair<TreePatternNode*, std::string> > Operands; + ReduceAllOperands(P->getTree(), "N", Operands, OS); + + // Now that we have reduced all of our operands, and have the values + // that reduction produces, perform the reduction action for this + // pattern. + std::string Result; + + // If the pattern produces a register result, generate a new register + // now. + if (Record *R = P->getResult()) { + assert(R->isSubClassOf("RegisterClass") && + "Only handle register class results so far!"); + OS << " unsigned NewReg = makeAnotherReg(" << Target.getName() + << "::" << R->getName() << "RegisterClass);\n"; + Result = "NewReg"; + DEBUG(OS << " std::cerr << \"%reg\" << NewReg << \" =\t\";\n"); + } else { + DEBUG(OS << " std::cerr << \"\t\t\";\n"); + Result = "0"; + } + + // Print out the pattern that matched... + DEBUG(OS << " std::cerr << \" " << P->getRecord()->getName() <<'"'); + DEBUG(for (unsigned i = 0, e = Operands.size(); i != e; ++i) + if (Operands[i].first->isLeaf()) { + Record *RV = Operands[i].first->getValueRecord(); + assert(RV->isSubClassOf("RegisterClass") && + "Only handles registers here so far!"); + OS << " << \" %reg\" << " << Operands[i].second + << "->Val"; + } else { + OS << " << ' ' << " << Operands[i].second + << "->Val"; + }); + DEBUG(OS << " << \"\\n\";\n"); + + // Generate the reduction code appropriate to the particular type of + // pattern that this is... + switch (P->getPatternType()) { + case Pattern::Instruction: + // Instruction patterns just emit a single MachineInstr, using BuildMI + OS << " BuildMI(MBB, " << Target.getName() << "::" + << P->getRecord()->getName() << ", " << Operands.size(); + if (P->getResult()) OS << ", NewReg"; + OS << ")"; + + for (unsigned i = 0, e = Operands.size(); i != e; ++i) { + TreePatternNode *Op = Operands[i].first; + if (Op->isLeaf()) { + Record *RV = Op->getValueRecord(); + assert(RV->isSubClassOf("RegisterClass") && + "Only handles registers here so far!"); + OS << ".addReg(" << Operands[i].second << "->Val)"; + } else if (Op->getOperator()->getName() == "imm") { + OS << ".addZImm(" << Operands[i].second << "->Val)"; + } else if (Op->getOperator()->getName() == "basicblock") { + OS << ".addMBB(" << Operands[i].second << "->Val)"; + } else { + assert(0 && "Unknown value type!"); + } + } + OS << ";\n"; + break; + case Pattern::Expander: { + // Expander patterns emit one machine instr for each instruction in + // the list of instructions expanded to. + ListInit *Insts = P->getRecord()->getValueAsListInit("Result"); + for (unsigned IN = 0, e = Insts->getSize(); IN != e; ++IN) { + DagInit *DIInst = dynamic_cast<DagInit*>(Insts->getElement(IN)); + if (!DIInst) P->error("Result list must contain instructions!"); + Record *InstRec = DIInst->getNodeType(); + Pattern *InstPat = getPattern(InstRec); + if (!InstPat || InstPat->getPatternType() != Pattern::Instruction) + P->error("Instruction list must contain Instruction patterns!"); + + bool hasResult = InstPat->getResult() != 0; + if (InstPat->getNumArgs() != DIInst->getNumArgs()-hasResult) { + P->error("Incorrect number of arguments specified for inst '" + + InstPat->getRecord()->getName() + "' in result list!"); + } + + // Start emission of the instruction... + OS << " BuildMI(MBB, " << Target.getName() << "::" + << InstRec->getName() << ", " + << DIInst->getNumArgs()-hasResult; + // Emit register result if necessary.. + if (hasResult) { + std::string ArgNameVal = + getArgName(P, DIInst->getArgName(0), Operands); + PrintExpanderOperand(DIInst->getArg(0), ArgNameVal, + InstPat->getResultNode(), P, false, + OS << ", "); + } + OS << ")"; + + for (unsigned i = hasResult, e = DIInst->getNumArgs(); i != e; ++i){ + std::string ArgNameVal = + getArgName(P, DIInst->getArgName(i), Operands); + + PrintExpanderOperand(DIInst->getArg(i), ArgNameVal, + InstPat->getArg(i-hasResult), P, true, OS); + } + + OS << ";\n"; + } + break; + } + default: + assert(0 && "Reduction of this type of pattern not implemented!"); + } + + OS << " Val = new ReducedValue_" << SlotName << "(" << Result<<");\n" + << " break;\n" + << " }\n"; + } + + + OS << " default: assert(0 && \"Unknown " << SlotName << " pattern!\");\n" + << " }\n\n N->addValue(Val); // Do not ever recalculate this\n" + << " return Val;\n}\n\n"; + } +} + diff --git a/llvm/utils/TableGen/InstrSelectorEmitter.h b/llvm/utils/TableGen/InstrSelectorEmitter.h new file mode 100644 index 00000000000..922aa79dfa1 --- /dev/null +++ b/llvm/utils/TableGen/InstrSelectorEmitter.h @@ -0,0 +1,387 @@ +//===- InstrInfoEmitter.h - Generate a Instruction Set Desc. ----*- C++ -*-===// +// +// This tablegen backend is responsible for emitting a description of the target +// instruction set for the code generator. +// +//===----------------------------------------------------------------------===// + +#ifndef INSTRSELECTOR_EMITTER_H +#define INSTRSELECTOR_EMITTER_H + +#include "TableGenBackend.h" +#include "CodeGenWrappers.h" +#include <vector> +#include <map> +#include <cassert> + +class DagInit; +class Init; +class InstrSelectorEmitter; + +/// NodeType - Represents Information parsed from the DagNode entries. +/// +struct NodeType { + enum ArgResultTypes { + Any, // No constraint on type + Val, // A non-void type + Arg0, // Value matches the type of Arg0 + Arg1, // Value matches the type of Arg1 + Ptr, // Tree node is the type of the target pointer + I8, // Always bool + Void, // Tree node always returns void + }; + + ArgResultTypes ResultType; + std::vector<ArgResultTypes> ArgTypes; + + NodeType(ArgResultTypes RT, std::vector<ArgResultTypes> &AT) : ResultType(RT){ + AT.swap(ArgTypes); + } + + NodeType() : ResultType(Val) {} + NodeType(const NodeType &N) : ResultType(N.ResultType), ArgTypes(N.ArgTypes){} + + static ArgResultTypes Translate(Record *R); +}; + + + +/// TreePatternNode - Represent a node of the tree patterns. +/// +class TreePatternNode { + /// Operator - The operation that this node represents... this is null if this + /// is a leaf. + Record *Operator; + + /// Type - The inferred value type... + /// + MVT::ValueType Type; + + /// Children - If this is not a leaf (Operator != 0), this is the subtrees + /// that we contain. + std::vector<std::pair<TreePatternNode*, std::string> > Children; + + /// Value - If this node is a leaf, this indicates what the thing is. + /// + Init *Value; +public: + TreePatternNode(Record *o, const std::vector<std::pair<TreePatternNode*, + std::string> > &c) + : Operator(o), Type(MVT::Other), Children(c), Value(0) {} + TreePatternNode(Init *V) : Operator(0), Type(MVT::Other), Value(V) {} + + Record *getOperator() const { + assert(Operator && "This is a leaf node!"); + return Operator; + } + MVT::ValueType getType() const { return Type; } + void setType(MVT::ValueType T) { Type = T; } + + bool isLeaf() const { return Operator == 0; } + + unsigned getNumChildren() const { return Children.size(); } + TreePatternNode *getChild(unsigned c) const { + assert(Operator != 0 && "This is a leaf node!"); + assert(c < Children.size() && "Child access out of range!"); + return Children[c].first; + } + const std::string &getChildName(unsigned c) const { + assert(Operator != 0 && "This is a leaf node!"); + assert(c < Children.size() && "Child access out of range!"); + return Children[c].second; + } + + Init *getValue() const { + assert(Operator == 0 && "This is not a leaf node!"); + return Value; + } + + /// getValueRecord - Returns the value of this tree node as a record. For now + /// we only allow DefInit's as our leaf values, so this is used. + Record *getValueRecord() const; + + /// clone - Make a copy of this tree and all of its children. + /// + TreePatternNode *clone() const; + + void dump() const; + + /// InstantiateNonterminals - If this pattern refers to any nonterminals which + /// are not themselves completely resolved, clone the nonterminal and resolve + /// it with the using context we provide. + void InstantiateNonterminals(InstrSelectorEmitter &ISE); + + /// 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(MVT::ValueType VT, const std::string &RecName); +}; + +std::ostream &operator<<(std::ostream &OS, const TreePatternNode &N); + + + +/// Pattern - Represent a pattern of one form or another. Currently, three +/// types of patterns are possible: Instruction's, Nonterminals, and Expanders. +/// +struct Pattern { + enum PatternType { + Nonterminal, Instruction, Expander + }; +private: + /// PTy - The type of pattern this is. + /// + PatternType PTy; + + /// Tree - The tree pattern which corresponds to this pattern. Note that if + /// there was a (set) node on the outside level that it has been stripped off. + /// + TreePatternNode *Tree; + + /// Result - If this is an instruction or expander pattern, this is the + /// register result, specified with a (set) in the pattern. + /// + std::string ResultName; // The name of the result value... + TreePatternNode *ResultNode; // The leaf node for the result register... + + /// TheRecord - The actual TableGen record corresponding to this pattern. + /// + Record *TheRecord; + + /// Resolved - This is true of the pattern is useful in practice. In + /// particular, some non-terminals will have non-resolvable types. When a + /// user of the non-terminal is later found, they will have inferred a type + /// for the result of the non-terminal, which cause a clone of an unresolved + /// nonterminal to be made which is "resolved". + /// + bool Resolved; + + /// Args - This is a list of all of the arguments to this pattern, which are + /// the non-void leaf nodes in this pattern. + std::vector<std::pair<TreePatternNode*, std::string> > Args; + + /// ISE - the instruction selector emitter coordinating this madness. + /// + InstrSelectorEmitter &ISE; +public: + + /// Pattern constructor - Parse the specified DagInitializer into the current + /// record. + Pattern(PatternType pty, DagInit *RawPat, Record *TheRec, + InstrSelectorEmitter &ise); + + /// Pattern - Constructor used for cloning nonterminal patterns + Pattern(TreePatternNode *tree, Record *rec, bool res, + InstrSelectorEmitter &ise) + : PTy(Nonterminal), Tree(tree), ResultNode(0), TheRecord(rec), + Resolved(res), ISE(ise) { + calculateArgs(Tree, ""); + } + + /// getPatternType - Return what flavor of Record this pattern originated from + /// + PatternType getPatternType() const { return PTy; } + + /// getTree - Return the tree pattern which corresponds to this pattern. + /// + TreePatternNode *getTree() const { return Tree; } + + Record *getResult() const { + return ResultNode ? ResultNode->getValueRecord() : 0; + } + const std::string &getResultName() const { return ResultName; } + TreePatternNode *getResultNode() const { return ResultNode; } + + /// getRecord - Return the actual TableGen record corresponding to this + /// pattern. + /// + Record *getRecord() const { return TheRecord; } + + unsigned getNumArgs() const { return Args.size(); } + TreePatternNode *getArg(unsigned i) const { + assert(i < Args.size() && "Argument reference out of range!"); + return Args[i].first; + } + Record *getArgRec(unsigned i) const { + return getArg(i)->getValueRecord(); + } + Init *getArgVal(unsigned i) const { + return getArg(i)->getValue(); + } + const std::string &getArgName(unsigned i) const { + assert(i < Args.size() && "Argument reference out of range!"); + return Args[i].second; + } + + bool isResolved() const { return Resolved; } + + /// InferAllTypes - Runs the type inference engine on the current pattern, + /// stopping when nothing can be inferred, then updating the Resolved field. + void InferAllTypes(); + + /// InstantiateNonterminals - If this pattern refers to any nonterminals which + /// are not themselves completely resolved, clone the nonterminal and resolve + /// it with the using context we provide. + void InstantiateNonterminals() { + Tree->InstantiateNonterminals(ISE); + } + + /// clone - This method is used to make an exact copy of the current pattern, + /// then change the "TheRecord" instance variable to the specified record. + /// + Pattern *clone(Record *R) const; + + /// error - Throw an exception, prefixing it with information about this + /// pattern. + void error(const std::string &Msg) const; + + /// getSlotName - If this is a leaf node, return the slot name that the + /// operand will update. + std::string getSlotName() const; + static std::string getSlotName(Record *R); + + void dump() const; + +private: + void calculateArgs(TreePatternNode *N, const std::string &Name); + MVT::ValueType getIntrinsicType(Record *R) const; + TreePatternNode *ParseTreePattern(DagInit *DI); + bool InferTypes(TreePatternNode *N, bool &MadeChange); +}; + +std::ostream &operator<<(std::ostream &OS, const Pattern &P); + + +/// PatternOrganizer - This class represents all of the patterns which are +/// useful for the instruction selector, neatly catagorized in a hierarchical +/// structure. +struct PatternOrganizer { + /// PatternsForNode - The list of patterns which can produce a value of a + /// particular slot type, given a particular root node in the tree. All of + /// the patterns in this vector produce the same value type and have the same + /// root DAG node. + typedef std::vector<Pattern*> PatternsForNode; + + /// NodesForSlot - This map keeps track of all of the root DAG nodes which can + /// lead to the production of a value for this slot. All of the patterns in + /// this data structure produces values of the same slot. + typedef std::map<Record*, PatternsForNode> NodesForSlot; + + /// AllPatterns - This data structure contains all patterns in the instruction + /// selector. + std::map<std::string, NodesForSlot> AllPatterns; + + // Forwarding functions... + typedef std::map<std::string, NodesForSlot>::iterator iterator; + iterator begin() { return AllPatterns.begin(); } + iterator end() { return AllPatterns.end(); } + + + /// addPattern - Add the specified pattern to the appropriate location in the + /// collection. + void addPattern(Pattern *P); +}; + + +/// InstrSelectorEmitter - The top-level class which coordinates construction +/// and emission of the instruction selector. +/// +class InstrSelectorEmitter : public TableGenBackend { + RecordKeeper &Records; + CodeGenTarget Target; + + std::map<Record*, NodeType> NodeTypes; + + /// Patterns - a list of all of the patterns defined by the target description + /// + std::map<Record*, Pattern*> Patterns; + + /// InstantiatedNTs - A data structure to keep track of which nonterminals + /// have been instantiated already... + /// + std::map<std::pair<Pattern*,MVT::ValueType>, Record*> InstantiatedNTs; + + /// ComputableValues - This map indicates which patterns can be used to + /// generate a value that is used by the selector. The keys of this map + /// implicitly define the values that are used by the selector. + /// + PatternOrganizer ComputableValues; + +public: + InstrSelectorEmitter(RecordKeeper &R) : Records(R) {} + + // run - Output the instruction set description, returning true on failure. + void run(std::ostream &OS); + + const CodeGenTarget &getTarget() const { return Target; } + std::map<Record*, NodeType> &getNodeTypes() { return NodeTypes; } + const NodeType &getNodeType(Record *R) const { + std::map<Record*, NodeType>::const_iterator I = NodeTypes.find(R); + assert(I != NodeTypes.end() && "Unknown node type!"); + return I->second; + } + + /// getPattern - return the pattern corresponding to the specified record, or + /// null if there is none. + Pattern *getPattern(Record *R) const { + std::map<Record*, Pattern*>::const_iterator I = Patterns.find(R); + return I != Patterns.end() ? I->second : 0; + } + + /// ReadNonterminal - This method parses the specified record as a + /// nonterminal, but only if it hasn't been read in already. + Pattern *ReadNonterminal(Record *R); + + /// InstantiateNonterminal - This method takes the nonterminal specified by + /// NT, which should not be completely resolved, clones it, applies ResultTy + /// to its root, then runs the type inference stuff on it. This should + /// produce a newly resolved nonterminal, which we make a record for and + /// return. To be extra fancy and efficient, this only makes one clone for + /// each type it is instantiated with. + Record *InstantiateNonterminal(Pattern *NT, MVT::ValueType ResultTy); + +private: + // ReadNodeTypes - Read in all of the node types in the current RecordKeeper, + // turning them into the more accessible NodeTypes data structure. + void ReadNodeTypes(); + + // ReadNonTerminals - Read in all nonterminals and incorporate them into our + // pattern database. + void ReadNonterminals(); + + // ReadInstructionPatterns - Read in all subclasses of Instruction, and + // process those with a useful Pattern field. + void ReadInstructionPatterns(); + + // ReadExpanderPatterns - Read in all of the expanded patterns. + void ReadExpanderPatterns(); + + // InstantiateNonterminals - Instantiate any unresolved nonterminals with + // information from the context that they are used in. + void InstantiateNonterminals(); + + // CalculateComputableValues - Fill in the ComputableValues map through + // analysis of the patterns we are playing with. + void CalculateComputableValues(); + + // EmitMatchCosters - Given a list of patterns, which all have the same root + // pattern operator, emit an efficient decision tree to decide which one to + // pick. This is structured this way to avoid reevaluations of non-obvious + // subexpressions. + void EmitMatchCosters(std::ostream &OS, + const std::vector<std::pair<Pattern*, TreePatternNode*> > &Patterns, + const std::string &VarPrefix, unsigned Indent); + + /// PrintExpanderOperand - Print out Arg as part of the instruction emission + /// process for the expander pattern P. This argument may be referencing some + /// values defined in P, or may just be physical register references or + /// something like that. If PrintArg is true, we are printing out arguments + /// to the BuildMI call. If it is false, we are printing the result register + /// name. + void PrintExpanderOperand(Init *Arg, const std::string &NameVar, + TreePatternNode *ArgDecl, Pattern *P, + bool PrintArg, std::ostream &OS); +}; + +#endif diff --git a/llvm/utils/TableGen/Makefile b/llvm/utils/TableGen/Makefile new file mode 100644 index 00000000000..89a956d9dde --- /dev/null +++ b/llvm/utils/TableGen/Makefile @@ -0,0 +1,18 @@ +LEVEL = ../.. +TOOLNAME = tblgen +USEDLIBS = support.a + +.PRECIOUS: FileLexer.cpp FileParser.cpp + +include $(LEVEL)/Makefile.common + +# +# Make the source file depend on the header file. In this way, dependencies +# (which depend on the source file) won't get generated until bison is done +# generating the C source and header files for the parser. +# +FileLexer.cpp: FileParser.h + +clean:: + -rm -f FileParser.cpp FileParser.h FileLexer.cpp CommandLine.cpp + -rm -f FileParser.output diff --git a/llvm/utils/TableGen/Record.cpp b/llvm/utils/TableGen/Record.cpp new file mode 100644 index 00000000000..384005081e7 --- /dev/null +++ b/llvm/utils/TableGen/Record.cpp @@ -0,0 +1,676 @@ +//===- Record.cpp - Record implementation ---------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +#include "Record.h" + +//===----------------------------------------------------------------------===// +// Type implementations +//===----------------------------------------------------------------------===// + +void RecTy::dump() const { print(std::cerr); } + +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) { + int 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; +} + +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) { + int Value = II->getValue(); + // Make sure this bitfield is large enough to hold the integer value... + if (Value >= 0) { + if (Value & ~((1 << Size)-1)) + return 0; + } else { + if ((Value >> Size) != -1 || ((Value & (1 << Size-1)) == 0)) + return 0; + } + + BitsInit *Ret = new BitsInit(Size); + for (unsigned i = 0; i != Size; ++i) + Ret->setBit(i, new BitInit(Value & (1 << 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) { + int 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(TypedInit *TI) { + if (dynamic_cast<StringRecTy*>(TI->getType())) + return TI; // Accept variable if already of the right type! + return 0; +} + +void ListRecTy::print(std::ostream &OS) const { + OS << "list<" << *Ty << ">"; +} + +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; +} + + +void RecordRecTy::print(std::ostream &OS) const { + OS << 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(std::cerr); } + +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; +} + +void BitsInit::print(std::ostream &OS) const { + //if (!printInHex(OS)) return; + //if (!printAsVariable(OS)) return; + //if (!printAsUnset(OS)) return; + + OS << "{ "; + for (unsigned i = 0, e = getNumBits(); i != e; ++i) { + if (i) OS << ", "; + if (Init *Bit = getBit(e-i-1)) + Bit->print(OS); + else + OS << "*"; + } + OS << " }"; +} + +bool BitsInit::printInHex(std::ostream &OS) const { + // First, attempt to convert the value into an integer value... + int 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) { + 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); + Changed |= B != CurBit; + } while (B != CurBit); + New->setBit(i, CurBit); + } + + if (Changed) + return New; + delete New; + return this; +} + +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] >= 32) { + delete BI; + return 0; + } + BI->setBit(i, new BitInit(Value & (1 << Bits[i]))); + } + return BI; +} + +void ListInit::print(std::ostream &OS) const { + OS << "["; + for (unsigned i = 0, e = Values.size(); i != e; ++i) { + if (i) OS << ", "; + OS << *Values[i]; + } + OS << "]"; +} + +Init *VarInit::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 *VarInit::resolveBitReference(Record &R, unsigned Bit) { + if (R.isTemplateArg(getName())) + return this; + + 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 this; +} + +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 (RecordRecTy *RTy = dynamic_cast<RecordRecTy*>(getType())) + if (const RecordVal *RV = R.getValue(VarName)) + if (Init *I = RV->getValue()->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) { + if (RecordVal *Val = R.getValue(VarName)) + if (!dynamic_cast<UnsetInit*>(Val->getValue())) + return Val->getValue(); + return this; +} + + +Init *VarBitInit::resolveReferences(Record &R) { + Init *I = getVariable()->resolveBitReference(R, getBitNum()); + if (I != getVariable()) + return I; + return this; +} + +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(); +} + + +void DefInit::print(std::ostream &OS) const { + OS << Def->getName(); +} + +Init *FieldInit::convertInitializerBitRange(const std::vector<unsigned> &Bits) { + BitsRecTy *T = dynamic_cast<BitsRecTy*>(getType()); + if (T == 0) return 0; // Cannot subscript a non-bits field... + 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 *FieldInit::resolveBitReference(Record &R, unsigned Bit) { + Init *BitsVal = Rec->getFieldInit(R, FieldName); + if (BitsVal) + 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 this; +} + +Init *FieldInit::resolveReferences(Record &R) { + Init *BitsVal = Rec->getFieldInit(R, FieldName); + if (BitsVal) { + Init *BVR = BitsVal->resolveReferences(R); + return BVR->isComplete() ? BVR : this; + } + return this; +} + + +void DagInit::print(std::ostream &OS) const { + OS << "(" << NodeTypeDef->getName(); + if (Args.size()) { + OS << " " << *Args[0]; + if (!ArgNames[0].empty()) OS << ":$" << ArgNames[0]; + for (unsigned i = 1, e = Args.size(); i != e; ++i) { + OS << ", " << *Args[i]; + if (!ArgNames[i].empty()) OS << ":$" << ArgNames[i]; + } + } + OS << ")"; +} + + +//===----------------------------------------------------------------------===// +// 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 { std::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"; +} + +// resolveReferences - If there are any field references that refer to fields +// that have been filled in, we can propagate the values now. +// +void Record::resolveReferences() { + for (unsigned i = 0, e = Values.size(); i != e; ++i) + Values[i].setValue(Values[i].getValue()->resolveReferences(*this)); +} + +void Record::dump() const { std::cerr << *this; } + +std::ostream &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!"; +} + +/// getValueAsInt - This method looks up the specified field and returns its +/// value as an int, throwing an exception if the field does not exist or if +/// the value is not the right type. +/// +int 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 a list initializer!"; +} + +/// 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 list 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!"; +} + + +void RecordKeeper::dump() const { std::cerr << *this; } + +std::ostream &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/llvm/utils/TableGen/Record.h b/llvm/utils/TableGen/Record.h new file mode 100644 index 00000000000..4a2fa057cfd --- /dev/null +++ b/llvm/utils/TableGen/Record.h @@ -0,0 +1,849 @@ +//===- Record.h - Classes to represent Table Records ------------*- C++ -*-===// +// +// 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 <string> +#include <vector> +#include <map> +#include <iostream> +#include <cassert> + +// RecTy subclasses... +class BitRecTy; +class BitsRecTy; +class IntRecTy; +class StringRecTy; +class ListRecTy; +class CodeRecTy; +class DagRecTy; +class RecordRecTy; + +// Init subclasses... +class Init; +class UnsetInit; +class BitInit; +class BitsInit; +class IntInit; +class StringInit; +class CodeInit; +class ListInit; +class DefInit; +class DagInit; +class TypedInit; +class VarInit; +class FieldInit; +class VarBitInit; + +// Other classes... +class Record; + +//===----------------------------------------------------------------------===// +// Type Classes +//===----------------------------------------------------------------------===// + +struct RecTy { + virtual ~RecTy() {} + + virtual void print(std::ostream &OS) const = 0; + 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( 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 +/// +struct BitRecTy : public RecTy { + Init *convertValue(UnsetInit *UI) { return (Init*)UI; } + Init *convertValue(BitInit *BI) { return (Init*)BI; } + Init *convertValue(BitsInit *BI); + Init *convertValue(IntInit *II); + Init *convertValue(TypedInit *VI); + Init *convertValue(VarBitInit *VB) { return (Init*)VB; } + + void print(std::ostream &OS) const { OS << "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; } +}; + + +/// BitsRecTy - 'bits<n>' - Represent a fixed number of bits +/// +class BitsRecTy : public RecTy { + unsigned Size; +public: + BitsRecTy(unsigned Sz) : Size(Sz) {} + + unsigned getNumBits() const { return Size; } + + Init *convertValue(UnsetInit *UI); + Init *convertValue(BitInit *UI); + Init *convertValue(BitsInit *BI); + Init *convertValue(IntInit *II); + Init *convertValue(TypedInit *VI); + + void print(std::ostream &OS) const { OS << "bits<" << Size << ">"; } + + bool typeIsConvertibleTo(const RecTy *RHS) const { + return RHS->baseClassOf(this); + } + virtual bool baseClassOf(const BitRecTy *RHS) const { return Size == 1; } + virtual bool baseClassOf(const IntRecTy *RHS) const { return true; } + virtual bool baseClassOf(const BitsRecTy *RHS) const { + return RHS->Size == Size; + } +}; + + +/// IntRecTy - 'int' - Represent an integer value of no particular size +/// +struct IntRecTy : public RecTy { + Init *convertValue(UnsetInit *UI) { return (Init*)UI; } + Init *convertValue(IntInit *II) { return (Init*)II; } + Init *convertValue(BitInit *BI); + Init *convertValue(BitsInit *BI); + Init *convertValue(TypedInit *TI); + + void print(std::ostream &OS) const { OS << "int"; } + + bool typeIsConvertibleTo(const RecTy *RHS) const { + return RHS->baseClassOf(this); + } + + virtual bool baseClassOf(const BitRecTy *RHS) const { return true; } + virtual bool baseClassOf(const IntRecTy *RHS) const { return true; } + virtual bool baseClassOf(const BitsRecTy *RHS) const { return true; } +}; + +/// StringRecTy - 'string' - Represent an string value +/// +struct StringRecTy : public RecTy { + Init *convertValue(UnsetInit *UI) { return (Init*)UI; } + Init *convertValue(StringInit *SI) { return (Init*)SI; } + Init *convertValue(TypedInit *TI); + void print(std::ostream &OS) const { OS << "string"; } + + bool typeIsConvertibleTo(const RecTy *RHS) const { + return RHS->baseClassOf(this); + } + + virtual bool baseClassOf(const StringRecTy *RHS) const { return true; } +}; + +/// ListRecTy - 'list<Ty>' - Represent a list of values, all of which must be of +/// the specified type. +/// +class ListRecTy : public RecTy { + RecTy *Ty; +public: + ListRecTy(RecTy *T) : Ty(T) {} + + RecTy *getElementType() const { return Ty; } + + Init *convertValue(UnsetInit *UI) { return (Init*)UI; } + Init *convertValue(ListInit *LI); + Init *convertValue(TypedInit *TI); + + void print(std::ostream &OS) const; + + bool typeIsConvertibleTo(const RecTy *RHS) const { + return RHS->baseClassOf(this); + } + + virtual bool baseClassOf(const ListRecTy *RHS) const { + return RHS->getElementType()->typeIsConvertibleTo(Ty); + } +}; + +/// CodeRecTy - 'code' - Represent an code fragment, function or method. +/// +struct CodeRecTy : public RecTy { + Init *convertValue(UnsetInit *UI) { return (Init*)UI; } + Init *convertValue( CodeInit *CI) { return (Init*)CI; } + Init *convertValue(TypedInit *TI); + + void print(std::ostream &OS) const { OS << "code"; } + + bool typeIsConvertibleTo(const RecTy *RHS) const { + return RHS->baseClassOf(this); + } + virtual bool baseClassOf(const CodeRecTy *RHS) const { return true; } +}; + +/// DagRecTy - 'dag' - Represent a dag fragment +/// +struct DagRecTy : public RecTy { + Init *convertValue(UnsetInit *UI) { return (Init*)UI; } + Init *convertValue( DagInit *CI) { return (Init*)CI; } + Init *convertValue(TypedInit *TI); + + void print(std::ostream &OS) const { OS << "dag"; } + + bool typeIsConvertibleTo(const RecTy *RHS) const { + return RHS->baseClassOf(this); + } + virtual bool baseClassOf(const DagRecTy *RHS) const { return true; } +}; + + +/// RecordRecTy - '<classname>' - Represent an instance of a class, such as: +/// (R32 X = EAX). +/// +class RecordRecTy : public RecTy { + Record *Rec; +public: + RecordRecTy(Record *R) : Rec(R) {} + + Record *getRecord() const { return Rec; } + + Init *convertValue(UnsetInit *UI) { return (Init*)UI; } + Init *convertValue( DefInit *DI); + Init *convertValue(TypedInit *VI); + + void print(std::ostream &OS) const; + + bool typeIsConvertibleTo(const RecTy *RHS) const { + return RHS->baseClassOf(this); + } + 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. + virtual void print(std::ostream &OS) 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; + } + + /// 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) { return this; } +}; + +inline std::ostream &operator<<(std::ostream &OS, const Init &I) { + I.print(OS); return OS; +} + + +/// UnsetInit - ? - Represents an uninitialized value +/// +struct UnsetInit : public Init { + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + + virtual bool isComplete() const { return false; } + virtual void print(std::ostream &OS) const { OS << "?"; } +}; + + +/// BitInit - true/false - Represent a concrete initializer for a bit. +/// +class BitInit : public Init { + bool Value; +public: + BitInit(bool V) : Value(V) {} + + bool getValue() const { return Value; } + + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + + virtual void print(std::ostream &OS) const { OS << (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: + 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 void print(std::ostream &OS) const; + + virtual Init *resolveReferences(Record &R); + + // 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 { + int Value; +public: + IntInit(int V) : Value(V) {} + + int getValue() const { return Value; } + + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + virtual Init *convertInitializerBitRange(const std::vector<unsigned> &Bits); + + virtual void print(std::ostream &OS) const { OS << Value; } +}; + + +/// StringInit - "foo" - Represent an initialization by a string value. +/// +class StringInit : public Init { + std::string Value; +public: + StringInit(const std::string &V) : Value(V) {} + + const std::string &getValue() const { return Value; } + + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + + virtual void print(std::ostream &OS) const { OS << "\"" << Value << "\""; } +}; + +/// CodeInit - "[{...}]" - Represent a code fragment. +/// +class CodeInit : public Init { + std::string Value; +public: + CodeInit(const std::string &V) : Value(V) {} + + const std::string getValue() const { return Value; } + + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + + virtual void print(std::ostream &OS) const { OS << "[{" << Value << "}]"; } +}; + +/// ListInit - [AL, AH, CL] - Represent a list of defs +/// +class ListInit : public Init { + std::vector<Init*> Values; +public: + ListInit(std::vector<Init*> &Vs) { + Values.swap(Vs); + } + + unsigned getSize() const { return Values.size(); } + Init *getElement(unsigned i) const { + assert(i < Values.size() && "List element index out of range!"); + return Values[i]; + } + + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + + virtual void print(std::ostream &OS) const; +}; + + +/// TypedInit - This is the common super-class of types that have a specific, +/// explicit, type. +/// +class TypedInit : public Init { + RecTy *Ty; +public: + TypedInit(RecTy *T) : Ty(T) {} + + RecTy *getType() const { return Ty; } + + /// 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 this. + /// + virtual Init *resolveBitReference(Record &R, unsigned Bit) = 0; +}; + +/// VarInit - 'Opcode' - Represent a reference to an entire variable object. +/// +class VarInit : public TypedInit { + std::string VarName; +public: + 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 *convertInitializerBitRange(const std::vector<unsigned> &Bits); + + virtual Init *resolveBitReference(Record &R, unsigned Bit); + + 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); + + virtual void print(std::ostream &OS) const { OS << 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 void print(std::ostream &OS) const { + TI->print(OS); OS << "{" << Bit << "}"; + } + virtual Init *resolveReferences(Record &R); +}; + + +/// DefInit - AL - Represent a reference to a 'def' in the description +/// +class DefInit : public Init { + Record *Def; +public: + DefInit(Record *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 void print(std::ostream &OS) const; +}; + + +/// 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 *convertInitializerBitRange(const std::vector<unsigned> &Bits); + + virtual Init *resolveBitReference(Record &R, unsigned Bit); + + virtual Init *resolveReferences(Record &R); + + virtual void print(std::ostream &OS) const { + Rec->print(OS); OS << "." << FieldName; + } +}; + +/// DagInit - (def a, b) - Represent a DAG tree value. DAG inits are required +/// to have Records for their first value, after that, any legal Init is +/// possible. +/// +class DagInit : public Init { + Record *NodeTypeDef; + std::vector<Init*> Args; + std::vector<std::string> ArgNames; +public: + DagInit(Record *D, const std::vector<std::pair<Init*, std::string> > &args) + : NodeTypeDef(D) { + 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); + } + } + + virtual Init *convertInitializerTo(RecTy *Ty) { + return Ty->convertValue(this); + } + + Record *getNodeType() const { return NodeTypeDef; } + + 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 void print(std::ostream &OS) const; +}; + +//===----------------------------------------------------------------------===// +// 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; +} + +struct Record { + const std::string Name; + std::vector<std::string> TemplateArgs; + std::vector<RecordVal> Values; + std::vector<Record*> SuperClasses; +public: + + Record(const std::string &N) : Name(N) {} + ~Record() {} + + const std::string &getName() const { return Name; } + 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(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(); + + 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; + + /// 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 int, throwing an exception if the field does not exist or if + /// the value is not the right type. + /// + int 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; +}; + +std::ostream &operator<<(std::ostream &OS, const Record &R); + +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)); + } + + //===--------------------------------------------------------------------===// + // 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; +}; + +std::ostream &operator<<(std::ostream &OS, const RecordKeeper &RK); + +extern RecordKeeper Records; + +#endif diff --git a/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/llvm/utils/TableGen/RegisterInfoEmitter.cpp new file mode 100644 index 00000000000..af3efe3a9c4 --- /dev/null +++ b/llvm/utils/TableGen/RegisterInfoEmitter.cpp @@ -0,0 +1,234 @@ +//===- RegisterInfoEmitter.cpp - Generate a Register File Desc. -*- C++ -*-===// +// +// 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 "CodeGenWrappers.h" +#include "Record.h" +#include "Support/StringExtras.h" +#include <set> + +// runEnums - Print out enum values for all of the registers. +void RegisterInfoEmitter::runEnums(std::ostream &OS) { + std::vector<Record*> Registers = Records.getAllDerivedDefinitions("Register"); + + if (Registers.size() == 0) + throw std::string("No 'Register' subclasses defined!"); + + std::string Namespace = Registers[0]->getValueAsString("Namespace"); + + EmitSourceFileHeader("Target Register Enum Values", OS); + + 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 << " };\n"; + if (!Namespace.empty()) + OS << "}\n"; +} + +void RegisterInfoEmitter::runHeader(std::ostream &OS) { + EmitSourceFileHeader("Register Information Header Fragment", OS); + const std::string &TargetName = CodeGenTarget().getName(); + std::string ClassName = TargetName + "GenRegisterInfo"; + + OS << "#include \"llvm/Target/MRegisterInfo.h\"\n\n"; + + OS << "struct " << ClassName << " : public MRegisterInfo {\n" + << " " << ClassName + << "(int CallFrameSetupOpcode = -1, int CallFrameDestroyOpcode = -1);\n" + << " const unsigned* getCalleeSaveRegs() const;\n" + << "};\n\n"; + + std::vector<Record*> RegisterClasses = + Records.getAllDerivedDefinitions("RegisterClass"); + + OS << "namespace " << TargetName << " { // Register classes\n"; + for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) { + if (RegisterClasses[i]->getValueAsBit("isDummyClass")) + continue; // Ignore dummies + + const std::string &Name = RegisterClasses[i]->getName(); + if (Name.size() < 9 || Name[9] != '.') // Ignore anonymous classes + OS << " extern TargetRegisterClass *" << Name << "RegisterClass;\n"; + } + OS << "} // end of namespace " << TargetName << "\n\n"; +} + +// RegisterInfoEmitter::run - Main register file description emitter. +// +void RegisterInfoEmitter::run(std::ostream &OS) { + EmitSourceFileHeader("Register Information Source Fragment", OS); + + // 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. + // + std::vector<Record*> RegisterClasses = + Records.getAllDerivedDefinitions("RegisterClass"); + + std::vector<Record*> Registers = Records.getAllDerivedDefinitions("Register"); + + std::set<Record*> RegistersFound; + std::vector<std::string> RegClassNames; + + // Loop over all of the register classes... emitting each one. + OS << "namespace { // Register classes...\n"; + + for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) { + Record *RC = RegisterClasses[rc]; + if (RC->getValueAsBit("isDummyClass")) continue; // Ignore dummies + + std::string Name = RC->getName(); + if (Name.size() > 9 && Name[9] == '.') { + static unsigned AnonCounter = 0; + Name = "AnonRegClass_"+utostr(AnonCounter++); + } + + RegClassNames.push_back(Name); + + // Emit the register list now... + OS << " // " << Name << " Register Class...\n const unsigned " << Name + << "[] = {\n "; + ListInit *RegList = RC->getValueAsListInit("MemberList"); + for (unsigned i = 0, e = RegList->getSize(); i != e; ++i) { + DefInit *RegDef = dynamic_cast<DefInit*>(RegList->getElement(i)); + if (!RegDef) throw "Register class member is not a record!"; + Record *Reg = RegDef->getDef(); + if (!Reg->isSubClassOf("Register")) + throw "Register Class member '" + Reg->getName() + + " does not derive from the Register class!"; + if (RegistersFound.count(Reg)) + throw "Register '" + Reg->getName() + + "' included in multiple register classes!"; + RegistersFound.insert(Reg); + OS << getQualifiedName(Reg) << ", "; + } + OS << "\n };\n\n"; + + OS << " struct " << Name << "Class : public TargetRegisterClass {\n" + << " " << Name << "Class() : TargetRegisterClass(" + << RC->getValueAsInt("Size")/8 << ", " << RC->getValueAsInt("Alignment") + << ", " << Name << ", " << Name << " + " << RegList->getSize() + << ") {}\n"; + + if (CodeInit *CI = dynamic_cast<CodeInit*>(RC->getValueInit("Methods"))) + OS << CI->getValue(); + else + throw "Expected 'code' fragment for 'Methods' value in register class '"+ + RC->getName() + "'!"; + + OS << " } " << Name << "Instance;\n\n"; + } + + OS << " const TargetRegisterClass* const RegisterClasses[] = {\n"; + for (unsigned i = 0, e = RegClassNames.size(); i != e; ++i) + OS << " &" << RegClassNames[i] << "Instance,\n"; + OS << " };\n"; + + // Emit register class aliases... + std::vector<Record*> RegisterAliasesRecs = + Records.getAllDerivedDefinitions("RegisterAliases"); + std::map<Record*, std::set<Record*> > RegisterAliases; + + for (unsigned i = 0, e = RegisterAliasesRecs.size(); i != e; ++i) { + Record *AS = RegisterAliasesRecs[i]; + Record *R = AS->getValueAsDef("Reg"); + ListInit *LI = AS->getValueAsListInit("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->getSize(); j != e; ++j) { + DefInit *Reg = dynamic_cast<DefInit*>(LI->getElement(j)); + if (!Reg) throw "ERROR: Alias list element is not a def!"; + if (RegisterAliases[R].count(Reg->getDef())) + std::cerr << "Warning: register alias between " << getQualifiedName(R) + << " and " << getQualifiedName(Reg->getDef()) + << " specified multiple times!\n"; + RegisterAliases[R].insert(Reg->getDef()); + + if (RegisterAliases[Reg->getDef()].count(R)) + std::cerr << "Warning: register alias between " << getQualifiedName(R) + << " and " << getQualifiedName(Reg->getDef()) + << " specified multiple times!\n"; + RegisterAliases[Reg->getDef()].insert(R); + } + } + + if (!RegisterAliases.empty()) + OS << "\n\n // Register Alias Sets...\n"; + + // Loop over all of the registers which have aliases, emitting the alias list + // to memory. + for (std::map<Record*, std::set<Record*> >::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"; + } + + OS << "\n const MRegisterDesc RegisterDescriptors[] = { // Descriptors\n"; + OS << " { \"NOREG\",\t0,\t\t0,\t0 },\n"; + // Now that register alias sets have been emitted, emit the register + // descriptors now. + for (unsigned i = 0, e = Registers.size(); i != e; ++i) { + Record *Reg = Registers[i]; + OS << " { \""; + if (!Reg->getValueAsString("Name").empty()) + OS << Reg->getValueAsString("Name"); + else + OS << Reg->getName(); + OS << "\",\t"; + if (RegisterAliases.count(Reg)) + OS << Reg->getName() << "_AliasSet,\t"; + else + OS << "0,\t\t"; + OS << "0, 0 },\n"; + } + OS << " };\n"; // End of register descriptors... + OS << "}\n\n"; // End of anonymous namespace... + + CodeGenTarget Target; + + OS << "namespace " << Target.getName() << " { // Register classes\n"; + for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) { + if (RegisterClasses[i]->getValueAsBit("isDummyClass")) + continue; // Ignore dummies + + const std::string &Name = RegisterClasses[i]->getName(); + if (Name.size() < 9 || Name[9] != '.') // Ignore anonymous classes + OS << " TargetRegisterClass *" << Name << "RegisterClass = &" + << Name << "Instance;\n"; + } + OS << "} // end of namespace " << Target.getName() << "\n\n"; + + + + std::string ClassName = Target.getName() + "GenRegisterInfo"; + + // Emit the constructor of the class... + OS << ClassName << "::" << ClassName + << "(int CallFrameSetupOpcode, int CallFrameDestroyOpcode)\n" + << " : MRegisterInfo(RegisterDescriptors, " << Registers.size()+1 + << ", RegisterClasses, RegisterClasses+" << RegClassNames.size() << ",\n " + << " CallFrameSetupOpcode, CallFrameDestroyOpcode) {}\n\n"; + + // Emit the getCalleeSaveRegs method... + OS << "const unsigned* " << ClassName << "::getCalleeSaveRegs() const {\n" + << " static const unsigned CalleeSaveRegs[] = {\n "; + + const std::vector<Record*> &CSR = Target.getCalleeSavedRegisters(); + for (unsigned i = 0, e = CSR.size(); i != e; ++i) + OS << getQualifiedName(CSR[i]) << ", "; + OS << " 0\n };\n return CalleeSaveRegs;\n}\n\n"; +} diff --git a/llvm/utils/TableGen/RegisterInfoEmitter.h b/llvm/utils/TableGen/RegisterInfoEmitter.h new file mode 100644 index 00000000000..65a03303cdd --- /dev/null +++ b/llvm/utils/TableGen/RegisterInfoEmitter.h @@ -0,0 +1,29 @@ +//===- RegisterInfoEmitter.h - Generate a Register File Desc. ---*- C++ -*-===// +// +// 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" + +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); +}; + +#endif diff --git a/llvm/utils/TableGen/TableGen.cpp b/llvm/utils/TableGen/TableGen.cpp new file mode 100644 index 00000000000..971ac9081aa --- /dev/null +++ b/llvm/utils/TableGen/TableGen.cpp @@ -0,0 +1,482 @@ +//===- TableGen.cpp - Top-Level TableGen implementation -------------------===// +// +// 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 "Support/CommandLine.h" +#include "Support/Signals.h" +#include "Support/FileUtilities.h" +#include "CodeEmitterGen.h" +#include "RegisterInfoEmitter.h" +#include "InstrInfoEmitter.h" +#include "InstrSelectorEmitter.h" +#include <algorithm> +#include <cstdio> +#include <fstream> + +enum ActionType { + PrintRecords, + GenEmitter, + GenRegisterEnums, GenRegister, GenRegisterHeader, + GenInstrEnums, GenInstrs, GenInstrSelector, + PrintEnums, + Parse, +}; + +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(GenInstrSelector, "gen-instr-selector", + "Generate an instruction selector"), + clEnumValN(PrintEnums, "print-enums", + "Print enum values for a class"), + clEnumValN(Parse, "parse", + "Interpret machine code (testing only)"), + 0)); + + 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::opt<std::string> + IncludeDir("I", cl::desc("Directory of include files"), + cl::value_desc("directory"), cl::init("")); +} + + +void ParseFile(const std::string &Filename, const std::string & IncludeDir); + +RecordKeeper Records; + +static Init *getBit(Record *R, unsigned BitNo) { + const std::vector<RecordVal> &V = R->getValues(); + for (unsigned i = 0, e = V.size(); i != e; ++i) + if (V[i].getPrefix()) { + assert(dynamic_cast<BitsInit*>(V[i].getValue()) && + "Can only handle fields of bits<> type!"); + BitsInit *I = (BitsInit*)V[i].getValue(); + if (BitNo < I->getNumBits()) + return I->getBit(BitNo); + BitNo -= I->getNumBits(); + } + + std::cerr << "Cannot find requested bit!\n"; + abort(); + return 0; +} + +static unsigned getNumBits(Record *R) { + const std::vector<RecordVal> &V = R->getValues(); + unsigned Num = 0; + for (unsigned i = 0, e = V.size(); i != e; ++i) + if (V[i].getPrefix()) { + assert(dynamic_cast<BitsInit*>(V[i].getValue()) && + "Can only handle fields of bits<> type!"); + Num += ((BitsInit*)V[i].getValue())->getNumBits(); + } + return Num; +} + +static bool BitsAreFixed(Record *I1, Record *I2, unsigned BitNo) { + return dynamic_cast<BitInit*>(getBit(I1, BitNo)) && + dynamic_cast<BitInit*>(getBit(I2, BitNo)); +} + +static bool BitsAreEqual(Record *I1, Record *I2, unsigned BitNo) { + BitInit *Bit1 = dynamic_cast<BitInit*>(getBit(I1, BitNo)); + BitInit *Bit2 = dynamic_cast<BitInit*>(getBit(I2, BitNo)); + + return Bit1 && Bit2 && Bit1->getValue() == Bit2->getValue(); +} + +static bool BitRangesEqual(Record *I1, Record *I2, + unsigned Start, unsigned End) { + for (unsigned i = Start; i != End; ++i) + if (!BitsAreEqual(I1, I2, i)) + return false; + return true; +} + +static unsigned getFirstFixedBit(Record *R, unsigned FirstFixedBit) { + // Look for the first bit of the pair that are required to be 0 or 1. + while (!dynamic_cast<BitInit*>(getBit(R, FirstFixedBit))) + ++FirstFixedBit; + return FirstFixedBit; +} + +static void FindInstDifferences(Record *I1, Record *I2, + unsigned FirstFixedBit, unsigned MaxBits, + unsigned &FirstVaryingBitOverall, + unsigned &LastFixedBitOverall) { + // Compare the first instruction to the rest of the instructions, looking for + // fields that differ. + // + unsigned FirstVaryingBit = FirstFixedBit; + while (FirstVaryingBit < MaxBits && BitsAreEqual(I1, I2, FirstVaryingBit)) + ++FirstVaryingBit; + + unsigned LastFixedBit = FirstVaryingBit; + while (LastFixedBit < MaxBits && BitsAreFixed(I1, I2, LastFixedBit)) + ++LastFixedBit; + + if (FirstVaryingBit < FirstVaryingBitOverall) + FirstVaryingBitOverall = FirstVaryingBit; + if (LastFixedBit < LastFixedBitOverall) + LastFixedBitOverall = LastFixedBit; +} + +static bool getBitValue(Record *R, unsigned BitNo) { + Init *I = getBit(R, BitNo); + assert(dynamic_cast<BitInit*>(I) && "Bit should be fixed!"); + return ((BitInit*)I)->getValue(); +} + +struct BitComparator { + unsigned BitBegin, BitEnd; + BitComparator(unsigned B, unsigned E) : BitBegin(B), BitEnd(E) {} + + bool operator()(Record *R1, Record *R2) { // Return true if R1 is less than R2 + for (unsigned i = BitBegin; i != BitEnd; ++i) { + bool V1 = getBitValue(R1, i), V2 = getBitValue(R2, i); + if (V1 < V2) + return true; + else if (V2 < V1) + return false; + } + return false; + } +}; + +static void PrintRange(std::vector<Record*>::iterator I, + std::vector<Record*>::iterator E) { + while (I != E) std::cerr << **I++; +} + +static bool getMemoryBit(unsigned char *M, unsigned i) { + return (M[i/8] & (1 << (i&7))) != 0; +} + +static unsigned getFirstFixedBitInSequence(std::vector<Record*>::iterator IB, + std::vector<Record*>::iterator IE, + unsigned StartBit) { + unsigned FirstFixedBit = 0; + for (std::vector<Record*>::iterator I = IB; I != IE; ++I) + FirstFixedBit = std::max(FirstFixedBit, getFirstFixedBit(*I, StartBit)); + return FirstFixedBit; +} + +// ParseMachineCode - Try to split the vector of instructions (which is +// intentionally taken by-copy) in half, narrowing down the possible +// instructions that we may have found. Eventually, this list will get pared +// down to zero or one instruction, in which case we have a match or failure. +// +static Record *ParseMachineCode(std::vector<Record*>::iterator InstsB, + std::vector<Record*>::iterator InstsE, + unsigned char *M) { + assert(InstsB != InstsE && "Empty range?"); + if (InstsB+1 == InstsE) { + // Only a single instruction, see if we match it... + Record *Inst = *InstsB; + for (unsigned i = 0, e = getNumBits(Inst); i != e; ++i) + if (BitInit *BI = dynamic_cast<BitInit*>(getBit(Inst, i))) + if (getMemoryBit(M, i) != BI->getValue()) + throw std::string("Parse failed!\n"); + return Inst; + } + + unsigned MaxBits = ~0; + for (std::vector<Record*>::iterator I = InstsB; I != InstsE; ++I) + MaxBits = std::min(MaxBits, getNumBits(*I)); + + unsigned FirstFixedBit = getFirstFixedBitInSequence(InstsB, InstsE, 0); + unsigned FirstVaryingBit, LastFixedBit; + do { + FirstVaryingBit = ~0; + LastFixedBit = ~0; + for (std::vector<Record*>::iterator I = InstsB+1; I != InstsE; ++I) + FindInstDifferences(*InstsB, *I, FirstFixedBit, MaxBits, + FirstVaryingBit, LastFixedBit); + if (FirstVaryingBit == MaxBits) { + std::cerr << "ERROR: Could not find bit to distinguish between " + << "the following entries!\n"; + PrintRange(InstsB, InstsE); + } + +#if 0 + std::cerr << "FVB: " << FirstVaryingBit << " - " << LastFixedBit + << ": " << InstsE-InstsB << "\n"; +#endif + + FirstFixedBit = getFirstFixedBitInSequence(InstsB, InstsE, FirstVaryingBit); + } while (FirstVaryingBit != FirstFixedBit); + + //std::cerr << "\n\nXXXXXXXXXXXXXXXXX\n\n"; + //PrintRange(InstsB, InstsE); + + // Sort the Insts list so that the entries have all of the bits in the range + // [FirstVaryingBit,LastFixedBit) sorted. These bits are all guaranteed to be + // set to either 0 or 1 (BitInit values), which simplifies things. + // + std::sort(InstsB, InstsE, BitComparator(FirstVaryingBit, LastFixedBit)); + + // Once the list is sorted by these bits, split the bit list into smaller + // lists, and recurse on each one. + // + std::vector<Record*>::iterator RangeBegin = InstsB; + Record *Match = 0; + while (RangeBegin != InstsE) { + std::vector<Record*>::iterator RangeEnd = RangeBegin+1; + while (RangeEnd != InstsE && + BitRangesEqual(*RangeBegin, *RangeEnd, FirstVaryingBit, LastFixedBit)) + ++RangeEnd; + + // We just identified a range of equal instructions. If this range is the + // input range, we were not able to distinguish between the instructions in + // the set. Print an error and exit! + // + if (RangeBegin == InstsB && RangeEnd == InstsE) { + std::cerr << "Error: Could not distinguish among the following insts!:\n"; + PrintRange(InstsB, InstsE); + abort(); + } + +#if 0 + std::cerr << "FVB: " << FirstVaryingBit << " - " << LastFixedBit + << ": [" << RangeEnd-RangeBegin << "] - "; + for (int i = LastFixedBit-1; i >= (int)FirstVaryingBit; --i) + std::cerr << (int)((BitInit*)getBit(*RangeBegin, i))->getValue() << " "; + std::cerr << "\n"; +#endif + + if (Record *R = ParseMachineCode(RangeBegin, RangeEnd, M)) { + if (Match) { + std::cerr << "Error: Multiple matches found:\n"; + PrintRange(InstsB, InstsE); + } + + assert(Match == 0 && "Multiple matches??"); + Match = R; + } + RangeBegin = RangeEnd; + } + + return Match; +} + +static void PrintValue(Record *I, unsigned char *Ptr, const RecordVal &Val) { + assert(dynamic_cast<BitsInit*>(Val.getValue()) && + "Can only handle undefined bits<> types!"); + BitsInit *BI = (BitsInit*)Val.getValue(); + assert(BI->getNumBits() <= 32 && "Can only handle fields up to 32 bits!"); + + unsigned Value = 0; + const std::vector<RecordVal> &Vals = I->getValues(); + + // Start by filling in fixed values... + for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i) + if (BitInit *B = dynamic_cast<BitInit*>(BI->getBit(i))) + Value |= B->getValue() << i; + + // Loop over all of the fields in the instruction adding in any + // contributions to this value (due to bit references). + // + unsigned Offset = 0; + for (unsigned f = 0, e = Vals.size(); f != e; ++f) + if (Vals[f].getPrefix()) { + BitsInit *FieldInitializer = (BitsInit*)Vals[f].getValue(); + if (&Vals[f] == &Val) { + // Read the bits directly now... + for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i) + Value |= getMemoryBit(Ptr, Offset+i) << i; + break; + } + + // Scan through the field looking for bit initializers of the current + // variable... + for (unsigned i = 0, e = FieldInitializer->getNumBits(); i != e; ++i) + if (VarBitInit *VBI = + dynamic_cast<VarBitInit*>(FieldInitializer->getBit(i))) { + TypedInit *TI = VBI->getVariable(); + if (VarInit *VI = dynamic_cast<VarInit*>(TI)) { + if (VI->getName() == Val.getName()) + Value |= getMemoryBit(Ptr, Offset+i) << VBI->getBitNum(); + } else if (FieldInit *FI = dynamic_cast<FieldInit*>(TI)) { + // FIXME: implement this! + std::cerr << "FIELD INIT not implemented yet!\n"; + } + } + Offset += FieldInitializer->getNumBits(); + } + + std::cout << "0x" << std::hex << Value << std::dec; +} + +static void PrintInstruction(Record *I, unsigned char *Ptr) { + std::cout << "Inst " << getNumBits(I)/8 << " bytes: " + << "\t" << I->getName() << "\t" << *I->getValue("Name")->getValue() + << "\t"; + + const std::vector<RecordVal> &Vals = I->getValues(); + for (unsigned i = 0, e = Vals.size(); i != e; ++i) + if (!Vals[i].getValue()->isComplete()) { + std::cout << Vals[i].getName() << "="; + PrintValue(I, Ptr, Vals[i]); + std::cout << "\t"; + } + + std::cout << "\n";// << *I; +} + +static void ParseMachineCode() { + // X86 code + unsigned char Buffer[] = { + 0x55, // push EBP + 0x89, 0xE5, // mov EBP, ESP + //0x83, 0xEC, 0x08, // sub ESP, 0x8 + 0xE8, 1, 2, 3, 4, // call +0x04030201 + 0x89, 0xEC, // mov ESP, EBP + 0x5D, // pop EBP + 0xC3, // ret + 0x90, // nop + 0xC9, // leave + 0x89, 0xF6, // mov ESI, ESI + 0x68, 1, 2, 3, 4, // push 0x04030201 + 0x5e, // pop ESI + 0xFF, 0xD0, // call EAX + 0xB8, 1, 2, 3, 4, // mov EAX, 0x04030201 + 0x85, 0xC0, // test EAX, EAX + 0xF4, // hlt + }; + +#if 0 + // SparcV9 code + unsigned char Buffer[] = { 0xbf, 0xe0, 0x20, 0x1f, 0x1, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0xc1, 0x0, 0x20, 0x1, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xaf, 0xe8, 0x20, 0x17 + }; +#endif + + std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction"); + + unsigned char *BuffPtr = Buffer; + while (1) { + Record *R = ParseMachineCode(Insts.begin(), Insts.end(), BuffPtr); + PrintInstruction(R, BuffPtr); + + unsigned Bits = getNumBits(R); + assert((Bits & 7) == 0 && "Instruction is not an even number of bytes!"); + BuffPtr += Bits/8; + } +} + + +int main(int argc, char **argv) { + cl::ParseCommandLineOptions(argc, argv); + ParseFile(InputFilename, IncludeDir); + + std::ostream *Out = &std::cout; + if (OutputFilename != "-") { + // Output to a .tmp file, because we don't actually want to overwrite the + // output file unless the generated file is different or the specified file + // does not exist. + Out = new std::ofstream((OutputFilename+".tmp").c_str()); + + if (!Out->good()) { + std::cerr << argv[0] << ": error opening " << OutputFilename << ".tmp!\n"; + return 1; + } + + // Make sure the file gets removed if *gasp* tablegen crashes... + RemoveFileOnSignal(OutputFilename+".tmp"); + } + + try { + switch (Action) { + case PrintRecords: + *Out << Records; // No argument, dump all contents + break; + case Parse: + ParseMachineCode(); + 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: + InstrInfoEmitter(Records).runEnums(*Out); + break; + case GenInstrs: + InstrInfoEmitter(Records).run(*Out); + break; + case GenInstrSelector: + InstrSelectorEmitter(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] << ", "; + *Out << "\n"; + break; + } + } catch (const std::string &Error) { + std::cerr << Error << "\n"; + if (Out != &std::cout) { + delete Out; // Close the file + std::remove(OutputFilename.c_str()); // Remove the file, it's broken + } + return 1; + } + + if (Out != &std::cout) { + delete Out; // Close the file + + // Now that we have generated the result, check to see if we either don't + // have the requested file, or if the requested file is different than the + // file we generated. If so, move the generated file over the requested + // file. Otherwise, just remove the file we just generated, so 'make' + // doesn't try to regenerate tons of dependencies. + // + MoveFileOverIfUpdated(OutputFilename+".tmp", OutputFilename); + } + return 0; +} diff --git a/llvm/utils/TableGen/TableGenBackend.cpp b/llvm/utils/TableGen/TableGenBackend.cpp new file mode 100644 index 00000000000..b86ae72ce9d --- /dev/null +++ b/llvm/utils/TableGen/TableGenBackend.cpp @@ -0,0 +1,27 @@ +//===- TableGenBackend.cpp - Base class for TableGen Backends ---*- C++ -*-===// +// +// This file provides useful services for TableGen backends... +// +//===----------------------------------------------------------------------===// + +#include "TableGenBackend.h" +#include "Record.h" +#include <iostream> + +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"; +} + +/// getQualifiedName - Return the name of the specified record, with a +/// namespace qualifier if the record contains one. +/// +std::string TableGenBackend::getQualifiedName(Record *R) const { + std::string Namespace = R->getValueAsString("Namespace"); + if (Namespace.empty()) return R->getName(); + return Namespace + "::" + R->getName(); +} + diff --git a/llvm/utils/TableGen/TableGenBackend.h b/llvm/utils/TableGen/TableGenBackend.h new file mode 100644 index 00000000000..8dfbaddad16 --- /dev/null +++ b/llvm/utils/TableGen/TableGenBackend.h @@ -0,0 +1,34 @@ +//===- TableGenBackend.h - Base class for TableGen Backends -----*- C++ -*-===// +// +// 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> +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; + + /// getQualifiedName - Return the name of the specified record, with a + /// namespace qualifier if the record contains one. + std::string getQualifiedName(Record *R) const; +}; + +#endif |

