From: Bruno Cardoso Lopes Date: Wed, 6 Jun 2007 07:42:06 +0000 (+0000) Subject: Initial Mips support, here we go! =) X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=972f5896e417d8e81cf400083fab15a37b6d4277;p=oota-llvm.git Initial Mips support, here we go! =) - Modifications from the last patch included (issues pointed by Evan Cheng are now fixed). - Added more MipsI instructions. - Added more patterns to match branch instructions. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@37461 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Target/Mips/Makefile b/lib/Target/Mips/Makefile new file mode 100644 index 00000000000..6ebffc76e06 --- /dev/null +++ b/lib/Target/Mips/Makefile @@ -0,0 +1,21 @@ +##===- lib/Target/Mips/Makefile ----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file was developed by Bruno Cardoso Lopes and is distributed under the +# University of Illinois Open Source License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../../.. +LIBRARYNAME = LLVMMips +TARGET = Mips + +# Make sure that tblgen is run, first thing. +BUILT_SOURCES = MipsGenRegisterInfo.h.inc MipsGenRegisterNames.inc \ + MipsGenRegisterInfo.inc MipsGenInstrNames.inc \ + MipsGenInstrInfo.inc MipsGenAsmWriter.inc \ + MipsGenDAGISel.inc MipsGenCallingConv.inc \ + MipsGenSubtarget.inc + +include $(LEVEL)/Makefile.common + diff --git a/lib/Target/Mips/Mips.h b/lib/Target/Mips/Mips.h new file mode 100644 index 00000000000..48b08eaf802 --- /dev/null +++ b/lib/Target/Mips/Mips.h @@ -0,0 +1,38 @@ +//===-- Mips.h - Top-level interface for Mips representation ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the entry points for global functions defined in +// the LLVM Mips back-end. +// +//===----------------------------------------------------------------------===// + +#ifndef TARGET_MIPS_H +#define TARGET_MIPS_H + +#include + +namespace llvm { + class MipsTargetMachine; + class FunctionPassManager; + class FunctionPass; + class MachineCodeEmitter; + + FunctionPass *createMipsCodePrinterPass(std::ostream &OS, + MipsTargetMachine &TM); + FunctionPass *createMipsISelDag(MipsTargetMachine &TM); +} // end namespace llvm; + +// Defines symbolic names for Mips registers. This defines a mapping from +// register name to register number. +#include "MipsGenRegisterNames.inc" + +// Defines symbolic names for the Mips instructions. +#include "MipsGenInstrNames.inc" + +#endif diff --git a/lib/Target/Mips/Mips.td b/lib/Target/Mips/Mips.td new file mode 100644 index 00000000000..662bc3b85d8 --- /dev/null +++ b/lib/Target/Mips/Mips.td @@ -0,0 +1,63 @@ +//===- Mips.td - Describe the Mips Target Machine ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Target-independent interfaces which we are implementing +//===----------------------------------------------------------------------===// + +include "../Target.td" + +//===----------------------------------------------------------------------===// +// Register File Description +//===----------------------------------------------------------------------===// + +include "MipsRegisterInfo.td" + +//===----------------------------------------------------------------------===// +// Subtarget features +//===----------------------------------------------------------------------===// + +// TODO: dummy, needed to compile +def FeatureCIX : SubtargetFeature<"r3000", "isR3000", "true", + "Enable r3000 extentions">; + +//===----------------------------------------------------------------------===// +// Instruction Description +//===----------------------------------------------------------------------===// + +include "MipsInstrInfo.td" + +def MipsInstrInfo : InstrInfo { + // Define how we want to layout our target-specific information field. + let TSFlagsFields = []; + let TSFlagsShifts = []; +} +//===----------------------------------------------------------------------===// +// Calling Conventions +//===----------------------------------------------------------------------===// + +include "MipsCallingConv.td" + +//===----------------------------------------------------------------------===// +// Mips processors supported. +//===----------------------------------------------------------------------===// + +class Proc Features> + : Processor; + +def : Proc<"generic", []>; + +//===----------------------------------------------------------------------===// +// Declare the target which we are implementing +//===----------------------------------------------------------------------===// + +def Mips : Target { + // Pull in Instruction Info: + let InstructionSet = MipsInstrInfo; +} diff --git a/lib/Target/Mips/MipsAsmPrinter.cpp b/lib/Target/Mips/MipsAsmPrinter.cpp new file mode 100644 index 00000000000..fdf60d92a24 --- /dev/null +++ b/lib/Target/Mips/MipsAsmPrinter.cpp @@ -0,0 +1,294 @@ +//===-- MipsAsmPrinter.cpp - Mips LLVM assembly writer --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a printer that converts from our internal representation +// of machine-dependent LLVM code to GAS-format MIPS assembly language. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mips-asm-printer" + +#include "Mips.h" +#include "MipsInstrInfo.h" +#include "MipsTargetMachine.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Module.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Support/Mangler.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/MathExtras.h" +#include + +using namespace llvm; + +STATISTIC(EmittedInsts, "Number of machine instrs printed"); + +namespace { + struct VISIBILITY_HIDDEN MipsAsmPrinter : public AsmPrinter { + MipsAsmPrinter(std::ostream &O, MipsTargetMachine &TM, + const TargetAsmInfo *T): + AsmPrinter(O, TM, T) {} + + virtual const char *getPassName() const { + return "Mips Assembly Printer"; + } + + void printOperand(const MachineInstr *MI, int opNum); + void printMemOperand(const MachineInstr *MI, int opNum, + const char *Modifier = 0); + + bool printInstruction(const MachineInstr *MI); // autogenerated. + bool runOnMachineFunction(MachineFunction &F); + bool doInitialization(Module &M); + bool doFinalization(Module &M); + }; +} // end of anonymous namespace + +#include "MipsGenAsmWriter.inc" + +/// createMipsCodePrinterPass - Returns a pass that prints the MIPS +/// assembly code for a MachineFunction to the given output stream, +/// using the given target machine description. This should work +/// regardless of whether the function is in SSA form. +FunctionPass *llvm::createMipsCodePrinterPass(std::ostream &o, + MipsTargetMachine &tm) +{ + return new MipsAsmPrinter(o, tm, tm.getTargetAsmInfo()); +} + +/// runOnMachineFunction - This uses the printMachineInstruction() +/// method to print assembly for each instruction. +bool MipsAsmPrinter:: +runOnMachineFunction(MachineFunction &MF) +{ + SetupMachineFunction(MF); + + // Print out constants referenced by the function + EmitConstantPool(MF.getConstantPool()); + + O << "\n\n"; + + // What's my mangled name? + CurrentFnName = Mang->getValueName(MF.getFunction()); + + // Print out the label for the function. + const Function *F = MF.getFunction(); + SwitchToTextSection(getSectionForFunction(*F).c_str(), F); + + // On Mips GAS if .align #n is present, #n means the number of bits + // to be cleared to align. So, if we want 4 byte alignment, we must + // have .align 2 + // TODO: + // add gas ".mask" and ".fmask" + EmitAlignment(1, F); + O << "\t.globl\t" << CurrentFnName << "\n"; + O << "\t.ent\t" << CurrentFnName << "\n"; + O << "\t.type\t" << CurrentFnName << ", @function\n"; + O << CurrentFnName << ":\n"; + + // Print out code for the function. + for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + + // Print a label for the basic block. + if (I != MF.begin()) { + printBasicBlockLabel(I, true); + O << '\n'; + } + + for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); + II != E; ++II) { + // Print the assembly for the instruction. + O << "\t"; + printInstruction(II); + ++EmittedInsts; + } + } + + // close function with asm directive + O << "\t.end\t" << CurrentFnName << "\n"; + + // We didn't modify anything. + return false; +} + +void MipsAsmPrinter:: +printOperand(const MachineInstr *MI, int opNum) +{ + const MachineOperand &MO = MI->getOperand(opNum); + const MRegisterInfo &RI = *TM.getRegisterInfo(); + bool closeP=false; + + // %hi and %lo used on mips gas to break large constants + if (MI->getOpcode() == Mips::LUi && !MO.isRegister() + && !MO.isImmediate()) { + O << "%hi("; + closeP = true; + } else if ((MI->getOpcode() == Mips::ADDiu) && !MO.isRegister() + && !MO.isImmediate()) { + O << "%lo("; + closeP = true; + } + + switch (MO.getType()) + { + case MachineOperand::MO_Register: + if (MRegisterInfo::isPhysicalRegister(MO.getReg())) + O << "$" << LowercaseString (RI.get(MO.getReg()).Name); + else + O << "$" << MO.getReg(); + break; + + case MachineOperand::MO_Immediate: + if ((MI->getOpcode() == Mips::SLTiu) || (MI->getOpcode() == Mips::ORi) || + (MI->getOpcode() == Mips::LUi) || (MI->getOpcode() == Mips::ANDi)) + O << (unsigned int)MO.getImmedValue(); + else + O << (int)MO.getImmedValue(); + break; + + case MachineOperand::MO_MachineBasicBlock: + printBasicBlockLabel(MO.getMachineBasicBlock()); + return; + + case MachineOperand::MO_GlobalAddress: + O << Mang->getValueName(MO.getGlobal()); + break; + + case MachineOperand::MO_ExternalSymbol: + O << MO.getSymbolName(); + break; + + case MachineOperand::MO_ConstantPoolIndex: + O << TAI->getPrivateGlobalPrefix() << "CPI" + << getFunctionNumber() << "_" << MO.getConstantPoolIndex(); + break; + + default: + O << ""; abort (); break; + } + + if (closeP) O << ")"; +} + +void MipsAsmPrinter:: +printMemOperand(const MachineInstr *MI, int opNum, const char *Modifier) +{ + // lw/sw $reg, MemOperand + // will turn into : + // lw/sw $reg, imm($reg) + printOperand(MI, opNum); + O << "("; + printOperand(MI, opNum+1); + O << ")"; +} + +bool MipsAsmPrinter:: +doInitialization(Module &M) +{ + Mang = new Mangler(M); + return false; // success +} + +bool MipsAsmPrinter:: +doFinalization(Module &M) +{ + const TargetData *TD = TM.getTargetData(); + + // Print out module-level global variables here. + for (Module::const_global_iterator I = M.global_begin(), + E = M.global_end(); I != E; ++I) + + // External global require no code + if (I->hasInitializer()) { + + // Check to see if this is a special global + // used by LLVM, if so, emit it. + if (EmitSpecialLLVMGlobal(I)) + continue; + + O << "\n\n"; + std::string name = Mang->getValueName(I); + Constant *C = I->getInitializer(); + unsigned Size = TD->getTypeSize(C->getType()); + unsigned Align = TD->getPrefTypeAlignment(C->getType()); + + if (C->isNullValue() && (I->hasLinkOnceLinkage() || + I->hasInternalLinkage() || I->hasWeakLinkage() + /* FIXME: Verify correct */)) { + + SwitchToDataSection(".data", I); + if (I->hasInternalLinkage()) + O << "\t.local " << name << "\n"; + + O << "\t.comm " << name << "," + << TD->getTypeSize(C->getType()) + << "," << Align << "\n"; + + } else { + + switch (I->getLinkage()) + { + case GlobalValue::LinkOnceLinkage: + case GlobalValue::WeakLinkage: + // FIXME: Verify correct for weak. + // Nonnull linkonce -> weak + O << "\t.weak " << name << "\n"; + SwitchToDataSection("", I); + O << "\t.section\t\".llvm.linkonce.d." << name + << "\",\"aw\",@progbits\n"; + break; + case GlobalValue::AppendingLinkage: + // FIXME: appending linkage variables + // should go into a section of their name or + // something. For now, just emit them as external. + case GlobalValue::ExternalLinkage: + // If external or appending, declare as a global symbol + O << "\t.globl " << name << "\n"; + case GlobalValue::InternalLinkage: + if (C->isNullValue()) + SwitchToDataSection(".bss", I); + else + SwitchToDataSection(".data", I); + break; + case GlobalValue::GhostLinkage: + cerr << "Should not have any" + << "unmaterialized functions!\n"; + abort(); + case GlobalValue::DLLImportLinkage: + cerr << "DLLImport linkage is" + << "not supported by this target!\n"; + abort(); + case GlobalValue::DLLExportLinkage: + cerr << "DLLExport linkage is" + << "not supported by this target!\n"; + abort(); + default: + assert(0 && "Unknown linkage type!"); + } + O << "\t.align " << Align << "\n"; + O << "\t.type " << name << ",@object\n"; + O << "\t.size " << name << "," << Size << "\n"; + O << name << ":\n"; + EmitGlobalConstant(C); + } + } + + AsmPrinter::doFinalization(M); + return false; // success +} diff --git a/lib/Target/Mips/MipsCallingConv.td b/lib/Target/Mips/MipsCallingConv.td new file mode 100644 index 00000000000..23ef8503d38 --- /dev/null +++ b/lib/Target/Mips/MipsCallingConv.td @@ -0,0 +1,39 @@ +//===- MipsCallingConv.td - Calling Conventions for Mips --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This describes the calling conventions for Mips architecture. +//===----------------------------------------------------------------------===// + +/// CCIfSubtarget - Match if the current subtarget has a feature F. +class CCIfSubtarget: + CCIf().", F), A>; + +//===----------------------------------------------------------------------===// +// Mips Return Value Calling Convention +//===----------------------------------------------------------------------===// +def RetCC_Mips : CallingConv<[ + // i32 are returned in registers V0, V1 + CCIfType<[i32], CCAssignToReg<[V0, V1]>> +]>; + + +//===----------------------------------------------------------------------===// +// Mips Argument Calling Conventions +//===----------------------------------------------------------------------===// +def CC_Mips : CallingConv<[ + // Promote i8/i16 arguments to i32. + CCIfType<[i8, i16], CCPromoteToType>, + + // The first 4 integer arguments are passed in integer registers. + CCIfType<[i32], CCAssignToReg<[A0, A1, A2, A3]>>, + + // Integer values get stored in stack slots that are 4 bytes in + // size and 4-byte aligned. + CCIfType<[i32], CCAssignToStack<4, 4>> +]>; + diff --git a/lib/Target/Mips/MipsISelDAGToDAG.cpp b/lib/Target/Mips/MipsISelDAGToDAG.cpp new file mode 100644 index 00000000000..e660f9cb857 --- /dev/null +++ b/lib/Target/Mips/MipsISelDAGToDAG.cpp @@ -0,0 +1,272 @@ +//===-- MipsISelDAGToDAG.cpp - A dag to dag inst selector for Mips --------===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines an instruction selector for the MIPS target. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mips-isel" + +#include "Mips.h" +#include "MipsISelLowering.h" +#include "MipsRegisterInfo.h" +#include "MipsSubtarget.h" +#include "MipsTargetMachine.h" +#include "llvm/GlobalValue.h" +#include "llvm/Instructions.h" +#include "llvm/Intrinsics.h" +#include "llvm/Support/CFG.h" +#include "llvm/Type.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +#include +#include + +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Instruction Selector Implementation +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// MipsDAGToDAGISel - MIPS specific code to select MIPS machine +// instructions for SelectionDAG operations. +//===----------------------------------------------------------------------===// +namespace { + +class VISIBILITY_HIDDEN MipsDAGToDAGISel : public SelectionDAGISel { + + /// TM - Keep a reference to MipsTargetMachine. + MipsTargetMachine &TM; + + /// MipsLowering - This object fully describes how to lower LLVM code to an + /// Mips-specific SelectionDAG. + MipsTargetLowering MipsLowering; + + /// Subtarget - Keep a pointer to the MipsSubtarget around so that we can + /// make the right decision when generating code for different targets. + //TODO: add initialization on constructor + //const MipsSubtarget *Subtarget; + +public: + MipsDAGToDAGISel(MipsTargetMachine &tm) : + SelectionDAGISel(MipsLowering), + TM(tm), MipsLowering(*TM.getTargetLowering()) {} + + virtual void InstructionSelectBasicBlock(SelectionDAG &SD); + + // Pass Name + virtual const char *getPassName() const { + return "MIPS DAG->DAG Pattern Instruction Selection"; + } + + +private: + // Include the pieces autogenerated from the target description. + #include "MipsGenDAGISel.inc" + + SDNode *Select(SDOperand N); + + // Complex Pattern. + bool SelectAddr(SDOperand Op, SDOperand N, + SDOperand &Base, SDOperand &Offset); + + + // getI32Imm - Return a target constant with the specified + // value, of type i32. + inline SDOperand getI32Imm(unsigned Imm) { + return CurDAG->getTargetConstant(Imm, MVT::i32); + } + + + #ifndef NDEBUG + unsigned Indent; + #endif +}; + +} + +/// InstructionSelectBasicBlock - This callback is invoked by +/// SelectionDAGISel when it has created a SelectionDAG for us to codegen. +void MipsDAGToDAGISel:: +InstructionSelectBasicBlock(SelectionDAG &SD) +{ + DEBUG(BB->dump()); + // Codegen the basic block. + #ifndef NDEBUG + DOUT << "===== Instruction selection begins:\n"; + Indent = 0; + #endif + + // Select target instructions for the DAG. + SD.setRoot(SelectRoot(SD.getRoot())); + + #ifndef NDEBUG + DOUT << "===== Instruction selection ends:\n"; + #endif + + SD.RemoveDeadNodes(); + + // Emit machine code to BB. + ScheduleAndEmitDAG(SD); +} + +/// ComplexPattern used on MipsInstrInfo +/// Used on Mips Load/Store instructions +bool MipsDAGToDAGISel:: +SelectAddr(SDOperand Op, SDOperand Addr, SDOperand &Offset, SDOperand &Base) +{ + // if Address is FI, get the TargetFrameIndex. + if (FrameIndexSDNode *FIN = dyn_cast(Addr)) { + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); + Offset = CurDAG->getTargetConstant(0, MVT::i32); + return true; + } + + // TargetExternalSymbol and TargetGlobalAddress are + // lowered and their addresses go into registers, so + // they should not be touched here. + if ((Addr.getOpcode() == ISD::TargetExternalSymbol || + Addr.getOpcode() == ISD::TargetGlobalAddress)) + return false; + + // Operand is an result from an ADD. + if (Addr.getOpcode() == ISD::ADD) + { + if (ConstantSDNode *CN = dyn_cast(Addr.getOperand(1))) + { + if (Predicate_immSExt16(CN)) + { + // If the first operand is a FI, get the TargetFI Node + if (FrameIndexSDNode *FIN = dyn_cast + (Addr.getOperand(0))) { + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); + } else { + Base = Addr.getOperand(0); + } + + Offset = CurDAG->getTargetConstant(CN->getValue(), MVT::i32); + return true; + } + } + } + + Base = Addr; + Offset = CurDAG->getTargetConstant(0, MVT::i32); + return true; +} + +/// Select instructions not customized! Used for +/// expanded, promoted and normal instructions +SDNode* MipsDAGToDAGISel:: +Select(SDOperand N) +{ + SDNode *Node = N.Val; + unsigned Opcode = Node->getOpcode(); + + // Dump information about the Node being selected + #ifndef NDEBUG + DOUT << std::string(Indent, ' ') << "Selecting: "; + DEBUG(Node->dump(CurDAG)); + DOUT << "\n"; + Indent += 2; + #endif + + // If we have a custom node, we already have selected! + if (Opcode >= ISD::BUILTIN_OP_END && Opcode < MipsISD::FIRST_NUMBER) { + #ifndef NDEBUG + DOUT << std::string(Indent-2, ' ') << "== "; + DEBUG(Node->dump(CurDAG)); + DOUT << "\n"; + Indent -= 2; + #endif + return NULL; + } + + /// + // Instruction Selection not handled by custom or by the + // auto-generated tablegen selection should be handled here + /// + switch(Opcode) { + + default: break; + + /// Special Mul operations + case ISD::MULHS: + case ISD::MULHU: { + SDOperand MulOp1 = Node->getOperand(0); + SDOperand MulOp2 = Node->getOperand(1); + AddToISelQueue(MulOp1); + AddToISelQueue(MulOp2); + + unsigned MulOp = (Opcode == ISD::MULHU ? Mips::MULTu : Mips::MULT); + SDNode *MulNode = CurDAG->getTargetNode(MulOp, MVT::Flag, MulOp1, MulOp2); + + SDOperand MFInFlag = SDOperand(MulNode, 0); + return CurDAG->getTargetNode(Mips::MFHI, MVT::i32, MFInFlag); + } + + /// Div operations + case ISD::SDIV: + case ISD::UDIV: { + SDOperand DivOp1 = Node->getOperand(0); + SDOperand DivOp2 = Node->getOperand(1); + AddToISelQueue(DivOp1); + AddToISelQueue(DivOp2); + + unsigned DivOp = (Opcode == ISD::SDIV ? Mips::DIV : Mips::DIVu); + SDNode *DivNode = CurDAG->getTargetNode(DivOp, MVT::Flag, DivOp1, DivOp2); + + SDOperand MFInFlag = SDOperand(DivNode, 0); + return CurDAG->getTargetNode(Mips::MFLO, MVT::i32, MFInFlag); + } + + /// Rem operations + case ISD::SREM: + case ISD::UREM: { + SDOperand RemOp1 = Node->getOperand(0); + SDOperand RemOp2 = Node->getOperand(1); + AddToISelQueue(RemOp1); + AddToISelQueue(RemOp2); + + unsigned RemOp = (Opcode == ISD::SREM ? Mips::DIV : Mips::DIVu); + SDNode *RemNode = CurDAG->getTargetNode(RemOp, MVT::Flag, RemOp1, RemOp2); + + SDOperand MFInFlag = SDOperand(RemNode, 0); + return CurDAG->getTargetNode(Mips::MFHI, MVT::i32, MFInFlag); + } + } + + // Select the default instruction + SDNode *ResNode = SelectCode(N); + + #ifndef NDEBUG + DOUT << std::string(Indent-2, ' ') << "=> "; + if (ResNode == NULL || ResNode == N.Val) + DEBUG(N.Val->dump(CurDAG)); + else + DEBUG(ResNode->dump(CurDAG)); + DOUT << "\n"; + Indent -= 2; + #endif + + return ResNode; +} + +/// createMipsISelDag - This pass converts a legalized DAG into a +/// MIPS-specific DAG, ready for instruction scheduling. +FunctionPass *llvm::createMipsISelDag(MipsTargetMachine &TM) { + return new MipsDAGToDAGISel(TM); +} diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp new file mode 100644 index 00000000000..98da5756a0b --- /dev/null +++ b/lib/Target/Mips/MipsISelLowering.cpp @@ -0,0 +1,519 @@ +//===-- MipsISelLowering.cpp - Mips DAG Lowering Implementation -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interfaces that Mips uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mips-lower" + +#include "MipsISelLowering.h" +#include "MipsTargetMachine.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Function.h" +#include "llvm/Intrinsics.h" +#include "llvm/CallingConv.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/CodeGen/SSARegMap.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/Support/Debug.h" +#include +#include + +using namespace llvm; + +const char *MipsTargetLowering:: +getTargetNodeName(unsigned Opcode) const +{ + switch (Opcode) + { + case MipsISD::JmpLink : return "MipsISD::JmpLink"; + case MipsISD::Hi : return "MipsISD::Hi"; + case MipsISD::Lo : return "MipsISD::Lo"; + case MipsISD::Ret : return "MipsISD::Ret"; + default : return NULL; + } +} + +MipsTargetLowering:: +MipsTargetLowering(MipsTargetMachine &TM): TargetLowering(TM) +{ + // Mips does not have i1 type, so use i32 for + // setcc operations results (slt, sgt, ...). + setSetCCResultType(MVT::i32); + setSetCCResultContents(ZeroOrOneSetCCResult); + + // Set up the register classes + addRegisterClass(MVT::i32, Mips::CPURegsRegisterClass); + + // Custom + setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); + setOperationAction(ISD::RET, MVT::Other, Custom); + + // Load extented operations for i1 types must be promoted + setLoadXAction(ISD::EXTLOAD, MVT::i1, Promote); + setLoadXAction(ISD::ZEXTLOAD, MVT::i1, Promote); + setLoadXAction(ISD::SEXTLOAD, MVT::i1, Promote); + + // Store operations for i1 types must be promoted + setStoreXAction(MVT::i1, Promote); + + // Mips does not have these NodeTypes below. + setOperationAction(ISD::BR_JT, MVT::Other, Expand); + setOperationAction(ISD::BR_CC, MVT::Other, Expand); + setOperationAction(ISD::SELECT_CC, MVT::Other, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); + setOperationAction(ISD::SELECT, MVT::i32, Expand); + + // Mips not supported intrinsics. + setOperationAction(ISD::MEMMOVE, MVT::Other, Expand); + setOperationAction(ISD::MEMSET, MVT::Other, Expand); + setOperationAction(ISD::MEMCPY, MVT::Other, Expand); + + setOperationAction(ISD::CTPOP, MVT::i32, Expand); + setOperationAction(ISD::CTTZ , MVT::i32, Expand); + setOperationAction(ISD::CTLZ , MVT::i32, Expand); + setOperationAction(ISD::ROTL , MVT::i32, Expand); + setOperationAction(ISD::ROTR , MVT::i32, Expand); + setOperationAction(ISD::BSWAP, MVT::i32, Expand); + + setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand); + setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand); + setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand); + + // We don't have line number support yet. + setOperationAction(ISD::LOCATION, MVT::Other, Expand); + setOperationAction(ISD::DEBUG_LOC, MVT::Other, Expand); + setOperationAction(ISD::LABEL, MVT::Other, Expand); + + // Use the default for now + setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); + setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); + + setStackPointerRegisterToSaveRestore(Mips::SP); + computeRegisterProperties(); +} + + +SDOperand MipsTargetLowering:: +LowerOperation(SDOperand Op, SelectionDAG &DAG) +{ + switch (Op.getOpcode()) + { + case ISD::CALL: return LowerCALL(Op, DAG); + case ISD::FORMAL_ARGUMENTS: return LowerFORMAL_ARGUMENTS(Op, DAG); + case ISD::RET: return LowerRET(Op, DAG); + case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); + case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG); + } + return SDOperand(); +} + +//===----------------------------------------------------------------------===// +// Lower helper functions +//===----------------------------------------------------------------------===// + +// AddLiveIn - This helper function adds the specified physical register to the +// MachineFunction as a live in value. It also creates a corresponding +// virtual register for it. +static unsigned +AddLiveIn(MachineFunction &MF, unsigned PReg, TargetRegisterClass *RC) +{ + assert(RC->contains(PReg) && "Not the correct regclass!"); + unsigned VReg = MF.getSSARegMap()->createVirtualRegister(RC); + MF.addLiveIn(PReg, VReg); + return VReg; +} + +// Set up a frame object for the return address. +SDOperand MipsTargetLowering::getReturnAddressFrameIndex(SelectionDAG &DAG) { + if (ReturnAddrIndex == 0) { + MachineFunction &MF = DAG.getMachineFunction(); + ReturnAddrIndex = MF.getFrameInfo()->CreateFixedObject(4, 0); + } + + return DAG.getFrameIndex(ReturnAddrIndex, getPointerTy()); +} + + +//===----------------------------------------------------------------------===// +// Misc Lower Operation implementation +//===----------------------------------------------------------------------===// +SDOperand MipsTargetLowering:: +LowerGlobalAddress(SDOperand Op, SelectionDAG &DAG) +{ + GlobalValue *GV = cast(Op)->getGlobal(); + + SDOperand GA = DAG.getTargetGlobalAddress(GV, MVT::i32); + SDOperand Hi = DAG.getNode(MipsISD::Hi, MVT::i32, GA); + SDOperand Lo = DAG.getNode(MipsISD::Lo, MVT::i32, GA); + + return DAG.getNode(ISD::ADD, MVT::i32, Lo, Hi); +} + +SDOperand MipsTargetLowering:: +LowerRETURNADDR(SDOperand Op, SelectionDAG &DAG) { + // Depths > 0 not supported yet! + if (cast(Op.getOperand(0))->getValue() > 0) + return SDOperand(); + + // Just load the return address + SDOperand RetAddrFI = getReturnAddressFrameIndex(DAG); + return DAG.getLoad(getPointerTy(), DAG.getEntryNode(), RetAddrFI, NULL, 0); +} + +//===----------------------------------------------------------------------===// +// Calling Convention Implementation +// +// The lower operations present on calling convention works on this order: +// LowerCALL (virt regs --> phys regs, virt regs --> stack) +// LowerFORMAL_ARGUMENTS (phys --> virt regs, stack --> virt regs) +// LowerRET (virt regs --> phys regs) +// LowerCALL (phys regs --> virt regs) +// +//===----------------------------------------------------------------------===// + +#include "MipsGenCallingConv.inc" + +//===----------------------------------------------------------------------===// +// CALL Calling Convention Implementation +//===----------------------------------------------------------------------===// + +/// Mips custom CALL implementation +SDOperand MipsTargetLowering:: +LowerCALL(SDOperand Op, SelectionDAG &DAG) +{ + unsigned CallingConv= cast(Op.getOperand(1))->getValue(); + + // By now, only CallingConv::C implemented + switch (CallingConv) + { + default: + assert(0 && "Unsupported calling convention"); + case CallingConv::Fast: + case CallingConv::C: + return LowerCCCCallTo(Op, DAG, CallingConv); + } +} + +/// LowerCCCCallTo - functions arguments are copied from virtual +/// regs to (physical regs)/(stack frame), CALLSEQ_START and +/// CALLSEQ_END are emitted. +/// TODO: isVarArg, isTailCall, sret, GOT, linkage types. +SDOperand MipsTargetLowering:: +LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG, unsigned CC) +{ + SDOperand Chain = Op.getOperand(0); + SDOperand Callee = Op.getOperand(4); + + // Analyze operands of the call, assigning locations to each operand. + SmallVector ArgLocs; + CCState CCInfo(CC, getTargetMachine(), ArgLocs); + CCInfo.AnalyzeCallOperands(Op.Val, CC_Mips); + + // Get a count of how many bytes are to be pushed on the stack. + unsigned NumBytes = CCInfo.getNextStackOffset(); + + Chain = DAG.getCALLSEQ_START(Chain,DAG.getConstant(NumBytes, + getPointerTy())); + + SmallVector, 8> RegsToPass; + SmallVector MemOpChains; + + SDOperand StackPtr; + + // Walk the register/memloc assignments, inserting copies/loads. + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + + // Arguments start after the 5 first operands of ISD::CALL + SDOperand Arg = Op.getOperand(5+2*VA.getValNo()); + + // Promote the value if needed. + switch (VA.getLocInfo()) { + default: assert(0 && "Unknown loc info!"); + case CCValAssign::Full: break; + case CCValAssign::SExt: + Arg = DAG.getNode(ISD::SIGN_EXTEND, VA.getLocVT(), Arg); + break; + case CCValAssign::ZExt: + Arg = DAG.getNode(ISD::ZERO_EXTEND, VA.getLocVT(), Arg); + break; + case CCValAssign::AExt: + Arg = DAG.getNode(ISD::ANY_EXTEND, VA.getLocVT(), Arg); + break; + } + + // Arguments that can be passed on register, + // must be kept at RegsToPass vector + if (VA.isRegLoc()) { + RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); + } else { + assert(VA.isMemLoc()); + // Mips::SP holds our stack pointer + if (StackPtr.Val == 0) + StackPtr = DAG.getRegister(Mips::SP, getPointerTy()); + + SDOperand PtrOff = DAG.getConstant(VA.getLocMemOffset(), + getPointerTy()); + + // emit a ISD::ADD which emits the final + // stack location to place the parameter + PtrOff = DAG.getNode(ISD::ADD, getPointerTy(), StackPtr, PtrOff); + + // emit ISD::STORE whichs stores the + // parameter value to a stack Location + MemOpChains.push_back(DAG.getStore(Chain, Arg, PtrOff, NULL, 0)); + } + } + + // Transform all store nodes into one single node because + // all store nodes ar independent of each other. + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, MVT::Other, + &MemOpChains[0], MemOpChains.size()); + + // Build a sequence of copy-to-reg nodes chained together with token + // chain and flag operands which copy the outgoing args into registers. + // The InFlag in necessary since all emited instructions must be + // stuck together. + SDOperand InFlag; + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { + Chain = DAG.getCopyToReg(Chain, RegsToPass[i].first, + RegsToPass[i].second, InFlag); + InFlag = Chain.getValue(1); + } + + // If the callee is a GlobalAddress node (quite common, every direct + // call is) turn it into a TargetGlobalAddress node so that legalize + // doesn't hack it. + if (GlobalAddressSDNode *G = dyn_cast(Callee)) { + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), getPointerTy()); + } else + if (ExternalSymbolSDNode *S = dyn_cast(Callee)) + Callee = DAG.getTargetExternalSymbol(S->getSymbol(), getPointerTy()); + + // MipsJmpLink = #chain, #target_address, #opt_in_flags... + // = Chain, Callee, Reg#1, Reg#2, ... + // + // Returns a chain & a flag for retval copy to use. + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Flag); + SmallVector Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + + // Add argument registers to the end of the list so that they are + // known live into the call. + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) + Ops.push_back(DAG.getRegister(RegsToPass[i].first, + RegsToPass[i].second.getValueType())); + + if (InFlag.Val) + Ops.push_back(InFlag); + + Chain = DAG.getNode(MipsISD::JmpLink, NodeTys, &Ops[0], Ops.size()); + InFlag = Chain.getValue(1); + + // Create the CALLSEQ_END node. + NodeTys = DAG.getVTList(MVT::Other, MVT::Flag); + Ops.clear(); + Ops.push_back(Chain); + Ops.push_back(DAG.getConstant(NumBytes, getPointerTy())); + Ops.push_back(InFlag); + Chain = DAG.getNode(ISD::CALLSEQ_END, NodeTys, &Ops[0], Ops.size()); + InFlag = Chain.getValue(1); + + // Handle result values, copying them out of physregs into vregs that we + // return. + return SDOperand(LowerCallResult(Chain, InFlag, Op.Val, CC, DAG), Op.ResNo); +} + +/// LowerCallResult - Lower the result values of an ISD::CALL into the +/// appropriate copies out of appropriate physical registers. This assumes that +/// Chain/InFlag are the input chain/flag to use, and that TheCall is the call +/// being lowered. Returns a SDNode with the same number of values as the +/// ISD::CALL. +SDNode *MipsTargetLowering:: +LowerCallResult(SDOperand Chain, SDOperand InFlag, SDNode *TheCall, + unsigned CallingConv, SelectionDAG &DAG) { + + // Assign locations to each value returned by this call. + SmallVector RVLocs; + CCState CCInfo(CallingConv, getTargetMachine(), RVLocs); + CCInfo.AnalyzeCallResult(TheCall, RetCC_Mips); + SmallVector ResultVals; + + // returns void + if (!RVLocs.size()) + return Chain.Val; + + // Copy all of the result registers out of their specified physreg. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + Chain = DAG.getCopyFromReg(Chain, RVLocs[i].getLocReg(), + RVLocs[i].getValVT(), InFlag).getValue(1); + InFlag = Chain.getValue(2); + ResultVals.push_back(Chain.getValue(0)); + } + + // Merge everything together with a MERGE_VALUES node. + ResultVals.push_back(Chain); + return DAG.getNode(ISD::MERGE_VALUES, TheCall->getVTList(), + &ResultVals[0], ResultVals.size()).Val; +} + +//===----------------------------------------------------------------------===// +// FORMAL_ARGUMENTS Calling Convention Implementation +//===----------------------------------------------------------------------===// + +/// Mips custom FORMAL_ARGUMENTS implementation +SDOperand MipsTargetLowering:: +LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG) +{ + unsigned CC = cast(Op.getOperand(1))->getValue(); + switch(CC) + { + default: + assert(0 && "Unsupported calling convention"); + case CallingConv::C: + return LowerCCCArguments(Op, DAG); + } +} + +/// LowerCCCArguments - transform physical registers into +/// virtual registers and generate load operations for +/// arguments places on the stack. +/// TODO: isVarArg, sret +SDOperand MipsTargetLowering:: +LowerCCCArguments(SDOperand Op, SelectionDAG &DAG) +{ + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + SDOperand Root = Op.getOperand(0); + + // Assign locations to all of the incoming arguments. + SmallVector ArgLocs; + CCState CCInfo(MF.getFunction()->getCallingConv(), + getTargetMachine(), ArgLocs); + CCInfo.AnalyzeFormalArguments(Op.Val, CC_Mips); + SmallVector ArgValues; + + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + + CCValAssign &VA = ArgLocs[i]; + + // Arguments stored on registers + if (VA.isRegLoc()) { + MVT::ValueType RegVT = VA.getLocVT(); + TargetRegisterClass *RC; + + if (RegVT == MVT::i32) + RC = Mips::CPURegsRegisterClass; + else + assert(0 && "support only Mips::CPURegsRegisterClass"); + + unsigned Reg = AddLiveIn(DAG.getMachineFunction(), VA.getLocReg(), RC); + + // Transform the arguments stored on + // physical registers into virtual ones + SDOperand ArgValue = DAG.getCopyFromReg(Root, Reg, RegVT); + + // If this is an 8 or 16-bit value, it is really passed promoted + // to 32 bits. Insert an assert[sz]ext to capture this, then + // truncate to the right size. + if (VA.getLocInfo() == CCValAssign::SExt) + ArgValue = DAG.getNode(ISD::AssertSext, RegVT, ArgValue, + DAG.getValueType(VA.getValVT())); + else if (VA.getLocInfo() == CCValAssign::ZExt) + ArgValue = DAG.getNode(ISD::AssertZext, RegVT, ArgValue, + DAG.getValueType(VA.getValVT())); + + if (VA.getLocInfo() != CCValAssign::Full) + ArgValue = DAG.getNode(ISD::TRUNCATE, VA.getValVT(), ArgValue); + + ArgValues.push_back(ArgValue); + + } else { + // sanity check + assert(VA.isMemLoc()); + + // Create the frame index object for this incoming parameter... + int FI = MFI->CreateFixedObject(MVT::getSizeInBits(VA.getValVT())/8, + VA.getLocMemOffset()); + + // Create load nodes to retrieve arguments from the stack + SDOperand FIN = DAG.getFrameIndex(FI, getPointerTy()); + ArgValues.push_back(DAG.getLoad(VA.getValVT(), Root, FIN, NULL, 0)); + } + } + ArgValues.push_back(Root); + + ReturnAddrIndex = 0; + + // Return the new list of results. + return DAG.getNode(ISD::MERGE_VALUES, Op.Val->getVTList(), + &ArgValues[0], ArgValues.size()).getValue(Op.ResNo); +} + +//===----------------------------------------------------------------------===// +// Return Value Calling Convention Implementation +//===----------------------------------------------------------------------===// + +SDOperand MipsTargetLowering:: +LowerRET(SDOperand Op, SelectionDAG &DAG) +{ + // CCValAssign - represent the assignment of + // the return value to a location + SmallVector RVLocs; + unsigned CC = DAG.getMachineFunction().getFunction()->getCallingConv(); + + // CCState - Info about the registers and stack slot. + CCState CCInfo(CC, getTargetMachine(), RVLocs); + + // Analize return values of ISD::RET + CCInfo.AnalyzeReturn(Op.Val, RetCC_Mips); + + // If this is the first return lowered for this function, add + // the regs to the liveout set for the function. + if (DAG.getMachineFunction().liveout_empty()) { + for (unsigned i = 0; i != RVLocs.size(); ++i) + DAG.getMachineFunction().addLiveOut(RVLocs[i].getLocReg()); + } + + // The chain is always operand #0 + SDOperand Chain = Op.getOperand(0); + SDOperand Flag; + + // Copy the result values into the output registers. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + CCValAssign &VA = RVLocs[i]; + assert(VA.isRegLoc() && "Can only return in registers!"); + + // ISD::RET => ret chain, (regnum1,val1), ... + // So i*2+1 index only the regnums + Chain = DAG.getCopyToReg(Chain, VA.getLocReg(), + Op.getOperand(i*2+1), Flag); + + // guarantee that all emitted copies are + // stuck together, avoiding something bad + Flag = Chain.getValue(1); + } + + // Return on Mips is always a "jr $ra" + if (Flag.Val) + return DAG.getNode(MipsISD::Ret, MVT::Other, + Chain, DAG.getRegister(Mips::RA, MVT::i32), Flag); + else // Return Void + return DAG.getNode(MipsISD::Ret, MVT::Other, + Chain, DAG.getRegister(Mips::RA, MVT::i32)); +} diff --git a/lib/Target/Mips/MipsISelLowering.h b/lib/Target/Mips/MipsISelLowering.h new file mode 100644 index 00000000000..3300f403f6b --- /dev/null +++ b/lib/Target/Mips/MipsISelLowering.h @@ -0,0 +1,83 @@ +//===-- MipsISelLowering.h - Mips DAG Lowering Interface --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interfaces that Mips uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#ifndef MipsISELLOWERING_H +#define MipsISELLOWERING_H + +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/Target/TargetLowering.h" +#include "Mips.h" +#include "MipsSubtarget.h" + +namespace llvm { + namespace MipsISD { + enum NodeType { + // Start the numbering from where ISD NodeType finishes. + FIRST_NUMBER = ISD::BUILTIN_OP_END+Mips::INSTRUCTION_LIST_END, + + // Jump and link (call) + JmpLink, + + // Get the Higher 16 bits from a 32-bit immediate + // No relation with Mips Hi register + Hi, + + // Get the Lower 16 bits from a 32-bit immediate + // No relation with Mips Lo register + Lo, + + // Return + Ret + }; + } + + //===--------------------------------------------------------------------===// + // TargetLowering Implementation + //===--------------------------------------------------------------------===// + class MipsTargetLowering : public TargetLowering + { + // FrameIndex for return slot. + int ReturnAddrIndex; + + // const MipsSubtarget &MipsSubTarget; + public: + + MipsTargetLowering(MipsTargetMachine &TM); + + /// LowerOperation - Provide custom lowering hooks for some operations. + virtual SDOperand LowerOperation(SDOperand Op, SelectionDAG &DAG); + + /// getTargetNodeName - This method returns the name of a target specific + // DAG node. + virtual const char *getTargetNodeName(unsigned Opcode) const; + + private: + // Lower Operand helpers + SDOperand LowerCCCArguments(SDOperand Op, SelectionDAG &DAG); + SDOperand LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG, unsigned CC); + SDNode *LowerCallResult(SDOperand Chain, SDOperand InFlag, SDNode*TheCall, + unsigned CallingConv, SelectionDAG &DAG); + SDOperand getReturnAddressFrameIndex(SelectionDAG &DAG); + + // Lower Operand specifics + SDOperand LowerRET(SDOperand Op, SelectionDAG &DAG); + SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG); + SDOperand LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG); + SDOperand LowerGlobalAddress(SDOperand Op, SelectionDAG &DAG); + SDOperand LowerRETURNADDR(SDOperand Op, SelectionDAG &DAG); + + }; +} + +#endif // MipsISELLOWERING_H diff --git a/lib/Target/Mips/MipsInstrFormats.td b/lib/Target/Mips/MipsInstrFormats.td new file mode 100644 index 00000000000..b88fa90a254 --- /dev/null +++ b/lib/Target/Mips/MipsInstrFormats.td @@ -0,0 +1,96 @@ +//===- MipsRegisterInfo.td - Mips Register defs -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Describe MIPS instructions format +// +// All the possible Mips fields are: +// +// opcode - operation code. +// rs - src reg. +// rt - dst reg (on a 2 regs instr) or src reg (on a 3 reg instr). +// rd - dst reg, only used on 3 regs instr. +// shamt - only used on shift instructions, contains the shift amount. +// funct - combined with opcode field give us an operation code. +// +//===----------------------------------------------------------------------===// + +// Generic Mips Format +class MipsInst pattern>: + Instruction +{ + field bits<32> Inst; + + let Namespace = "Mips"; + + bits<6> opcode; + + // Top 5 bits are the 'opcode' field + let Inst{31-26} = opcode; + + dag OperandList = ops; + let AsmString = asmstr; + let Pattern = pattern; +} + + +//===----------------------------------------------------------------------===// +// Format R instruction class in Mips : <|opcode|rs|rt|rd|shamt|funct|> +//===----------------------------------------------------------------------===// + +class FR op, bits<6> _funct, dag ops, string asmstr, list pattern>: + MipsInst +{ + bits<5> rd; + bits<5> rs; + bits<5> rt; + bits<5> shamt; + bits<6> funct; + + let opcode = op; + let funct = _funct; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = shamt; + let Inst{5-0} = funct; +} + +//===----------------------------------------------------------------------===// +// Format I instruction class in Mips : <|opcode|rs|rt|immediate|> +//===----------------------------------------------------------------------===// + +class FI op, dag ops, string asmstr, list pattern>: + MipsInst +{ + bits<5> rt; + bits<5> rs; + bits<16> imm16; + + let opcode = op; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-0} = imm16; +} + +//===----------------------------------------------------------------------===// +// Format J instruction class in Mips : <|opcode|address|> +//===----------------------------------------------------------------------===// + +class FJ op, dag ops, string asmstr, list pattern>: + MipsInst +{ + bits<26> addr; + + let opcode = op; + + let Inst{25-0} = addr; +} diff --git a/lib/Target/Mips/MipsInstrInfo.cpp b/lib/Target/Mips/MipsInstrInfo.cpp new file mode 100644 index 00000000000..808403067e8 --- /dev/null +++ b/lib/Target/Mips/MipsInstrInfo.cpp @@ -0,0 +1,114 @@ +//===- MipsInstrInfo.cpp - Mips Instruction Information ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "Mips.h" +#include "MipsInstrInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "MipsGenInstrInfo.inc" + +using namespace llvm; + +// TODO: Add the subtarget support on this constructor +MipsInstrInfo::MipsInstrInfo(MipsTargetMachine &tm) + : TargetInstrInfo(MipsInsts, sizeof(MipsInsts)/sizeof(MipsInsts[0])), + TM(tm), RI(*this) {} + +static bool isZeroImm(const MachineOperand &op) { + return op.isImmediate() && op.getImmedValue() == 0; +} + +/// Return true if the instruction is a register to register move and +/// leave the source and dest operands in the passed parameters. +bool MipsInstrInfo:: +isMoveInstr(const MachineInstr &MI, unsigned &SrcReg, unsigned &DstReg) const +{ + // addu $dst, $src, $zero || addu $dst, $zero, $src + // or $dst, $src, $zero || or $dst, $zero, $src + if ((MI.getOpcode() == Mips::ADDu) || (MI.getOpcode() == Mips::OR)) + { + if (MI.getOperand(1).getReg() == Mips::ZERO) { + DstReg = MI.getOperand(0).getReg(); + SrcReg = MI.getOperand(2).getReg(); + return true; + } else if (MI.getOperand(2).getReg() == Mips::ZERO) { + DstReg = MI.getOperand(0).getReg(); + SrcReg = MI.getOperand(1).getReg(); + return true; + } + } + + // addiu $dst, $src, 0 + if (MI.getOpcode() == Mips::ADDiu) + { + if ((MI.getOperand(1).isRegister()) && (isZeroImm(MI.getOperand(2)))) { + DstReg = MI.getOperand(0).getReg(); + SrcReg = MI.getOperand(1).getReg(); + return true; + } + } + return false; +} + +/// isLoadFromStackSlot - If the specified machine instruction is a direct +/// load from a stack slot, return the virtual or physical register number of +/// the destination along with the FrameIndex of the loaded stack slot. If +/// not, return 0. This predicate must return 0 if the instruction has +/// any side effects other than loading from the stack slot. +unsigned MipsInstrInfo:: +isLoadFromStackSlot(MachineInstr *MI, int &FrameIndex) const +{ + // TODO: add lhu, lbu ??? + if (MI->getOpcode() == Mips::LW) + { + if ((MI->getOperand(2).isFrameIndex()) && // is a stack slot + (MI->getOperand(1).isImmediate()) && // the imm is zero + (isZeroImm(MI->getOperand(1)))) + { + FrameIndex = MI->getOperand(2).getFrameIndex(); + return MI->getOperand(0).getReg(); + } + } + + return 0; +} + +/// isStoreToStackSlot - If the specified machine instruction is a direct +/// store to a stack slot, return the virtual or physical register number of +/// the source reg along with the FrameIndex of the loaded stack slot. If +/// not, return 0. This predicate must return 0 if the instruction has +/// any side effects other than storing to the stack slot. +unsigned MipsInstrInfo:: +isStoreToStackSlot(MachineInstr *MI, int &FrameIndex) const +{ + // TODO: add sb, sh ??? + if (MI->getOpcode() == Mips::SW) { + if ((MI->getOperand(0).isFrameIndex()) && // is a stack slot + (MI->getOperand(1).isImmediate()) && // the imm is zero + (isZeroImm(MI->getOperand(1)))) + { + FrameIndex = MI->getOperand(0).getFrameIndex(); + return MI->getOperand(2).getReg(); + } + } + return 0; +} + +unsigned MipsInstrInfo:: +InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, const std::vector &Cond) + const +{ + // TODO: add Mips::J here. + assert(0 && "Cant handle any kind of branches!"); + return 1; +} diff --git a/lib/Target/Mips/MipsInstrInfo.h b/lib/Target/Mips/MipsInstrInfo.h new file mode 100644 index 00000000000..356cf3d7006 --- /dev/null +++ b/lib/Target/Mips/MipsInstrInfo.h @@ -0,0 +1,63 @@ +//===- MipsInstrInfo.h - Mips Instruction Information -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSINSTRUCTIONINFO_H +#define MIPSINSTRUCTIONINFO_H + +#include "Mips.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "MipsRegisterInfo.h" + +namespace llvm { + +class MipsInstrInfo : public TargetInstrInfo +{ + MipsTargetMachine &TM; + const MipsRegisterInfo RI; +public: + MipsInstrInfo(MipsTargetMachine &TM); + + /// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As + /// such, whenever a client has an instance of instruction info, it should + /// always be able to get register info as well (through this method). + /// + virtual const MRegisterInfo &getRegisterInfo() const { return RI; } + + /// Return true if the instruction is a register to register move and + /// leave the source and dest operands in the passed parameters. + /// + virtual bool isMoveInstr(const MachineInstr &MI, + unsigned &SrcReg, unsigned &DstReg) const; + + /// isLoadFromStackSlot - If the specified machine instruction is a direct + /// load from a stack slot, return the virtual or physical register number of + /// the destination along with the FrameIndex of the loaded stack slot. If + /// not, return 0. This predicate must return 0 if the instruction has + /// any side effects other than loading from the stack slot. + virtual unsigned isLoadFromStackSlot(MachineInstr *MI, int &FrameIndex) const; + + /// isStoreToStackSlot - If the specified machine instruction is a direct + /// store to a stack slot, return the virtual or physical register number of + /// the source reg along with the FrameIndex of the loaded stack slot. If + /// not, return 0. This predicate must return 0 if the instruction has + /// any side effects other than storing to the stack slot. + virtual unsigned isStoreToStackSlot(MachineInstr *MI, int &FrameIndex) const; + + virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const std::vector &Cond) const; +}; + +} + +#endif diff --git a/lib/Target/Mips/MipsInstrInfo.td b/lib/Target/Mips/MipsInstrInfo.td new file mode 100644 index 00000000000..0a7e3ce29cf --- /dev/null +++ b/lib/Target/Mips/MipsInstrInfo.td @@ -0,0 +1,468 @@ +//===- MipsInstrInfo.td - Mips Register defs --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Instruction format superclass +//===----------------------------------------------------------------------===// + +include "MipsInstrFormats.td" + +//===----------------------------------------------------------------------===// +// Mips profiles and nodes +//===----------------------------------------------------------------------===// + +// Call +def SDT_MipsJmpLink : SDTypeProfile<0, 1, [SDTCisVT<0, iPTR>]>; +def MipsJmpLink : SDNode<"MipsISD::JmpLink",SDT_MipsJmpLink, [SDNPHasChain, + SDNPOutFlag]>; + +// Hi and Lo nodes are created to let easy manipulation of 16-bit when +// handling 32-bit immediates. They are used on MipsISelLowering to +// lower stuff like GlobalAddress, ExternalSymbol, ... +// This two nodes have nothing to do with Mips Registers Hi and Lo. +def MipsHi : SDNode<"MipsISD::Hi", SDTIntUnaryOp>; +def MipsLo : SDNode<"MipsISD::Lo", SDTIntUnaryOp>; + +// Return +def SDT_MipsRet : SDTypeProfile<0, 1, [SDTCisInt<0>]>; +def MipsRet : SDNode<"MipsISD::Ret", SDT_MipsRet, [SDNPHasChain, + SDNPOptInFlag]>; + +// These are target-independent nodes, but have target-specific formats. +def SDT_MipsCallSeq : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>; +def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_MipsCallSeq, + [SDNPHasChain, SDNPOutFlag]>; +def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_MipsCallSeq, + [SDNPHasChain, SDNPOutFlag]>; + +// Instruction operand types +def brtarget : Operand; +def calltarget : Operand; +def uimm16 : Operand; +def simm16 : Operand; +def shamt : Operand; + +// Address operand +def mem : Operand { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops simm16, CPURegs); +} + +//===----------------------------------------------------------------------===// +// Mips Patterns and Transformations +//===----------------------------------------------------------------------===// + +// Transformation Function - get the lower 16 bits. +def LO16 : SDNodeXFormgetValue() & 0xFFFF); +}]>; + +// Transformation Function - get the higher 16 bits. +def HI16 : SDNodeXFormgetValue() >> 16); +}]>; + +// Node immediate fits as 16-bit sign extended on target immediate. +// e.g. addi, andi +def immSExt16 : PatLeaf<(imm), [{ + if (N->getValueType(0) == MVT::i32) + return (int32_t)N->getValue() == (short)N->getValue(); + else + return (int64_t)N->getValue() == (short)N->getValue(); +}]>; + +// Node immediate fits as 16-bit zero extended on target immediate. +// The LO16 param means that only the lower 16 bits of the node +// immediate are caught. +// e.g. addiu, sltiu +def immZExt16 : PatLeaf<(imm), [{ + return (uint64_t)N->getValue() == (unsigned short)N->getValue(); +}], LO16>; + +// Node immediate must have only it's 16 high bits set. +// The HI16 param means that only the higher 16 bits of the node +// immediate are caught. +// e.g. lui +def imm16ShiftedZExt : PatLeaf<(imm), [{ + return (N->getValue() & ~uint64_t(0xFFFF0000)) == 0; +}], HI16>; + +// shamt field must fit in 5 bits. +def immZExt5 : PatLeaf<(imm), [{ + return N->getValue() == ((N->getValue()) & 0x1f) ; +}]>; + +// Mips Address Mode! SDNode frameindex could possibily be a match +// since load and store instructions from stack used it. +def addr : ComplexPattern; + +//===----------------------------------------------------------------------===// +// Instructions specific format +//===----------------------------------------------------------------------===// + +// Arithmetic 3 register operands +let isCommutable = 1 in +class ArithR< bits<6> op, bits<6> func, string instr_asm, SDNode OpNode>: + FR< op, + func, + (ops CPURegs:$dst, CPURegs:$b, CPURegs:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [(set CPURegs:$dst, (OpNode CPURegs:$b, CPURegs:$c))] >; + +let isCommutable = 1 in +class ArithOverflowR< bits<6> op, bits<6> func, string instr_asm>: + FR< op, + func, + (ops CPURegs:$dst, CPURegs:$b, CPURegs:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + []>; + +// Arithmetic 2 register operands +let isCommutable = 1 in +class ArithI op, string instr_asm, SDNode OpNode, + Operand Od, PatLeaf imm_type> : + FI< op, + (ops CPURegs:$dst, CPURegs:$b, Od:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [(set CPURegs:$dst, (OpNode CPURegs:$b, imm_type:$c))] >; + +// Arithmetic Multiply ADD/SUB +let rd=0 in +class MArithR func, string instr_asm> : + FR< 0x1c, + func, + (ops CPURegs:$rs, CPURegs:$rt), + !strconcat(instr_asm, " $rs, $rt"), + []>; + +// Logical +class LogicR func, string instr_asm, SDNode OpNode>: + FR< 0x00, + func, + (ops CPURegs:$dst, CPURegs:$b, CPURegs:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [(set CPURegs:$dst, (OpNode CPURegs:$b, CPURegs:$c))] >; + +class LogicI op, string instr_asm, SDNode OpNode>: + FI< op, + (ops CPURegs:$dst, CPURegs:$b, uimm16:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [(set CPURegs:$dst, (OpNode CPURegs:$b, immSExt16:$c))]>; + +class LogicNOR op, bits<6> func, string instr_asm>: + FR< op, + func, + (ops CPURegs:$dst, CPURegs:$b, CPURegs:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [(set CPURegs:$dst, (not (or CPURegs:$b, CPURegs:$c)))] >; + +// Shifts +let rt = 0 in +class LogicR_shift_imm func, string instr_asm, SDNode OpNode>: + FR< 0x00, + func, + (ops CPURegs:$dst, CPURegs:$b, shamt:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [(set CPURegs:$dst, (OpNode CPURegs:$b, immZExt5:$c))] >; + +class LogicR_shift_reg func, string instr_asm, SDNode OpNode>: + FR< 0x00, + func, + (ops CPURegs:$dst, CPURegs:$b, CPURegs:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [(set CPURegs:$dst, (OpNode CPURegs:$b, CPURegs:$c))] >; + +// Load Upper Imediate +class LoadUpper op, string instr_asm>: + FI< op, + (ops CPURegs:$dst, uimm16:$imm), + !strconcat(instr_asm, " $dst, $imm"), + [(set CPURegs:$dst, imm16ShiftedZExt:$imm)]>; + +// Memory Load/Store +let isLoad = 1 in +class LoadM op, string instr_asm, PatFrag OpNode>: + FI< op, + (ops CPURegs:$dst, mem:$addr), + !strconcat(instr_asm, " $dst, $addr"), + [(set CPURegs:$dst, (OpNode addr:$addr))]>; + +let isStore = 1 in +class StoreM op, string instr_asm, PatFrag OpNode>: + FI< op, + (ops CPURegs:$dst, mem:$addr), + !strconcat(instr_asm, " $dst, $addr"), + [(OpNode CPURegs:$dst, addr:$addr)]>; + +// Conditional Branch +let isBranch = 1, noResults=1, isTerminator=1 in +class CBranch op, string instr_asm, PatFrag cond_op>: + FI< op, + (ops CPURegs:$a, CPURegs:$b, brtarget:$offset), + !strconcat(instr_asm, " $a, $b, $offset"), + [(brcond (cond_op CPURegs:$a, CPURegs:$b), bb:$offset)]>; + +class SetCC_R op, bits<6> func, string instr_asm, + PatFrag cond_op>: + FR< op, + func, + (ops CPURegs:$dst, CPURegs:$b, CPURegs:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [(set CPURegs:$dst, (cond_op CPURegs:$b, CPURegs:$c))]>; + +class SetCC_I op, string instr_asm, PatFrag cond_op, + Operand Od, PatLeaf imm_type>: + FI< op, + (ops CPURegs:$dst, CPURegs:$b, Od:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [(set CPURegs:$dst, (cond_op CPURegs:$b, imm_type:$c))]>; + +// Unconditional branch +let hasCtrlDep=1, noResults=1, isTerminator=1 in +class JumpFJ op, string instr_asm>: + FJ< op, + (ops brtarget:$target), + !strconcat(instr_asm, " $target"), + [(br bb:$target)]>; + +let hasCtrlDep=1, noResults=1, isTerminator=1, rd=0 in +class JumpFR op, bits<6> func, string instr_asm>: + FR< op, + func, + (ops CPURegs:$target), + !strconcat(instr_asm, " $target"), + []>; + +// Jump and Link (Call) +let isCall=1 in +class JumpLink op, string instr_asm>: + FJ< op, + (ops calltarget:$target), + !strconcat(instr_asm, " $target"), + [(MipsJmpLink imm:$target)]>; + +let isCall=1 in +class JumpLinkReg op, bits<6> func, string instr_asm>: + FR< op, + func, + (ops CPURegs:$rd, CPURegs:$rs), + !strconcat(instr_asm, " $rs, $rd"), + []>; + +// Mul, Div +class MulDiv func, string instr_asm>: + FR< 0x00, + func, + (ops CPURegs:$a, CPURegs:$b), + !strconcat(instr_asm, " $a, $b"), + []>; + +// Move from Hi/Lo +class MoveFromTo func, string instr_asm>: + FR< 0x00, + func, + (ops CPURegs:$dst), + !strconcat(instr_asm, " $dst"), + []>; + +// Count Leading Ones/Zeros in Word +class CountLeading func, string instr_asm>: + FR< 0x1c, + func, + (ops CPURegs:$dst, CPURegs:$src), + !strconcat(instr_asm, " $dst, $src"), + []>; + + +//===----------------------------------------------------------------------===// +// Pseudo instructions +//===----------------------------------------------------------------------===// + +class Pseudo pattern>: + MipsInst; + +// As stack alignment is always done with addiu, we need a 16-bit immediate +def ADJCALLSTACKDOWN : Pseudo<(ops uimm16:$amt), + "!ADJCALLSTACKDOWN $amt", + [(callseq_start imm:$amt)]>, Imp<[SP],[SP]>; +def ADJCALLSTACKUP : Pseudo<(ops uimm16:$amt), + "!ADJCALLSTACKUP $amt", + [(callseq_end imm:$amt)]>, Imp<[SP],[SP]>; + +def IMPLICIT_DEF_CPURegs : Pseudo<(ops CPURegs:$dst), + "!IMPLICIT_DEF $dst", + [(set CPURegs:$dst, (undef))]>; + +//===----------------------------------------------------------------------===// +// Instruction definition +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Mips32 I +//===----------------------------------------------------------------------===// + +// Arithmetic +def ADDi : ArithI<0x08, "addi", add, simm16, immZExt16>; +def ADDiu : ArithI<0x09, "addiu", add, uimm16, immSExt16>; +def MUL : ArithR<0x1c, 0x02, "mul", mul>; +def ADDu : ArithR<0x00, 0x21, "addu", add>; +def SUBu : ArithR<0x00, 0x23, "subu", sub>; +def ADD : ArithOverflowR<0x00, 0x20, "add">; +def SUB : ArithOverflowR<0x00, 0x22, "sub">; +def MADD : MArithR<0x00, "madd">; +def MADDU : MArithR<0x01, "maddu">; +def MSUB : MArithR<0x04, "msub">; +def MSUBU : MArithR<0x05, "msubu">; + +// Logical +def AND : LogicR<0x24, "and", and>; +def OR : LogicR<0x25, "or", or>; +def XOR : LogicR<0x26, "xor", xor>; +def ANDi : LogicI<0x0c, "andi", and>; +def ORi : LogicI<0x0d, "ori", or>; +def XORi : LogicI<0x0e, "xori", xor>; +def NOR : LogicNOR<0x00, 0x27, "nor">; + +// Shifts +def SLL : LogicR_shift_imm<0x00, "sll", shl>; +def SRL : LogicR_shift_imm<0x02, "srl", srl>; +def SRA : LogicR_shift_imm<0x03, "sra", sra>; +def SLLV : LogicR_shift_reg<0x04, "sllv", shl>; +def SRLV : LogicR_shift_reg<0x06, "srlv", srl>; +def SRAV : LogicR_shift_reg<0x07, "srav", sra>; + +// Load Upper Immediate +def LUi : LoadUpper<0x0f, "lui">; + +// Load/Store +def LB : LoadM<0x20, "lb", sextloadi8>; +def LBu : LoadM<0x24, "lbu", zextloadi8>; +def LH : LoadM<0x21, "lh", sextloadi16>; +def LHu : LoadM<0x25, "lhu", zextloadi16>; +def LW : LoadM<0x23, "lw", load>; +def SB : StoreM<0x28, "sb", truncstorei8>; +def SH : StoreM<0x29, "sh", truncstorei16>; +def SW : StoreM<0x2b, "sw", store>; + +// Conditional Branch +def BEQ : CBranch<0x04, "beq", seteq>; +def BNE : CBranch<0x05, "bne", setne>; +def SLT : SetCC_R<0x00, 0x2a, "slt", setlt>; +def SLTu : SetCC_R<0x00, 0x2b, "sltu", setult>; +def SLTi : SetCC_I<0x0a, "slti", setlt, simm16, immSExt16>; +def SLTiu : SetCC_I<0x0b, "sltiu", setult, uimm16, immZExt16>; + +// Unconditional jump +def J : JumpFJ<0x02, "j">; +def JR : JumpFR<0x00, 0x08, "jr">; + +// Jump and Link (Call) +def JAL : JumpLink<0x03, "jal">; +def JALR : JumpLinkReg<0x00, 0x09, "jalr">; + +// MulDiv and Move From Hi/Lo operations, have +// their correpondent SDNodes created on ISelDAG. +// Special Mul, Div operations +def MULT : MulDiv<0x18, "mult">; +def MULTu : MulDiv<0x19, "multu">; +def DIV : MulDiv<0x1a, "div">; +def DIVu : MulDiv<0x1b, "divu">; + +// Move From Hi/Lo +def MFHI : MoveFromTo<0x10, "mfhi">; +def MFLO : MoveFromTo<0x12, "mflo">; +def MTHI : MoveFromTo<0x11, "mthi">; +def MTLO : MoveFromTo<0x13, "mtlo">; + +// Count Leading +def CLO : CountLeading<0x21, "clo">; +def CLZ : CountLeading<0x20, "clz">; + +// No operation +let addr=0 in +def NOOP : FJ<0, (ops), "nop", []>; + +// Ret instruction - as mips does not have "ret" a +// jr $ra must be generated. +let isReturn=1, isTerminator=1, hasDelaySlot=1, noResults=1, + isBarrier=1, hasCtrlDep=1, rs=0, rt=0, shamt=0 in +{ + def RET : FR <0x00, 0x02, (ops CPURegs:$target), + "jr $target", [(MipsRet CPURegs:$target)]>; +} + +//===----------------------------------------------------------------------===// +// Arbitrary patterns that map to one or more instructions +//===----------------------------------------------------------------------===// + +// Small immediates +def : Pat<(i32 immSExt16:$in), + (ORi ZERO, imm:$in)>; + +// Arbitrary immediates +def : Pat<(i32 imm:$imm), + (ORi (LUi (HI16 imm:$imm)), (LO16 imm:$imm))>; + +// Call +def : Pat<(MipsJmpLink (i32 tglobaladdr:$dst)), + (JAL tglobaladdr:$dst)>; +def : Pat<(MipsJmpLink (i32 texternalsym:$dst)), + (JAL texternalsym:$dst)>; + +// GlobalAddress, Constant Pool, ExternalSymbol, and JumpTable +def : Pat<(MipsHi tglobaladdr:$in), (LUi tglobaladdr:$in)>; +def : Pat<(MipsLo tglobaladdr:$in), (ADDiu ZERO, tglobaladdr:$in)>; + +// When extracting the address from GlobalAddress we +// need something of the form "addiu $reg, %lo(addr)" +def : Pat<(add CPURegs:$a, (MipsLo tglobaladdr:$in)), + (ADDiu CPURegs:$a, tglobaladdr:$in)>; + +// Mips does not have not, so we increase the operation +def : Pat<(not CPURegs:$in), + (NOR CPURegs:$in, CPURegs:$in)>; + +// extended load and stores +def : Pat<(i32 (extloadi8 addr:$src)), (LBu addr:$src)>; +def : Pat<(i32 (extloadi16 addr:$src)), (LHu addr:$src)>; +def : Pat<(truncstorei1 CPURegs:$src, addr:$addr), + (SB CPURegs:$src, addr:$src)>; + +// Conditional branch patterns. +// cond branches patterns, 2 register operands signed. +def : Pat<(brcond (setlt CPURegs:$lhs, CPURegs:$rhs), bb:$dst), + (BNE (SLT CPURegs:$lhs, CPURegs:$rhs), ZERO, bb:$dst)>; +def : Pat<(brcond (setle CPURegs:$lhs, CPURegs:$rhs), bb:$dst), + (BEQ (SLT CPURegs:$rhs, CPURegs:$lhs), ZERO, bb:$dst)>; +def : Pat<(brcond (setgt CPURegs:$lhs, CPURegs:$rhs), bb:$dst), + (BNE (SLT CPURegs:$rhs, CPURegs:$lhs), ZERO, bb:$dst)>; +def : Pat<(brcond (setge CPURegs:$lhs, CPURegs:$rhs), bb:$dst), + (BEQ (SLT CPURegs:$lhs, CPURegs:$rhs), ZERO, bb:$dst)>; + +// cond branches patterns, 2 register operands unsigned. +def : Pat<(brcond (setult CPURegs:$lhs, CPURegs:$rhs), bb:$dst), + (BNE (SLTu CPURegs:$lhs, CPURegs:$rhs), ZERO, bb:$dst)>; +def : Pat<(brcond (setule CPURegs:$lhs, CPURegs:$rhs), bb:$dst), + (BEQ (SLTu CPURegs:$rhs, CPURegs:$lhs), ZERO, bb:$dst)>; +def : Pat<(brcond (setugt CPURegs:$lhs, CPURegs:$rhs), bb:$dst), + (BNE (SLTu CPURegs:$rhs, CPURegs:$lhs), ZERO, bb:$dst)>; +def : Pat<(brcond (setuge CPURegs:$lhs, CPURegs:$rhs), bb:$dst), + (BEQ (SLTu CPURegs:$lhs, CPURegs:$rhs), ZERO, bb:$dst)>; + +// cond branches patterns, reg/imm operands signed. +def : Pat<(brcond (setult CPURegs:$lhs, immSExt16:$rhs), bb:$dst), + (BNE (SLTi CPURegs:$lhs, immSExt16:$rhs), ZERO, bb:$dst)>; +def : Pat<(brcond (setuge CPURegs:$lhs, immSExt16:$rhs), bb:$dst), + (BEQ (SLTi CPURegs:$lhs, immSExt16:$rhs), ZERO, bb:$dst)>; + +// cond branches patterns, reg/imm operands unsigned. +def : Pat<(brcond (setult CPURegs:$lhs, immZExt16:$rhs), bb:$dst), + (BNE (SLTiu CPURegs:$lhs, immZExt16:$rhs), ZERO, bb:$dst)>; +def : Pat<(brcond (setuge CPURegs:$lhs, immZExt16:$rhs), bb:$dst), + (BEQ (SLTiu CPURegs:$lhs, immZExt16:$rhs), ZERO, bb:$dst)>; diff --git a/lib/Target/Mips/MipsRegisterInfo.cpp b/lib/Target/Mips/MipsRegisterInfo.cpp new file mode 100644 index 00000000000..a23a4264cfe --- /dev/null +++ b/lib/Target/Mips/MipsRegisterInfo.cpp @@ -0,0 +1,288 @@ +//===- MipsRegisterInfo.cpp - MIPS Register Information -== -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the MIPS implementation of the MRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mips-reg-info" + +#include "Mips.h" +#include "MipsRegisterInfo.h" +#include "llvm/Constants.h" +#include "llvm/Type.h" +#include "llvm/Function.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineLocation.h" +#include "llvm/Target/TargetFrameInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" +//#include "MipsSubtarget.h" + +using namespace llvm; + +// TODO: add subtarget support +MipsRegisterInfo::MipsRegisterInfo(const TargetInstrInfo &tii) + : MipsGenRegisterInfo(Mips::ADJCALLSTACKDOWN, Mips::ADJCALLSTACKUP), + TII(tii) {} + +void MipsRegisterInfo:: +storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned SrcReg, int FI, + const TargetRegisterClass *RC) const +{ + if (RC == Mips::CPURegsRegisterClass) + BuildMI(MBB, I, TII.get(Mips::SW)).addFrameIndex(FI) + .addImm(0).addReg(SrcReg, false, false, true); + else + assert(0 && "Can't store this register to stack slot"); +} + +void MipsRegisterInfo:: +loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned DestReg, int FI, + const TargetRegisterClass *RC) const +{ + if (RC == Mips::CPURegsRegisterClass) + BuildMI(MBB, I, TII.get(Mips::LW), DestReg).addImm(0).addFrameIndex(FI); + else + assert(0 && "Can't load this register from stack slot"); +} + +void MipsRegisterInfo:: +copyRegToReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned DestReg, unsigned SrcReg, + const TargetRegisterClass *RC) const +{ + if (RC == Mips::CPURegsRegisterClass) + BuildMI(MBB, I, TII.get(Mips::ADDu), DestReg).addReg(Mips::ZERO) + .addReg(SrcReg); + else + assert (0 && "Can't copy this register"); +} + +void MipsRegisterInfo::reMaterialize(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned DestReg, + const MachineInstr *Orig) const +{ + MachineInstr *MI = Orig->clone(); + MI->getOperand(0).setReg(DestReg); + MBB.insert(I, MI); +} + +MachineInstr *MipsRegisterInfo:: +foldMemoryOperand(MachineInstr* MI, unsigned OpNum, int FI) const +{ + MachineInstr *NewMI = NULL; + + switch (MI->getOpcode()) + { + case Mips::ADDu: + if ((MI->getOperand(0).isRegister()) && + (MI->getOperand(1).isRegister()) && + (MI->getOperand(1).getReg() == Mips::ZERO) && + (MI->getOperand(2).isRegister())) + { + if (OpNum == 0) // COPY -> STORE + NewMI = BuildMI(TII.get(Mips::SW)).addFrameIndex(FI) + .addImm(0).addReg(MI->getOperand(2).getReg()); + else // COPY -> LOAD + NewMI = BuildMI(TII.get(Mips::LW), MI->getOperand(0) + .getReg()).addImm(0).addFrameIndex(FI); + } + break; + } + + if (NewMI) + NewMI->copyKillDeadInfo(MI); + return NewMI; +} + +/// Mips Callee Saved Registers +const unsigned* MipsRegisterInfo:: +getCalleeSavedRegs() const +{ + // Mips calle-save register range is $16-$26(s0-s7) + static const unsigned CalleeSavedRegs[] = { + Mips::S0, Mips::S1, Mips::S2, Mips::S3, + Mips::S4, Mips::S5, Mips::S6, Mips::S7, 0 + }; + return CalleeSavedRegs; +} + +/// Mips Callee Saved Register Classes +const TargetRegisterClass* const* +MipsRegisterInfo::getCalleeSavedRegClasses() const +{ + static const TargetRegisterClass * const CalleeSavedRegClasses[] = { + &Mips::CPURegsRegClass, &Mips::CPURegsRegClass, + &Mips::CPURegsRegClass, &Mips::CPURegsRegClass, + &Mips::CPURegsRegClass, &Mips::CPURegsRegClass, + &Mips::CPURegsRegClass, &Mips::CPURegsRegClass, 0 + }; + return CalleeSavedRegClasses; +} + +BitVector MipsRegisterInfo:: +getReservedRegs(const MachineFunction &MF) const +{ + BitVector Reserved(getNumRegs()); + Reserved.set(Mips::ZERO); + Reserved.set(Mips::AT); + Reserved.set(Mips::K0); + Reserved.set(Mips::K1); + Reserved.set(Mips::GP); + Reserved.set(Mips::SP); + Reserved.set(Mips::FP); + Reserved.set(Mips::RA); + return Reserved; +} + +//===----------------------------------------------------------------------===// +// Stack Frame Processing methods +//===----------------------------------------------------------------------===// + +// True if target has frame pointer +bool MipsRegisterInfo:: +hasFP(const MachineFunction &MF) const { + return false; +} + +// This function eliminate ADJCALLSTACKDOWN, +// ADJCALLSTACKUP pseudo instructions +void MipsRegisterInfo:: +eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + // Simply discard ADJCALLSTACKDOWN, ADJCALLSTACKUP instructions. + MBB.erase(I); +} + +// FrameIndex represent objects inside a abstract stack. +// We must replace FrameIndex with an stack/frame pointer +// direct reference. +void MipsRegisterInfo:: +eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, + RegScavenger *RS) const +{ + unsigned i = 0; + MachineInstr &MI = *II; + MachineFunction &MF = *MI.getParent()->getParent(); + + while (!MI.getOperand(i).isFrameIndex()) { + ++i; + assert(i < MI.getNumOperands() && + "Instr doesn't have FrameIndex operand!"); + } + + // FrameInfo addressable stack objects are accessed + // using neg. offsets, so we must add with the stack + // size to obtain $sp relative address. + int FrameIndex = MI.getOperand(i).getFrameIndex(); + int stackSize = MF.getFrameInfo()->getStackSize(); + int spOffset = MF.getFrameInfo()->getObjectOffset(FrameIndex); + + #ifndef NDEBUG + DOUT << "\n<--------->\n"; + MI.print(DOUT); + DOUT << "FrameIndex : " << FrameIndex << "\n"; + DOUT << "spOffset : " << spOffset << "\n"; + DOUT << "stackSize : " << stackSize << "\n"; + #endif + + // If the FrameIndex points to a positive SPOffset this + // means we are inside the callee and getting the arguments + // from the caller stack + int Offset = (-(stackSize)) + spOffset; + + #ifndef NDEBUG + DOUT << "Offset : " << Offset << "\n"; + DOUT << "<--------->\n"; + #endif + + MI.getOperand(i-1).ChangeToImmediate(Offset); + MI.getOperand(i).ChangeToRegister(Mips::SP,false); +} + +void MipsRegisterInfo:: +emitPrologue(MachineFunction &MF) const +{ + MachineBasicBlock &MBB = MF.front(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + + // Get the number of bytes to allocate from the FrameInfo + int NumBytes = (int) MFI->getStackSize(); + + // Do we need to allocate space on the stack? + if (NumBytes == 0) return; + + // FIXME: is Stack Align needed here ?? (maybe it's done before...) + unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment(); + NumBytes = -((NumBytes+Align-1)/Align*Align); + + // Update frame info to pretend that this is part of the stack... + MFI->setStackSize(NumBytes); + + // adjust stack : addi sp, sp, (-imm) + BuildMI(MBB, MBB.begin(), TII.get(Mips::ADDi), Mips::SP) + .addReg(Mips::SP).addImm(NumBytes); +} + +void MipsRegisterInfo:: +emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const +{ + MachineBasicBlock::iterator MBBI = prior(MBB.end()); + MachineFrameInfo *MFI = MF.getFrameInfo(); + + // Get the number of bytes from FrameInfo + int NumBytes = (int) MFI->getStackSize(); + + // adjust stack : insert addi sp, sp, (imm) + if (NumBytes) { + BuildMI(MBB, MBBI, TII.get(Mips::ADDi), Mips::SP) + .addReg(Mips::SP).addImm(-NumBytes); + } +} + +void MipsRegisterInfo:: +processFunctionBeforeFrameFinalized(MachineFunction &MF) const {} + +unsigned MipsRegisterInfo:: +getRARegister() const { + return Mips::RA; +} + +unsigned MipsRegisterInfo:: +getFrameRegister(MachineFunction &MF) const { + assert(0 && "What is the frame register"); + return Mips::FP; +} + +unsigned MipsRegisterInfo:: +getEHExceptionRegister() const { + assert(0 && "What is the exception register"); + return 0; +} + +unsigned MipsRegisterInfo:: +getEHHandlerRegister() const { + assert(0 && "What is the exception handler register"); + return 0; +} + +#include "MipsGenRegisterInfo.inc" + diff --git a/lib/Target/Mips/MipsRegisterInfo.h b/lib/Target/Mips/MipsRegisterInfo.h new file mode 100644 index 00000000000..d84194f31ae --- /dev/null +++ b/lib/Target/Mips/MipsRegisterInfo.h @@ -0,0 +1,83 @@ +//===- MipsRegisterInfo.h - Mips Register Information Impl ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips implementation of the MRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSREGISTERINFO_H +#define MIPSREGISTERINFO_H + +#include "llvm/Target/MRegisterInfo.h" +#include "MipsGenRegisterInfo.h.inc" + +namespace llvm { + +class TargetInstrInfo; +class Type; + +struct MipsRegisterInfo : public MipsGenRegisterInfo { + const TargetInstrInfo &TII; + + MipsRegisterInfo(const TargetInstrInfo &tii); + + /// Code Generation virtual methods... + void storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned SrcReg, int FrameIndex, + const TargetRegisterClass *RC) const; + + void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC) const; + + void reMaterialize(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, + unsigned DestReg, const MachineInstr *Orig) const; + + MachineInstr* foldMemoryOperand(MachineInstr* MI, unsigned OpNum, + int FrameIndex) const; + + void copyRegToReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + unsigned DestReg, unsigned SrcReg, + const TargetRegisterClass *RC) const; + + + const unsigned *getCalleeSavedRegs() const; + + const TargetRegisterClass* const* getCalleeSavedRegClasses() const; + + BitVector getReservedRegs(const MachineFunction &MF) const; + + bool hasFP(const MachineFunction &MF) const; + + void eliminateCallFramePseudoInstr(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + void eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS = NULL) const; + + void processFunctionBeforeFrameFinalized(MachineFunction &MF) const; + + void emitPrologue(MachineFunction &MF) const; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; + + // Debug information queries. + unsigned getRARegister() const; + unsigned getFrameRegister(MachineFunction &MF) const; + + // Exception handling queries. + unsigned getEHExceptionRegister() const; + unsigned getEHHandlerRegister() const; +}; + +} // end namespace llvm + +#endif diff --git a/lib/Target/Mips/MipsRegisterInfo.td b/lib/Target/Mips/MipsRegisterInfo.td new file mode 100644 index 00000000000..2b7d15ff734 --- /dev/null +++ b/lib/Target/Mips/MipsRegisterInfo.td @@ -0,0 +1,80 @@ +//===- MipsRegisterInfo.td - Mips Register defs -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Declarations that describe the MIPS register file +//===----------------------------------------------------------------------===// + +// We have banks of 32 registers each. +class MipsReg : Register { + field bits<5> Num; + let Namespace = "Mips"; +} + +// Mips CPU Registers +class MipsGPRReg num, string n> : MipsReg { + let Num = num; +} + +// CPU GPR Registers +def ZERO : MipsGPRReg< 0, "ZERO">, DwarfRegNum<0>; +def AT : MipsGPRReg< 1, "AT">, DwarfRegNum<1>; +def V0 : MipsGPRReg< 2, "2">, DwarfRegNum<2>; +def V1 : MipsGPRReg< 3, "3">, DwarfRegNum<3>; +def A0 : MipsGPRReg< 4, "4">, DwarfRegNum<5>; +def A1 : MipsGPRReg< 5, "5">, DwarfRegNum<5>; +def A2 : MipsGPRReg< 6, "6">, DwarfRegNum<6>; +def A3 : MipsGPRReg< 7, "7">, DwarfRegNum<7>; +def T0 : MipsGPRReg< 8, "8">, DwarfRegNum<8>; +def T1 : MipsGPRReg< 9, "9">, DwarfRegNum<9>; +def T2 : MipsGPRReg< 10, "10">, DwarfRegNum<10>; +def T3 : MipsGPRReg< 11, "11">, DwarfRegNum<11>; +def T4 : MipsGPRReg< 12, "12">, DwarfRegNum<12>; +def T5 : MipsGPRReg< 13, "13">, DwarfRegNum<13>; +def T6 : MipsGPRReg< 14, "14">, DwarfRegNum<14>; +def T7 : MipsGPRReg< 15, "15">, DwarfRegNum<15>; +def S0 : MipsGPRReg< 16, "16">, DwarfRegNum<16>; +def S1 : MipsGPRReg< 17, "17">, DwarfRegNum<17>; +def S2 : MipsGPRReg< 18, "18">, DwarfRegNum<18>; +def S3 : MipsGPRReg< 19, "19">, DwarfRegNum<19>; +def S4 : MipsGPRReg< 20, "20">, DwarfRegNum<20>; +def S5 : MipsGPRReg< 21, "21">, DwarfRegNum<21>; +def S6 : MipsGPRReg< 22, "22">, DwarfRegNum<22>; +def S7 : MipsGPRReg< 23, "23">, DwarfRegNum<23>; +def T8 : MipsGPRReg< 24, "24">, DwarfRegNum<24>; +def T9 : MipsGPRReg< 25, "25">, DwarfRegNum<25>; +def K0 : MipsGPRReg< 26, "26">, DwarfRegNum<26>; +def K1 : MipsGPRReg< 27, "27">, DwarfRegNum<27>; +def GP : MipsGPRReg< 28, "GP">, DwarfRegNum<28>; +def SP : MipsGPRReg< 29, "SP">, DwarfRegNum<29>; +def FP : MipsGPRReg< 30, "FP">, DwarfRegNum<30>; +def RA : MipsGPRReg< 31, "RA">, DwarfRegNum<31>; + +// CPU Registers Class +def CPURegs : RegisterClass<"Mips", [i32], 32, + // Return Values and Arguments + [V0, V1, A0, A1, A2, A3, + // Not preserved across procedure calls + T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, + // Callee save + S0, S1, S2, S3, S4, S5, S6, S7, + // Reserved + ZERO, AT, K0, K1, GP, SP, FP, RA]> +{ + let MethodProtos = [{ + iterator allocation_order_end(const MachineFunction &MF) const; + }]; + let MethodBodies = [{ + CPURegsClass::iterator + CPURegsClass::allocation_order_end(const MachineFunction &MF) const { + // The last 8 registers on the list above are reserved + return end()-8; + } + }]; +} diff --git a/lib/Target/Mips/MipsSubtarget.cpp b/lib/Target/Mips/MipsSubtarget.cpp new file mode 100644 index 00000000000..a394f774ab8 --- /dev/null +++ b/lib/Target/Mips/MipsSubtarget.cpp @@ -0,0 +1,26 @@ +//===- MipsSubtarget.cpp - Mips Subtarget Information -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Mips specific subclass of TargetSubtarget. +// +//===----------------------------------------------------------------------===// + +#include "MipsSubtarget.h" +#include "Mips.h" +#include "MipsGenSubtarget.inc" +using namespace llvm; + +MipsSubtarget::MipsSubtarget(const TargetMachine &TM, const Module &M, + const std::string &FS) : isR3000(false) +{ + std::string CPU = "generic"; + + // Parse features string. + ParseSubtargetFeatures(FS, CPU); +} diff --git a/lib/Target/Mips/MipsSubtarget.h b/lib/Target/Mips/MipsSubtarget.h new file mode 100644 index 00000000000..7ec61ca95b2 --- /dev/null +++ b/lib/Target/Mips/MipsSubtarget.h @@ -0,0 +1,43 @@ +//=====-- MipsSubtarget.h - Define Subtarget for the Mips -----*- C++ -*--====// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the Mips specific subclass of TargetSubtarget. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSSUBTARGET_H +#define MIPSSUBTARGET_H + +#include "llvm/Target/TargetSubtarget.h" +#include "llvm/Target/TargetMachine.h" + +#include + +namespace llvm { +class Module; + +class MipsSubtarget : public TargetSubtarget { +protected: + bool isR3000; +public: + /// This constructor initializes the data members to match that + /// of the specified module. + /// + MipsSubtarget(const TargetMachine &TM, const Module &M, + const std::string &FS); + + /// ParseSubtargetFeatures - Parses features string setting specified + /// subtarget options. Definition of function is auto generated by tblgen. + void ParseSubtargetFeatures(const std::string &FS, const std::string &CPU); + + bool IsR3000() const { return isR3000; } +}; +} // End llvm namespace + +#endif diff --git a/lib/Target/Mips/MipsTargetAsmInfo.cpp b/lib/Target/Mips/MipsTargetAsmInfo.cpp new file mode 100644 index 00000000000..08166f6f8e7 --- /dev/null +++ b/lib/Target/Mips/MipsTargetAsmInfo.cpp @@ -0,0 +1,22 @@ +//===-- MipsTargetAsmInfo.cpp - Mips asm properties -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declarations of the MipsTargetAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "MipsTargetAsmInfo.h" + +using namespace llvm; + +MipsTargetAsmInfo::MipsTargetAsmInfo(const MipsTargetMachine &TM) { + Data16bitsDirective = "\t.half\t"; + Data32bitsDirective = "\t.word\t"; + CommentString = "#"; +} diff --git a/lib/Target/Mips/MipsTargetAsmInfo.h b/lib/Target/Mips/MipsTargetAsmInfo.h new file mode 100644 index 00000000000..908f036bb1f --- /dev/null +++ b/lib/Target/Mips/MipsTargetAsmInfo.h @@ -0,0 +1,30 @@ +//=====-- MipsTargetAsmInfo.h - Mips asm properties -----------*- C++ -*--====// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declaration of the MipsTargetAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSTARGETASMINFO_H +#define MIPSTARGETASMINFO_H + +#include "llvm/Target/TargetAsmInfo.h" + +namespace llvm { + + // Forward declaration. + class MipsTargetMachine; + + struct MipsTargetAsmInfo : public TargetAsmInfo { + MipsTargetAsmInfo(const MipsTargetMachine &TM); + }; + +} // namespace llvm + +#endif diff --git a/lib/Target/Mips/MipsTargetMachine.cpp b/lib/Target/Mips/MipsTargetMachine.cpp new file mode 100644 index 00000000000..de30284e013 --- /dev/null +++ b/lib/Target/Mips/MipsTargetMachine.cpp @@ -0,0 +1,81 @@ +//===-- MipsTargetMachine.cpp - Define TargetMachine for Mips -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implements the info about Mips target spec. +// +//===----------------------------------------------------------------------===// + +#include "Mips.h" +#include "MipsTargetAsmInfo.h" +#include "MipsTargetMachine.h" +#include "llvm/Module.h" +#include "llvm/PassManager.h" +#include "llvm/Target/TargetMachineRegistry.h" +using namespace llvm; + +namespace { + // Register the target. + RegisterTarget X("mips", " Mips"); +} + +const TargetAsmInfo *MipsTargetMachine:: +createTargetAsmInfo() const +{ + return new MipsTargetAsmInfo(*this); +} + +// DataLayout --> Big-endian, 32-bit pointer/ABI/alignment +// FrameInfo --> StackGrowsDown, 8 bytes aligned, LOA : -4 (Ra : 0) +MipsTargetMachine:: +MipsTargetMachine(const Module &M, const std::string &FS): + Subtarget(*this, M, FS), DataLayout("E-p:32:32:32"), + InstrInfo(*this), FrameInfo(TargetFrameInfo::StackGrowsDown, 8, -4), + TLInfo(*this) {} + +// return 0 and must specify -march to gen MIPS code. +unsigned MipsTargetMachine:: +getModuleMatchQuality(const Module &M) +{ + // We strongly match "mips-*". + std::string TT = M.getTargetTriple(); + if (TT.size() >= 5 && std::string(TT.begin(), TT.begin()+5) == "mips-") + return 20; + + return 0; +} + +// Install an instruction selector pass using +// the ISelDag to gen Mips code. +bool MipsTargetMachine:: +addInstSelector(FunctionPassManager &PM, bool Fast) +{ + PM.add(createMipsISelDag(*this)); + return false; +} + +// Implemented by targets that want to run passes immediately before +// machine code is emitted. return true if -print-machineinstrs should +// print out the code after the passes. +// TODO: Delay slot must be implemented here. +bool MipsTargetMachine:: +addPreEmitPass(FunctionPassManager &PM, bool Fast) +{ + return false; +} + +// Implements the AssemblyEmitter for the target. Must return +// true if AssemblyEmitter is supported +bool MipsTargetMachine:: +addAssemblyEmitter(FunctionPassManager &PM, bool Fast, + std::ostream &Out) +{ + // Output assembly language. + PM.add(createMipsCodePrinterPass(Out, *this)); + return false; +} diff --git a/lib/Target/Mips/MipsTargetMachine.h b/lib/Target/Mips/MipsTargetMachine.h new file mode 100644 index 00000000000..9e1ccc3254c --- /dev/null +++ b/lib/Target/Mips/MipsTargetMachine.h @@ -0,0 +1,65 @@ +//===-- MipsTargetMachine.h - Define TargetMachine for Mips -00--*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Bruno Cardoso Lopes and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the Mips specific subclass of TargetMachine. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSTARGETMACHINE_H +#define MIPSTARGETMACHINE_H + +#include "MipsSubtarget.h" +#include "MipsInstrInfo.h" +#include "MipsISelLowering.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetFrameInfo.h" + +namespace llvm { + class MipsTargetMachine : public LLVMTargetMachine { + MipsSubtarget Subtarget; + const TargetData DataLayout; // Calculates type size & alignment + MipsInstrInfo InstrInfo; + TargetFrameInfo FrameInfo; + MipsTargetLowering TLInfo; + + protected: + virtual const TargetAsmInfo *createTargetAsmInfo() const; + + public: + MipsTargetMachine(const Module &M, const std::string &FS); + + virtual const MipsInstrInfo *getInstrInfo() const + { return &InstrInfo; } + virtual const TargetFrameInfo *getFrameInfo() const + { return &FrameInfo; } + virtual const TargetSubtarget *getSubtargetImpl() const + { return &Subtarget; } + virtual const TargetData *getTargetData() const + { return &DataLayout;} + + virtual const MRegisterInfo *getRegisterInfo() const { + return &InstrInfo.getRegisterInfo(); + } + + virtual MipsTargetLowering *getTargetLowering() const { + return const_cast(&TLInfo); + } + + static unsigned getModuleMatchQuality(const Module &M); + + // Pass Pipeline Configuration + virtual bool addInstSelector(FunctionPassManager &PM, bool Fast); + virtual bool addPreEmitPass(FunctionPassManager &PM, bool Fast); + virtual bool addAssemblyEmitter(FunctionPassManager &PM, bool Fast, + std::ostream &Out); + }; +} // End llvm namespace + +#endif