//===- SimpleInstrSelEmitter.cpp - Generate a Simple Instruction Selector ------------===// // // The LLVM Compiler Infrastructure // // This file was developed by the LLVM research group and is distributed under // the University of Illinois Open Source License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This tablegen backend is responsible for emitting an instruction selector // // //===----------------------------------------------------------------------===// #include "InstrInfoEmitter.h" #include "SimpleInstrSelEmitter.h" #include "CodeGenWrappers.h" #include "Record.h" #include "Support/Debug.h" #include "Support/StringExtras.h" #include #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 "SimpleInstrSelEmitter.h" #include #include #include #include namespace llvm { std::string FnDecs; // run - Emit the main instruction description records for the target... void SimpleInstrSelEmitter::run(std::ostream &OS) { // EmitSourceFileHeader("Mark's Instruction Selector for the X86 target", OS); // OS << "#include \"llvm/CodeGen/MachineInstrBuilder.h\"\n"; // OS << "#include \"llvm/Constants.h\"\n"; // OS << "#include \"llvm/DerivedTypes.h\"\n"; // OS << "#include \"llvm/Function.h\"\n"; // OS << "#include \"llvm/Instructions.h\"\n"; // OS << "#include \"llvm/IntrinsicLowering.h\"\n"; // OS << "#include \"llvm/Pass.h\"\n"; // OS << "#include \"llvm/CodeGen/MachineConstantPool.h\"\n"; // OS << "#include \"llvm/CodeGen/MachineFrameInfo.h\"\n"; // OS << "#include \"llvm/CodeGen/MachineFunction.h\"\n"; // OS << "#include \"llvm/CodeGen/MachineInstrBuilder.h\"\n"; // OS << "#include \"llvm/CodeGen/SSARegMap.h\"\n"; // OS << "#include \"llvm/Target/MRegisterInfo.h\"\n"; // OS << "#include \"llvm/Target/TargetMachine.h\"\n"; // OS << "#include \"llvm/Support/InstVisitor.h\"\n"; // OS << "using namespace llvm;\n\n"; FnDecs = ""; // for each InstrClass std::vector Recs = Records.getAllDerivedDefinitions("InstrClass"); for (unsigned i = 0, e = Recs.size(); i != e; ++i) { std::string InstrClassName = Recs[i]->getName(); OS << "// Generate BMI instructions for " << InstrClassName << "\n\n"; OS << "void ISel::visit"; OS << Recs[i]->getValueAsString("FunctionName"); OS << "(" << Recs[i]->getValueAsString("InstructionName") << " &I)\n{" << "\n"; // for each supported InstrSubclass OS << spacing() << "unsigned DestReg = getReg(I);\n"; OS << spacing() << "unsigned Op0Reg = getReg(I.getOperand(0));\n"; OS << spacing() << "unsigned Op1Reg = getReg(I.getOperand(1));\n"; OS << spacing() << "Value *Op0Val = I.getOperand(0);\n"; OS << spacing() << "Value *Op1Val = I.getOperand(1);\n"; OS << spacing() << "MachineBasicBlock::iterator IP = BB->end();\n"; OS << std::endl; ListInit *SupportedSubclasses = Recs[i]->getValueAsListInit("Supports"); //OS << spacing() << InstrClassName << "Prep();" << "\n"; //FnDecs += "void ISel::" + InstrClassName + "Prep() {\n\n}\n\n"; std::vector vi; // generate subclasses nested switch statements InstrSubclasses(OS, InstrClassName, InstrClassName, SupportedSubclasses, vi, 0); //OS << spacing() << InstrClassName << "Post();\n"; //FnDecs += "void ISel::" + InstrClassName + "Post() {\n\n}\n\n"; OS << "}\n"; OS << "\n\n\n"; } // for each instrclass // OS << "} //namespace\n"; #if 0 // print out function stubs OS << "\n\n\n//Functions\n\n" << FnDecs; // print out getsubclass() definitions std::vector SubclassColRec = Records.getAllDerivedDefinitions("InstrSubclassCollection"); for (unsigned j=0, m=SubclassColRec.getSize(); j!=m; ++j) { std::string SubclassName = SubclassColRec[j]->getName(); FnDecs += "unsigned ISel::get" + SubclassName + "() {\n\n"; ListInit* list = dynamic_cast(SubclassColRec[j].getValueAsListInit("List")); for (unsigned k=0; n=list.getSize(); k!=n; ++k) { FnDecs += "}\n\n"; } #endif } //run // find instructions that match all the subclasses (only support for 1 now) Record* SimpleInstrSelEmitter::findInstruction(std::ostream &OS, std::string cl, std::vector& vi) { std::vector Recs = Records.getAllDerivedDefinitions("TargInstrSet"); for (unsigned i = 0, e = Recs.size(); i != e; ++i) { Record* thisClass = Recs[i]->getValueAsDef("Class"); if (thisClass->getName() == cl) { // get the Subclasses this supports ListInit* SubclassList = Recs[i]->getValueAsListInit("List"); bool Match = true; if (SubclassList->getSize() != vi.size()) Match = false; // match the instruction's supported subclasses with the subclasses we are looking for for (unsigned j=0, f=SubclassList->getSize(); j!=f; ++j) { DefInit* SubclassDef = dynamic_cast(SubclassList->getElement(j)); Record* thisSubclass = SubclassDef->getDef(); std::string searchingFor = vi[j]; if (thisSubclass->getName() != searchingFor) { Match = false; } } // for each subclass list if (Match == true) { return Recs[i]; } } //if instrclass matches } // for all instructions // if no instructions found, return NULL return NULL; } //findInstruction Record* SimpleInstrSelEmitter::findRegister(std::ostream &OS, std::string regname) { std::vector Recs = Records.getAllDerivedDefinitions("Register"); for (unsigned i = 0, e = Recs.size(); i != e; ++i) { Record* thisReg = Recs[i]; if (thisReg->getName() == regname) return Recs[i]; } return NULL; } // handle "::" and "+" etc std::string SimpleInstrSelEmitter::formatRegister(std::ostream &OS, std::string regname) { std::string Reg; std::string suffix; int x = std::strcspn(regname.c_str(),"+-"); // operate on text before "+" or "-", append it back at the end Reg = regname.substr(0,x); suffix = regname.substr(x,regname.length()); unsigned int y = std::strcspn(Reg.c_str(),":"); if (y == Reg.length()) { // does not contain "::" Record* RegRec = findRegister(OS,Reg); assert(RegRec && "Register not found!"); if (RegRec->getValueAsString("Namespace") != "Virtual") { Reg = RegRec->getValueAsString("Namespace") + "::" + RegRec->getName(); } else { Reg = RegRec->getName(); } } // regular case // append + or - at the end again (i.e. X86::EAX+1) Reg = Reg + suffix; return Reg; } // take information in the instruction class and generate the correct BMI call void SimpleInstrSelEmitter::generateBMIcall(std::ostream &OS, std::string MBB, std::string IP, std::string Opcode, int NumOperands, ListInit &instroperands, ListInit &operands) { // find Destination Register StringInit* DestRegStr = dynamic_cast(operands.getElement(0)); std::string DestReg = formatRegister(OS,DestRegStr->getValue()); OS << "BuildMI("; OS << MBB << ", "; OS << IP << ", "; OS << Opcode << ", "; OS << NumOperands; if (DestReg != "Pseudo") { OS << ", " << DestReg << ")"; } else { OS << ")"; } // handle the .add stuff for (unsigned i=0, e=instroperands.getSize(); i!=e; ++i) { DefInit* OpDef = dynamic_cast(instroperands.getElement(i)); StringInit* RegStr = dynamic_cast(operands.getElement(i+1)); Record* Op = OpDef->getDef(); std::string opstr = Op->getValueAsString("Name"); std::string regname; if (opstr == "Register") { regname = formatRegister(OS,RegStr->getValue()); } else { regname = RegStr->getValue(); } OS << ".add" << opstr << "(" << regname << ")"; } OS << ";\n"; } //generateBMIcall std::string SimpleInstrSelEmitter::spacing() { return globalSpacing; } std::string SimpleInstrSelEmitter::addspacing() { globalSpacing += " "; return globalSpacing; } std::string SimpleInstrSelEmitter::remspacing() { globalSpacing = globalSpacing.substr(0,globalSpacing.length()-2); return globalSpacing; } // recursively print out the subclasses of an instruction // void SimpleInstrSelEmitter::InstrSubclasses(std::ostream &OS, std::string prefix, std::string InstrClassName, ListInit* SupportedSubclasses, std::vector& vi, unsigned depth) { if (depth >= SupportedSubclasses->getSize()) { return; } // get the subclass collection DefInit* InstrSubclassColl = dynamic_cast(SupportedSubclasses->getElement(depth)); Record* InstrSubclassRec = InstrSubclassColl->getDef(); std::string SubclassName = InstrSubclassRec->getName(); if (InstrSubclassRec->getValueAsString("PreCode") != "") { // OS << spacing() << prefix << "_" << Subclass->getName() << "_Prep();\n"; OS << spacing() << InstrSubclassRec->getValueAsString("PreCode") << "\n\n"; } OS << spacing() << "// Looping through " << SubclassName << "\n"; OS << spacing() << "switch (" << SubclassName <<") {\n"; addspacing(); ListInit* SubclassList = InstrSubclassRec->getValueAsListInit("List"); for (unsigned k=0, g = SubclassList->getSize(); k!=g; ++k) { DefInit* SubclassDef = dynamic_cast(SubclassList->getElement(k)); Record* Subclass = SubclassDef->getDef(); OS << spacing() << "// " << prefix << "_" << Subclass->getName() << "\n"; OS << spacing() << "case " << Subclass->getName() << ":\n"; addspacing(); OS << spacing() << "{\n"; vi.push_back(Subclass->getName()); // go down hierarchy InstrSubclasses(OS, prefix + "_" + Subclass->getName(), InstrClassName, SupportedSubclasses, vi, depth+1); // find the record that matches this Record *theInstructionSet = findInstruction(OS, InstrClassName, vi); // only print out the assertion if this is a leaf if ( (theInstructionSet == NULL) && (depth == (SupportedSubclasses->getSize() - 1)) ) { OS << spacing() << "assert(0 && \"No instructions defined for " << InstrClassName << " instructions of subclasses " << prefix << "_" << Subclass->getName() << "!\");" << "\n"; } else if (theInstructionSet != NULL) { if (theInstructionSet->getValueAsString("PreCode") != "") { OS << spacing() << theInstructionSet->getValueAsString("PreCode") << "\n\n"; } ListInit *theInstructions = theInstructionSet->getValueAsListInit("Instructions"); ListInit *registerlists = theInstructionSet->getValueAsListInit("Operands"); // not necessarily registers anymore, but the name will stay for now for (unsigned l=0, h=theInstructions->getSize(); l!=h; ++l) { DefInit *theInstructionDef = dynamic_cast(theInstructions->getElement(l)); Record *theInstruction = theInstructionDef->getDef(); ListInit *operands = theInstruction->getValueAsListInit("Params"); OS << spacing(); ListInit* registers = dynamic_cast(registerlists->getElement(l)); // handle virtual instructions here before going to generateBMIcall if (theInstruction->getValueAsString("Namespace") == "Virtual") { // create reg for different sizes std::string Instr = theInstruction->getName(); StringInit* DestRegInit = dynamic_cast(registers->getElement(0)); std::string DestReg = DestRegInit->getValue(); std::string theType; if (Instr == "NullInstruction") { } // do nothing else if (Instr == "CreateRegByte") OS << "unsigned " << DestReg << " = makeAnotherReg(Type::SByteTy);\n"; else if (Instr == "CreateRegShort") OS << "unsigned " << DestReg << " = makeAnotherReg(Type::SShortTy);\n"; else if (Instr == "CreateRegInt") OS << "unsigned " << DestReg << " = makeAnotherReg(Type::SIntTy);\n"; else if (Instr == "CreateRegLong") OS << "unsigned " << DestReg << " = makeAnotherReg(Type::SLongTy);\n"; else if (Instr == "CreateRegUByte") OS << "unsigned " << DestReg << " = makeAnotherReg(Type::UByteTy);\n"; else if (Instr == "CreateRegUShort") OS << "unsigned " << DestReg << " = makeAnotherReg(Type::UShortTy);\n"; else if (Instr == "CreateRegUInt") OS << "unsigned " << DestReg << " = makeAnotherReg(Type::UIntTy);\n"; else if (Instr == "CreateRegULong") OS << "unsigned " << DestReg << " = makeAnotherReg(Type::ULongTy);\n"; else if (Instr == "CreateRegFloat") OS << "unsigned " << DestReg << " = makeAnotherReg(Type::FloatTy);\n"; else if (Instr == "CreateRegDouble") OS << "unsigned " << DestReg << " = makeAnotherReg(Type::DoubleTy);\n"; else if (Instr == "CreateRegPointer") OS << "unsigned " << DestReg << " = makeAnotherReg(Type::PointerTy_;\n"; else OS << "unsigned " << DestReg << " = makeAnotherReg(Type::SByteTy);\n"; // create a byte by default } else { std::string InstrName; if (theInstruction->getValueAsString("Namespace") != "Virtual") { InstrName = theInstruction->getValueAsString("Namespace") + "::" + theInstruction->getValueAsString("Name"); } else { // shouldn't ever happen, virtual instrs should be caught before this InstrName = theInstruction->getValueAsString("Name"); } generateBMIcall(OS, "*BB","IP",InstrName,theInstruction->getValueAsInt("NumOperands"),*operands,*registers); } } if (theInstructionSet->getValueAsString("PostCode") != "") { OS << spacing() << theInstructionSet->getValueAsString("PostCode") << "\n\n"; } } if (InstrSubclassRec->getValueAsString("PostCode") != "") { //OS << spacing() << "// " << prefix << "_" << Subclass->getName() << "_Prep();\n"; OS << spacing() << InstrSubclassRec->getValueAsString("PostCode") << "\n\n"; } OS << spacing() << "break;\n"; OS << spacing() << "}\n\n"; remspacing(); vi.pop_back(); } // provide a default case for the switch OS << spacing() << "default:\n"; OS << spacing() << " assert(0 && \"No instructions defined for " << InstrClassName << " instructions of subclasses " << prefix << "_" << SubclassName << "!\");" << "\n"; OS << spacing() << " break;\n\n"; remspacing(); OS << spacing() << "}\n"; } // ret br switch invoke unwind // add sub mul div rem setcc (eq ne lt gt le ge) // and or xor sbl sbr // malloc free alloca load store // getelementptr phi cast call vanext vaarg } // End llvm namespace