mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-11-01 15:11:24 +00:00
Tablegen backend for really simple instruction selector
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@12713 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
01b6a6f279
commit
88ac78c4d9
453
utils/TableGen/SimpleInstrSelEmitter.cpp
Normal file
453
utils/TableGen/SimpleInstrSelEmitter.cpp
Normal file
@ -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 <set>
|
||||
|
||||
|
||||
#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 <algorithm>
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
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<Record*> 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<std::string> 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<Record*> 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<ListInit*>(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<std::string>& vi) {
|
||||
std::vector<Record*> 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<DefInit*>(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<Record*> 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<StringInit*>(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<DefInit*>(instroperands.getElement(i));
|
||||
StringInit* RegStr = dynamic_cast<StringInit*>(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<std::string>& vi, unsigned depth) {
|
||||
|
||||
|
||||
if (depth >= SupportedSubclasses->getSize()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get the subclass collection
|
||||
|
||||
DefInit* InstrSubclassColl = dynamic_cast<DefInit*>(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<DefInit*>(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<DefInit*>(theInstructions->getElement(l));
|
||||
Record *theInstruction = theInstructionDef->getDef();
|
||||
|
||||
ListInit *operands = theInstruction->getValueAsListInit("Params");
|
||||
|
||||
OS << spacing();
|
||||
|
||||
ListInit* registers = dynamic_cast<ListInit*>(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<StringInit*>(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
|
61
utils/TableGen/SimpleInstrSelEmitter.h
Normal file
61
utils/TableGen/SimpleInstrSelEmitter.h
Normal file
@ -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 <vector>
|
||||
#include <map>
|
||||
#include <cassert>
|
||||
|
||||
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<std::string>& 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<std::string>& vi, unsigned depth);
|
||||
|
||||
std::string spacing();
|
||||
std::string addspacing();
|
||||
std::string remspacing();
|
||||
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user