diff options
-rw-r--r-- | lib/Target/Mips/Makefile | 21 | ||||
-rw-r--r-- | lib/Target/Mips/Mips.h | 38 | ||||
-rw-r--r-- | lib/Target/Mips/Mips.td | 63 | ||||
-rw-r--r-- | lib/Target/Mips/MipsAsmPrinter.cpp | 294 | ||||
-rw-r--r-- | lib/Target/Mips/MipsCallingConv.td | 39 | ||||
-rw-r--r-- | lib/Target/Mips/MipsISelDAGToDAG.cpp | 272 | ||||
-rw-r--r-- | lib/Target/Mips/MipsISelLowering.cpp | 519 | ||||
-rw-r--r-- | lib/Target/Mips/MipsISelLowering.h | 83 | ||||
-rw-r--r-- | lib/Target/Mips/MipsInstrFormats.td | 96 | ||||
-rw-r--r-- | lib/Target/Mips/MipsInstrInfo.cpp | 114 | ||||
-rw-r--r-- | lib/Target/Mips/MipsInstrInfo.h | 63 | ||||
-rw-r--r-- | lib/Target/Mips/MipsInstrInfo.td | 468 | ||||
-rw-r--r-- | lib/Target/Mips/MipsRegisterInfo.cpp | 288 | ||||
-rw-r--r-- | lib/Target/Mips/MipsRegisterInfo.h | 83 | ||||
-rw-r--r-- | lib/Target/Mips/MipsRegisterInfo.td | 80 | ||||
-rw-r--r-- | lib/Target/Mips/MipsSubtarget.cpp | 26 | ||||
-rw-r--r-- | lib/Target/Mips/MipsSubtarget.h | 43 | ||||
-rw-r--r-- | lib/Target/Mips/MipsTargetAsmInfo.cpp | 22 | ||||
-rw-r--r-- | lib/Target/Mips/MipsTargetAsmInfo.h | 30 | ||||
-rw-r--r-- | lib/Target/Mips/MipsTargetMachine.cpp | 81 | ||||
-rw-r--r-- | lib/Target/Mips/MipsTargetMachine.h | 65 |
21 files changed, 2788 insertions, 0 deletions
diff --git a/lib/Target/Mips/Makefile b/lib/Target/Mips/Makefile new file mode 100644 index 0000000000..6ebffc76e0 --- /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 0000000000..48b08eaf80 --- /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 <iosfwd> + +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 0000000000..662bc3b85d --- /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<string Name, list<SubtargetFeature> Features> + : Processor<Name, NoItineraries, Features>; + +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 0000000000..fdf60d92a2 --- /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 <cctype> + +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 << "<unknown operand type>"; 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 0000000000..23ef8503d3 --- /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<string F, CCAction A>: + CCIf<!strconcat("State.getTarget().getSubtarget<MipsSubtarget>().", 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<i32>>, + + // 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 0000000000..e660f9cb85 --- /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 <queue> +#include <set> + +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<FrameIndexSDNode>(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<ConstantSDNode>(Addr.getOperand(1))) + { + if (Predicate_immSExt16(CN)) + { + // If the first operand is a FI, get the TargetFI Node + if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode> + (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 0000000000..98da5756a0 --- /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 <queue> +#include <set> + +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 reg |