From 88ac78c4d9e4126bfc2014b0f921769b79eff16f Mon Sep 17 00:00:00 2001 From: Jakub Staszak Date: Tue, 6 Apr 2004 19:31:31 +0000 Subject: [PATCH] Tablegen backend for really simple instruction selector git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@12713 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/SimpleInstrSelEmitter.cpp | 453 +++++++++++++++++++++++ utils/TableGen/SimpleInstrSelEmitter.h | 61 +++ 2 files changed, 514 insertions(+) create mode 100644 utils/TableGen/SimpleInstrSelEmitter.cpp create mode 100644 utils/TableGen/SimpleInstrSelEmitter.h diff --git a/utils/TableGen/SimpleInstrSelEmitter.cpp b/utils/TableGen/SimpleInstrSelEmitter.cpp new file mode 100644 index 00000000000..5f4d20854d0 --- /dev/null +++ b/utils/TableGen/SimpleInstrSelEmitter.cpp @@ -0,0 +1,453 @@ +//===- 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 diff --git a/utils/TableGen/SimpleInstrSelEmitter.h b/utils/TableGen/SimpleInstrSelEmitter.h new file mode 100644 index 00000000000..19ab444a3eb --- /dev/null +++ b/utils/TableGen/SimpleInstrSelEmitter.h @@ -0,0 +1,61 @@ +//===- SimpleInstrSelEmitter.h - Generate a Simple Instruction Selector ----*- C++ -*-===// +// +// 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 a simple instruction selector +// +// +//===----------------------------------------------------------------------===// + +#ifndef SIMPLE_INSTR_SELECTOR_EMITTER_H +#define SIMPLE_INSTR_SELECTOR_EMITTER_H + +#include "TableGenBackend.h" +#include "CodeGenWrappers.h" +#include +#include +#include + +namespace llvm { + +class Init; +class InstrSelectorEmitter; + + +/// InstrSelectorEmitter - The top-level class which coordinates construction +/// and emission of the instruction selector. +/// +class SimpleInstrSelEmitter : public TableGenBackend { + RecordKeeper &Records; + std::string globalSpacing; + +public: + SimpleInstrSelEmitter(RecordKeeper &R) : Records(R) {globalSpacing = " ";} + + // run - Output the instruction set description, returning true on failure. + void run(std::ostream &OS); + + Record* SimpleInstrSelEmitter::findInstruction(std::ostream &OS, std::string cl, std::vector& vi); + + Record* SimpleInstrSelEmitter::findRegister(std::ostream &OS, std::string regname); + + std::string SimpleInstrSelEmitter::formatRegister(std::ostream &OS, std::string regname); + + void SimpleInstrSelEmitter::generateBMIcall(std::ostream &OS, std::string MBB, std::string IP, std::string Opcode, int NumOperands, ListInit &l, ListInit &r); + + void SimpleInstrSelEmitter::InstrSubclasses(std::ostream &OS, std::string prefix, std::string InstrClassName, ListInit* SupportedSubclasses, std::vector& vi, unsigned depth); + + std::string spacing(); + std::string addspacing(); + std::string remspacing(); + +}; + +} // End llvm namespace + +#endif