diff options
| author | Ed Schouten <ed@FreeBSD.org> | 2009-06-02 17:52:33 +0000 |
|---|---|---|
| committer | Ed Schouten <ed@FreeBSD.org> | 2009-06-02 17:52:33 +0000 |
| commit | 009b1c42aa6266385f2c37e227516b24077e6dd7 (patch) | |
| tree | 64ba909838c23261cace781ece27d106134ea451 /lib/Target/Mips | |
Notes
Diffstat (limited to 'lib/Target/Mips')
28 files changed, 6398 insertions, 0 deletions
diff --git a/lib/Target/Mips/AsmPrinter/CMakeLists.txt b/lib/Target/Mips/AsmPrinter/CMakeLists.txt new file mode 100644 index 000000000000..6a868c2fc78c --- /dev/null +++ b/lib/Target/Mips/AsmPrinter/CMakeLists.txt @@ -0,0 +1,12 @@ +include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}/..
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ )
+
+add_partially_linked_object(LLVMMipsAsmPrinter
+ MipsAsmPrinter.cpp
+ )
+
+target_name_of_partially_linked_object(LLVMMipsCodeGen n)
+
+add_dependencies(LLVMMipsAsmPrinter ${n})
diff --git a/lib/Target/Mips/AsmPrinter/Makefile b/lib/Target/Mips/AsmPrinter/Makefile new file mode 100644 index 000000000000..a2fecf44e8e1 --- /dev/null +++ b/lib/Target/Mips/AsmPrinter/Makefile @@ -0,0 +1,17 @@ +##===- lib/Target/Mips/AsmPrinter/Makefile -----------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME = LLVMMipsAsmPrinter + +# Hack: we need to include 'main' Mips target directory to grab +# private headers +CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/lib/Target/Mips/AsmPrinter/MipsAsmPrinter.cpp b/lib/Target/Mips/AsmPrinter/MipsAsmPrinter.cpp new file mode 100644 index 000000000000..dfb62382e75d --- /dev/null +++ b/lib/Target/Mips/AsmPrinter/MipsAsmPrinter.cpp @@ -0,0 +1,580 @@ +//===-- MipsAsmPrinter.cpp - Mips LLVM assembly writer --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file 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 "MipsSubtarget.h" +#include "MipsInstrInfo.h" +#include "MipsTargetMachine.h" +#include "MipsMachineFunction.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Module.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/DwarfWriter.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Support/Mangler.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" +#include <cctype> + +using namespace llvm; + +STATISTIC(EmittedInsts, "Number of machine instrs printed"); + +namespace { + class VISIBILITY_HIDDEN MipsAsmPrinter : public AsmPrinter { + const MipsSubtarget *Subtarget; + public: + explicit MipsAsmPrinter(raw_ostream &O, MipsTargetMachine &TM, + const TargetAsmInfo *T, CodeGenOpt::Level OL, + bool V) + : AsmPrinter(O, TM, T, OL, V) { + Subtarget = &TM.getSubtarget<MipsSubtarget>(); + } + + virtual const char *getPassName() const { + return "Mips Assembly Printer"; + } + + bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, const char *ExtraCode); + void printOperand(const MachineInstr *MI, int opNum); + void printUnsignedImm(const MachineInstr *MI, int opNum); + void printMemOperand(const MachineInstr *MI, int opNum, + const char *Modifier = 0); + void printFCCOperand(const MachineInstr *MI, int opNum, + const char *Modifier = 0); + void printModuleLevelGV(const GlobalVariable* GVar); + void printSavedRegsBitmask(MachineFunction &MF); + void printHex32(unsigned int Value); + + const char *emitCurrentABIString(void); + void emitFunctionStart(MachineFunction &MF); + void emitFunctionEnd(MachineFunction &MF); + void emitFrameDirective(MachineFunction &MF); + + 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(raw_ostream &o, + MipsTargetMachine &tm, + CodeGenOpt::Level OptLevel, + bool verbose) { + return new MipsAsmPrinter(o, tm, tm.getTargetAsmInfo(), OptLevel, verbose); +} + +//===----------------------------------------------------------------------===// +// +// Mips Asm Directives +// +// -- Frame directive "frame Stackpointer, Stacksize, RARegister" +// Describe the stack frame. +// +// -- Mask directives "(f)mask bitmask, offset" +// Tells the assembler which registers are saved and where. +// bitmask - contain a little endian bitset indicating which registers are +// saved on function prologue (e.g. with a 0x80000000 mask, the +// assembler knows the register 31 (RA) is saved at prologue. +// offset - the position before stack pointer subtraction indicating where +// the first saved register on prologue is located. (e.g. with a +// +// Consider the following function prologue: +// +// .frame $fp,48,$ra +// .mask 0xc0000000,-8 +// addiu $sp, $sp, -48 +// sw $ra, 40($sp) +// sw $fp, 36($sp) +// +// With a 0xc0000000 mask, the assembler knows the register 31 (RA) and +// 30 (FP) are saved at prologue. As the save order on prologue is from +// left to right, RA is saved first. A -8 offset means that after the +// stack pointer subtration, the first register in the mask (RA) will be +// saved at address 48-8=40. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Mask directives +//===----------------------------------------------------------------------===// + +// Create a bitmask with all callee saved registers for CPU or Floating Point +// registers. For CPU registers consider RA, GP and FP for saving if necessary. +void MipsAsmPrinter:: +printSavedRegsBitmask(MachineFunction &MF) +{ + const TargetRegisterInfo &RI = *TM.getRegisterInfo(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + // CPU and FPU Saved Registers Bitmasks + unsigned int CPUBitmask = 0; + unsigned int FPUBitmask = 0; + + // Set the CPU and FPU Bitmasks + MachineFrameInfo *MFI = MF.getFrameInfo(); + const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); + for (unsigned i = 0, e = CSI.size(); i != e; ++i) { + unsigned RegNum = MipsRegisterInfo::getRegisterNumbering(CSI[i].getReg()); + if (CSI[i].getRegClass() == Mips::CPURegsRegisterClass) + CPUBitmask |= (1 << RegNum); + else + FPUBitmask |= (1 << RegNum); + } + + // Return Address and Frame registers must also be set in CPUBitmask. + if (RI.hasFP(MF)) + CPUBitmask |= (1 << MipsRegisterInfo:: + getRegisterNumbering(RI.getFrameRegister(MF))); + + if (MF.getFrameInfo()->hasCalls()) + CPUBitmask |= (1 << MipsRegisterInfo:: + getRegisterNumbering(RI.getRARegister())); + + // Print CPUBitmask + O << "\t.mask \t"; printHex32(CPUBitmask); O << ',' + << MipsFI->getCPUTopSavedRegOff() << '\n'; + + // Print FPUBitmask + O << "\t.fmask\t"; printHex32(FPUBitmask); O << "," + << MipsFI->getFPUTopSavedRegOff() << '\n'; +} + +// Print a 32 bit hex number with all numbers. +void MipsAsmPrinter:: +printHex32(unsigned int Value) +{ + O << "0x"; + for (int i = 7; i >= 0; i--) + O << utohexstr( (Value & (0xF << (i*4))) >> (i*4) ); +} + +//===----------------------------------------------------------------------===// +// Frame and Set directives +//===----------------------------------------------------------------------===// + +/// Frame Directive +void MipsAsmPrinter:: +emitFrameDirective(MachineFunction &MF) +{ + const TargetRegisterInfo &RI = *TM.getRegisterInfo(); + + unsigned stackReg = RI.getFrameRegister(MF); + unsigned returnReg = RI.getRARegister(); + unsigned stackSize = MF.getFrameInfo()->getStackSize(); + + + O << "\t.frame\t" << '$' << LowercaseString(RI.get(stackReg).AsmName) + << ',' << stackSize << ',' + << '$' << LowercaseString(RI.get(returnReg).AsmName) + << '\n'; +} + +/// Emit Set directives. +const char * MipsAsmPrinter:: +emitCurrentABIString(void) +{ + switch(Subtarget->getTargetABI()) { + case MipsSubtarget::O32: return "abi32"; + case MipsSubtarget::O64: return "abiO64"; + case MipsSubtarget::N32: return "abiN32"; + case MipsSubtarget::N64: return "abi64"; + case MipsSubtarget::EABI: return "eabi32"; // TODO: handle eabi64 + default: break; + } + + assert(0 && "Unknown Mips ABI"); + return NULL; +} + +/// Emit the directives used by GAS on the start of functions +void MipsAsmPrinter:: +emitFunctionStart(MachineFunction &MF) +{ + // Print out the label for the function. + const Function *F = MF.getFunction(); + SwitchToSection(TAI->SectionForGlobal(F)); + + // 2 bits aligned + EmitAlignment(2, F); + + O << "\t.globl\t" << CurrentFnName << '\n'; + O << "\t.ent\t" << CurrentFnName << '\n'; + + printVisibility(CurrentFnName, F->getVisibility()); + + if ((TAI->hasDotTypeDotSizeDirective()) && Subtarget->isLinux()) + O << "\t.type\t" << CurrentFnName << ", @function\n"; + + O << CurrentFnName << ":\n"; + + emitFrameDirective(MF); + printSavedRegsBitmask(MF); + + O << '\n'; +} + +/// Emit the directives used by GAS on the end of functions +void MipsAsmPrinter:: +emitFunctionEnd(MachineFunction &MF) +{ + // There are instruction for this macros, but they must + // always be at the function end, and we can't emit and + // break with BB logic. + O << "\t.set\tmacro\n"; + O << "\t.set\treorder\n"; + + O << "\t.end\t" << CurrentFnName << '\n'; + if (TAI->hasDotTypeDotSizeDirective() && !Subtarget->isLinux()) + O << "\t.size\t" << CurrentFnName << ", .-" << CurrentFnName << '\n'; +} + +/// runOnMachineFunction - This uses the printMachineInstruction() +/// method to print assembly for each instruction. +bool MipsAsmPrinter:: +runOnMachineFunction(MachineFunction &MF) +{ + this->MF = &MF; + + SetupMachineFunction(MF); + + // Print out constants referenced by the function + EmitConstantPool(MF.getConstantPool()); + + // Print out jump tables referenced by the function + EmitJumpTableInfo(MF.getJumpTableInfo(), MF); + + O << "\n\n"; + + // Emit the function start directives + emitFunctionStart(MF); + + // 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, true); + O << '\n'; + } + + for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); + II != E; ++II) { + // Print the assembly for the instruction. + printInstruction(II); + ++EmittedInsts; + } + + // Each Basic Block is separated by a newline + O << '\n'; + } + + // Emit function end directives + emitFunctionEnd(MF); + + // We didn't modify anything. + return false; +} + +// Print out an operand for an inline asm expression. +bool MipsAsmPrinter:: +PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, const char *ExtraCode) +{ + // Does this asm operand have a single letter operand modifier? + if (ExtraCode && ExtraCode[0]) + return true; // Unknown modifier. + + printOperand(MI, OpNo); + return false; +} + +void MipsAsmPrinter:: +printOperand(const MachineInstr *MI, int opNum) +{ + const MachineOperand &MO = MI->getOperand(opNum); + const TargetRegisterInfo &RI = *TM.getRegisterInfo(); + bool closeP = false; + bool isPIC = (TM.getRelocationModel() == Reloc::PIC_); + bool isCodeLarge = (TM.getCodeModel() == CodeModel::Large); + + // %hi and %lo used on mips gas to load global addresses on + // static code. %got is used to load global addresses when + // using PIC_. %call16 is used to load direct call targets + // on PIC_ and small code size. %call_lo and %call_hi load + // direct call targets on PIC_ and large code size. + if (MI->getOpcode() == Mips::LUi && !MO.isReg() && !MO.isImm()) { + if ((isPIC) && (isCodeLarge)) + O << "%call_hi("; + else + O << "%hi("; + closeP = true; + } else if ((MI->getOpcode() == Mips::ADDiu) && !MO.isReg() && !MO.isImm()) { + const MachineOperand &firstMO = MI->getOperand(opNum-1); + if (firstMO.getReg() == Mips::GP) + O << "%gp_rel("; + else + O << "%lo("; + closeP = true; + } else if ((isPIC) && (MI->getOpcode() == Mips::LW) && + (!MO.isReg()) && (!MO.isImm())) { + const MachineOperand &firstMO = MI->getOperand(opNum-1); + const MachineOperand &lastMO = MI->getOperand(opNum+1); + if ((firstMO.isReg()) && (lastMO.isReg())) { + if ((firstMO.getReg() == Mips::T9) && (lastMO.getReg() == Mips::GP) + && (!isCodeLarge)) + O << "%call16("; + else if ((firstMO.getReg() != Mips::T9) && (lastMO.getReg() == Mips::GP)) + O << "%got("; + else if ((firstMO.getReg() == Mips::T9) && (lastMO.getReg() != Mips::GP) + && (isCodeLarge)) + O << "%call_lo("; + closeP = true; + } + } + + switch (MO.getType()) + { + case MachineOperand::MO_Register: + if (TargetRegisterInfo::isPhysicalRegister(MO.getReg())) + O << '$' << LowercaseString (RI.get(MO.getReg()).AsmName); + else + O << '$' << MO.getReg(); + break; + + case MachineOperand::MO_Immediate: + O << (short int)MO.getImm(); + break; + + case MachineOperand::MO_MachineBasicBlock: + printBasicBlockLabel(MO.getMBB()); + return; + + case MachineOperand::MO_GlobalAddress: + { + const GlobalValue *GV = MO.getGlobal(); + O << Mang->getValueName(GV); + } + break; + + case MachineOperand::MO_ExternalSymbol: + O << MO.getSymbolName(); + break; + + case MachineOperand::MO_JumpTableIndex: + O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() + << '_' << MO.getIndex(); + break; + + case MachineOperand::MO_ConstantPoolIndex: + O << TAI->getPrivateGlobalPrefix() << "CPI" + << getFunctionNumber() << "_" << MO.getIndex(); + break; + + default: + O << "<unknown operand type>"; abort (); break; + } + + if (closeP) O << ")"; +} + +void MipsAsmPrinter:: +printUnsignedImm(const MachineInstr *MI, int opNum) +{ + const MachineOperand &MO = MI->getOperand(opNum); + if (MO.getType() == MachineOperand::MO_Immediate) + O << (unsigned short int)MO.getImm(); + else + printOperand(MI, opNum); +} + +void MipsAsmPrinter:: +printMemOperand(const MachineInstr *MI, int opNum, const char *Modifier) +{ + // when using stack locations for not load/store instructions + // print the same way as all normal 3 operand instructions. + if (Modifier && !strcmp(Modifier, "stackloc")) { + printOperand(MI, opNum+1); + O << ", "; + printOperand(MI, opNum); + return; + } + + // Load/Store memory operands -- imm($reg) + // If PIC target the target is loaded as the + // pattern lw $25,%call16($28) + printOperand(MI, opNum); + O << "("; + printOperand(MI, opNum+1); + O << ")"; +} + +void MipsAsmPrinter:: +printFCCOperand(const MachineInstr *MI, int opNum, const char *Modifier) +{ + const MachineOperand& MO = MI->getOperand(opNum); + O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm()); +} + +bool MipsAsmPrinter:: +doInitialization(Module &M) +{ + Mang = new Mangler(M, "", TAI->getPrivateGlobalPrefix()); + + // Tell the assembler which ABI we are using + O << "\t.section .mdebug." << emitCurrentABIString() << '\n'; + + // TODO: handle O64 ABI + if (Subtarget->isABI_EABI()) + O << "\t.section .gcc_compiled_long" << + (Subtarget->isGP32bit() ? "32" : "64") << '\n'; + + // return to previous section + O << "\t.previous" << '\n'; + + return false; // success +} + +void MipsAsmPrinter:: +printModuleLevelGV(const GlobalVariable* GVar) { + const TargetData *TD = TM.getTargetData(); + + if (!GVar->hasInitializer()) + return; // External global require no code + + // Check to see if this is a special global used by LLVM, if so, emit it. + if (EmitSpecialLLVMGlobal(GVar)) + return; + + O << "\n\n"; + std::string name = Mang->getValueName(GVar); + Constant *C = GVar->getInitializer(); + const Type *CTy = C->getType(); + unsigned Size = TD->getTypeAllocSize(CTy); + const ConstantArray *CVA = dyn_cast<ConstantArray>(C); + bool printSizeAndType = true; + + // A data structure or array is aligned in memory to the largest + // alignment boundary required by any data type inside it (this matches + // the Preferred Type Alignment). For integral types, the alignment is + // the type size. + unsigned Align; + if (CTy->getTypeID() == Type::IntegerTyID || + CTy->getTypeID() == Type::VoidTyID) { + assert(!(Size & (Size-1)) && "Alignment is not a power of two!"); + Align = Log2_32(Size); + } else + Align = TD->getPreferredTypeAlignmentShift(CTy); + + printVisibility(name, GVar->getVisibility()); + + SwitchToSection(TAI->SectionForGlobal(GVar)); + + if (C->isNullValue() && !GVar->hasSection()) { + if (!GVar->isThreadLocal() && + (GVar->hasLocalLinkage() || GVar->isWeakForLinker())) { + if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it. + + if (GVar->hasLocalLinkage()) + O << "\t.local\t" << name << '\n'; + + O << TAI->getCOMMDirective() << name << ',' << Size; + if (TAI->getCOMMDirectiveTakesAlignment()) + O << ',' << (1 << Align); + + O << '\n'; + return; + } + } + switch (GVar->getLinkage()) { + case GlobalValue::LinkOnceAnyLinkage: + case GlobalValue::LinkOnceODRLinkage: + case GlobalValue::CommonLinkage: + case GlobalValue::WeakAnyLinkage: + case GlobalValue::WeakODRLinkage: + // FIXME: Verify correct for weak. + // Nonnull linkonce -> weak + O << "\t.weak " << name << '\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 << TAI->getGlobalDirective() << name << '\n'; + // Fall Through + case GlobalValue::PrivateLinkage: + case GlobalValue::InternalLinkage: + if (CVA && CVA->isCString()) + printSizeAndType = false; + 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!"); + } + + EmitAlignment(Align, GVar); + + if (TAI->hasDotTypeDotSizeDirective() && printSizeAndType) { + O << "\t.type " << name << ",@object\n"; + O << "\t.size " << name << ',' << Size << '\n'; + } + + O << name << ":\n"; + EmitGlobalConstant(C); +} + +bool MipsAsmPrinter:: +doFinalization(Module &M) +{ + // Print out module-level global variables here. + for (Module::const_global_iterator I = M.global_begin(), + E = M.global_end(); I != E; ++I) + printModuleLevelGV(I); + + O << '\n'; + + return AsmPrinter::doFinalization(M); +} diff --git a/lib/Target/Mips/CMakeLists.txt b/lib/Target/Mips/CMakeLists.txt new file mode 100644 index 000000000000..70c7a51c2850 --- /dev/null +++ b/lib/Target/Mips/CMakeLists.txt @@ -0,0 +1,22 @@ +set(LLVM_TARGET_DEFINITIONS Mips.td) + +tablegen(MipsGenRegisterInfo.h.inc -gen-register-desc-header) +tablegen(MipsGenRegisterNames.inc -gen-register-enums) +tablegen(MipsGenRegisterInfo.inc -gen-register-desc) +tablegen(MipsGenInstrNames.inc -gen-instr-enums) +tablegen(MipsGenInstrInfo.inc -gen-instr-desc) +tablegen(MipsGenAsmWriter.inc -gen-asm-writer) +tablegen(MipsGenDAGISel.inc -gen-dag-isel) +tablegen(MipsGenCallingConv.inc -gen-callingconv) +tablegen(MipsGenSubtarget.inc -gen-subtarget) + +add_llvm_target(MipsCodeGen + MipsDelaySlotFiller.cpp + MipsInstrInfo.cpp + MipsISelDAGToDAG.cpp + MipsISelLowering.cpp + MipsRegisterInfo.cpp + MipsSubtarget.cpp + MipsTargetAsmInfo.cpp + MipsTargetMachine.cpp + ) diff --git a/lib/Target/Mips/Makefile b/lib/Target/Mips/Makefile new file mode 100644 index 000000000000..48ab5f994704 --- /dev/null +++ b/lib/Target/Mips/Makefile @@ -0,0 +1,23 @@ +##===- lib/Target/Mips/Makefile ----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../../.. +LIBRARYNAME = LLVMMipsCodeGen +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 + +DIRS = AsmPrinter + +include $(LEVEL)/Makefile.common + diff --git a/lib/Target/Mips/Mips.h b/lib/Target/Mips/Mips.h new file mode 100644 index 000000000000..0accb4e347ee --- /dev/null +++ b/lib/Target/Mips/Mips.h @@ -0,0 +1,41 @@ +//===-- Mips.h - Top-level interface for Mips representation ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file 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 "llvm/Target/TargetMachine.h" + +namespace llvm { + class MipsTargetMachine; + class FunctionPass; + class MachineCodeEmitter; + class raw_ostream; + + FunctionPass *createMipsISelDag(MipsTargetMachine &TM); + FunctionPass *createMipsDelaySlotFillerPass(MipsTargetMachine &TM); + FunctionPass *createMipsCodePrinterPass(raw_ostream &OS, + MipsTargetMachine &TM, + CodeGenOpt::Level OptLevel, + bool Verbose); +} // 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 000000000000..79a78d86aef7 --- /dev/null +++ b/lib/Target/Mips/Mips.td @@ -0,0 +1,88 @@ +//===- Mips.td - Describe the Mips Target Machine ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This is the top level entry point for the Mips target. +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Target-independent interfaces +//===----------------------------------------------------------------------===// + +include "llvm/Target/Target.td" + +//===----------------------------------------------------------------------===// +// Register File, Calling Conv, Instruction Descriptions +//===----------------------------------------------------------------------===// + +include "MipsRegisterInfo.td" +include "MipsSchedule.td" +include "MipsInstrInfo.td" +include "MipsCallingConv.td" + +def MipsInstrInfo : InstrInfo { + let TSFlagsFields = []; + let TSFlagsShifts = []; +} + +//===----------------------------------------------------------------------===// +// Mips Subtarget features // +//===----------------------------------------------------------------------===// + +def FeatureGP64Bit : SubtargetFeature<"gp64", "IsGP64bit", "true", + "General Purpose Registers are 64-bit wide.">; +def FeatureFP64Bit : SubtargetFeature<"fp64", "IsFP64bit", "true", + "Support 64-bit FP registers.">; +def FeatureSingleFloat : SubtargetFeature<"single-float", "IsSingleFloat", + "true", "Only supports single precision float">; +def FeatureMips1 : SubtargetFeature<"mips1", "MipsArchVersion", "Mips1", + "Mips1 ISA Support">; +def FeatureMips2 : SubtargetFeature<"mips2", "MipsArchVersion", "Mips2", + "Mips2 ISA Support">; +def FeatureO32 : SubtargetFeature<"o32", "MipsABI", "O32", + "Enable o32 ABI">; +def FeatureEABI : SubtargetFeature<"eabi", "MipsABI", "EABI", + "Enable eabi ABI">; +def FeatureVFPU : SubtargetFeature<"vfpu", "HasVFPU", + "true", "Enable vector FPU instructions.">; +def FeatureSEInReg : SubtargetFeature<"seinreg", "HasSEInReg", "true", + "Enable 'signext in register' instructions.">; +def FeatureCondMov : SubtargetFeature<"condmov", "HasCondMov", "true", + "Enable 'conditional move' instructions.">; +def FeatureMulDivAdd : SubtargetFeature<"muldivadd", "HasMulDivAdd", "true", + "Enable 'multiply add/sub' instructions.">; +def FeatureMinMax : SubtargetFeature<"minmax", "HasMinMax", "true", + "Enable 'min/max' instructions.">; +def FeatureSwap : SubtargetFeature<"swap", "HasSwap", "true", + "Enable 'byte/half swap' instructions.">; +def FeatureBitCount : SubtargetFeature<"bitcount", "HasBitCount", "true", + "Enable 'count leading bits' instructions.">; + +//===----------------------------------------------------------------------===// +// Mips processors supported. +//===----------------------------------------------------------------------===// + +class Proc<string Name, list<SubtargetFeature> Features> + : Processor<Name, MipsGenericItineraries, Features>; + +def : Proc<"mips1", [FeatureMips1]>; +def : Proc<"r2000", [FeatureMips1]>; +def : Proc<"r3000", [FeatureMips1]>; + +def : Proc<"mips2", [FeatureMips2]>; +def : Proc<"r6000", [FeatureMips2]>; + +// Allegrex is a 32bit subset of r4000, both for interger and fp registers, +// but much more similar to Mips2 than Mips3. It also contains some of +// Mips32/Mips32r2 instructions and a custom vector fpu processor. +def : Proc<"allegrex", [FeatureMips2, FeatureSingleFloat, FeatureEABI, + FeatureVFPU, FeatureSEInReg, FeatureCondMov, FeatureMulDivAdd, + FeatureMinMax, FeatureSwap, FeatureBitCount]>; + +def Mips : Target { + let InstructionSet = MipsInstrInfo; +} diff --git a/lib/Target/Mips/MipsCallingConv.td b/lib/Target/Mips/MipsCallingConv.td new file mode 100644 index 000000000000..01fe92e6b73c --- /dev/null +++ b/lib/Target/Mips/MipsCallingConv.td @@ -0,0 +1,86 @@ +//===- MipsCallingConv.td - Calling Conventions for Mips --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file 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 O32 Calling Convention +//===----------------------------------------------------------------------===// + +// Only the return rules are defined here for O32. The rules for argument +// passing are defined in MipsISelLowering.cpp. +def RetCC_MipsO32 : CallingConv<[ + // i32 are returned in registers V0, V1 + CCIfType<[i32], CCAssignToReg<[V0, V1]>>, + + // f32 are returned in registers F0, F1 + CCIfType<[f32], CCAssignToReg<[F0, F1]>>, + + // f64 are returned in register D0 + CCIfType<[f64], CCIfSubtarget<"isNotSingleFloat()", CCAssignToReg<[D0]>>> +]>; + +//===----------------------------------------------------------------------===// +// Mips EABI Calling Convention +//===----------------------------------------------------------------------===// + +def CC_MipsEABI : CallingConv<[ + // Promote i8/i16 arguments to i32. + CCIfType<[i8, i16], CCPromoteToType<i32>>, + + // Integer arguments are passed in integer registers. + CCIfType<[i32], CCAssignToReg<[A0, A1, A2, A3, T0, T1, T2, T3]>>, + + // Single fp arguments are passed in pairs within 32-bit mode + CCIfType<[f32], CCIfSubtarget<"isSingleFloat()", + CCAssignToReg<[F12, F13, F14, F15, F16, F17, F18, F19]>>>, + + CCIfType<[f32], CCIfSubtarget<"isNotSingleFloat()", + CCAssignToReg<[F12, F14, F16, F18]>>>, + + // The first 4 doubl fp arguments are passed in single fp registers. + CCIfType<[f64], CCIfSubtarget<"isNotSingleFloat()", + CCAssignToReg<[D6, D7, D8, D9]>>>, + + // Integer values get stored in stack slots that are 4 bytes in + // size and 4-byte aligned. + CCIfType<[i32, f32], CCAssignToStack<4, 4>>, + + // Integer values get stored in stack slots that are 8 bytes in + // size and 8-byte aligned. + CCIfType<[f64], CCIfSubtarget<"isNotSingleFloat()", CCAssignToStack<8, 8>>> +]>; + +def RetCC_MipsEABI : CallingConv<[ + // i32 are returned in registers V0, V1 + CCIfType<[i32], CCAssignToReg<[V0, V1]>>, + + // f32 are returned in registers F0, F1 + CCIfType<[f32], CCAssignToReg<[F0, F1]>>, + + // f64 are returned in register D0 + CCIfType<[f64], CCIfSubtarget<"isNotSingleFloat()", CCAssignToReg<[D0]>>> +]>; + +//===----------------------------------------------------------------------===// +// Mips Calling Convention Dispatch +//===----------------------------------------------------------------------===// + +def CC_Mips : CallingConv<[ + CCIfSubtarget<"isABI_EABI()", CCDelegateTo<CC_MipsEABI>> +]>; + +def RetCC_Mips : CallingConv<[ + CCIfSubtarget<"isABI_EABI()", CCDelegateTo<RetCC_MipsEABI>>, + CCDelegateTo<RetCC_MipsO32> +]>; diff --git a/lib/Target/Mips/MipsDelaySlotFiller.cpp b/lib/Target/Mips/MipsDelaySlotFiller.cpp new file mode 100644 index 000000000000..a2b615d8add2 --- /dev/null +++ b/lib/Target/Mips/MipsDelaySlotFiller.cpp @@ -0,0 +1,77 @@ +//===-- DelaySlotFiller.cpp - Mips delay slot filler ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Simple pass to fills delay slots with NOPs. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "delay-slot-filler" + +#include "Mips.h" +#include "MipsTargetMachine.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/ADT/Statistic.h" + +using namespace llvm; + +STATISTIC(FilledSlots, "Number of delay slots filled"); + +namespace { + struct Filler : public MachineFunctionPass { + + TargetMachine &TM; + const TargetInstrInfo *TII; + + static char ID; + Filler(TargetMachine &tm) + : MachineFunctionPass(&ID), TM(tm), TII(tm.getInstrInfo()) { } + + virtual const char *getPassName() const { + return "Mips Delay Slot Filler"; + } + + bool runOnMachineBasicBlock(MachineBasicBlock &MBB); + bool runOnMachineFunction(MachineFunction &F) { + bool Changed = false; + for (MachineFunction::iterator FI = F.begin(), FE = F.end(); + FI != FE; ++FI) + Changed |= runOnMachineBasicBlock(*FI); + return Changed; + } + + }; + char Filler::ID = 0; +} // end of anonymous namespace + +/// runOnMachineBasicBlock - Fill in delay slots for the given basic block. +/// Currently, we fill delay slots with NOPs. We assume there is only one +/// delay slot per delayed instruction. +bool Filler:: +runOnMachineBasicBlock(MachineBasicBlock &MBB) +{ + bool Changed = false; + for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) + if (I->getDesc().hasDelaySlot()) { + MachineBasicBlock::iterator J = I; + ++J; + BuildMI(MBB, J, I->getDebugLoc(), TII->get(Mips::NOP)); + ++FilledSlots; + Changed = true; + } + return Changed; +} + +/// createMipsDelaySlotFillerPass - Returns a pass that fills in delay +/// slots in Mips MachineFunctions +FunctionPass *llvm::createMipsDelaySlotFillerPass(MipsTargetMachine &tm) { + return new Filler(tm); +} + diff --git a/lib/Target/Mips/MipsISelDAGToDAG.cpp b/lib/Target/Mips/MipsISelDAGToDAG.cpp new file mode 100644 index 000000000000..f05ac702ccdd --- /dev/null +++ b/lib/Target/Mips/MipsISelDAGToDAG.cpp @@ -0,0 +1,392 @@ +//===-- MipsISelDAGToDAG.cpp - A dag to dag inst selector for Mips --------===// +// +// The LLVM Compiler Infrastructure +// +// This file 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 "MipsMachineFunction.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/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +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; + + /// Subtarget - Keep a pointer to the MipsSubtarget around so that we can + /// make the right decision when generating code for different targets. + const MipsSubtarget &Subtarget; + +public: + explicit MipsDAGToDAGISel(MipsTargetMachine &tm) : + SelectionDAGISel(tm), + TM(tm), Subtarget(tm.getSubtarget<MipsSubtarget>()) {} + + virtual void InstructionSelect(); + + // 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" + + SDValue getGlobalBaseReg(); + SDNode *Select(SDValue N); + + // Complex Pattern. + bool SelectAddr(SDValue Op, SDValue N, + SDValue &Base, SDValue &Offset); + + + // getI32Imm - Return a target constant with the specified + // value, of type i32. + inline SDValue getI32Imm(unsigned Imm) { + return CurDAG->getTargetConstant(Imm, MVT::i32); + } + + + #ifndef NDEBUG + unsigned Indent; + #endif +}; + +} + +/// InstructionSelect - This callback is invoked by +/// SelectionDAGISel when it has created a SelectionDAG for us to codegen. +void MipsDAGToDAGISel:: +InstructionSelect() +{ + DEBUG(BB->dump()); + // Codegen the basic block. + #ifndef NDEBUG + DOUT << "===== Instruction selection begins:\n"; + Indent = 0; + #endif + + // Select target instructions for the DAG. + SelectRoot(*CurDAG); + + #ifndef NDEBUG + DOUT << "===== Instruction selection ends:\n"; + #endif + + CurDAG->RemoveDeadNodes(); +} + +/// getGlobalBaseReg - Output the instructions required to put the +/// GOT address into a register. +SDValue MipsDAGToDAGISel::getGlobalBaseReg() { + MachineFunction* MF = BB->getParent(); + unsigned GP = 0; + for(MachineRegisterInfo::livein_iterator ii = MF->getRegInfo().livein_begin(), + ee = MF->getRegInfo().livein_end(); ii != ee; ++ii) + if (ii->first == Mips::GP) { + GP = ii->second; + break; + } + assert(GP && "GOT PTR not in liveins"); + // FIXME is there a sensible place to get debug info for this? + return CurDAG->getCopyFromReg(CurDAG->getEntryNode(), + DebugLoc::getUnknownLoc(), GP, MVT::i32); +} + +/// ComplexPattern used on MipsInstrInfo +/// Used on Mips Load/Store instructions +bool MipsDAGToDAGISel:: +SelectAddr(SDValue Op, SDValue Addr, SDValue &Offset, SDValue &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; + } + + // on PIC code Load GA + if (TM.getRelocationModel() == Reloc::PIC_) { + if ((Addr.getOpcode() == ISD::TargetGlobalAddress) || + (Addr.getOpcode() == ISD::TargetJumpTable)){ + Base = CurDAG->getRegister(Mips::GP, MVT::i32); + Offset = Addr; + return true; + } + } else { + if ((Addr.getOpcode() == ISD::TargetExternalSymbol || + Addr.getOpcode() == ISD::TargetGlobalAddress)) + return false; + } + + // Operand is a 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->getZExtValue(), 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(SDValue N) +{ + SDNode *Node = N.getNode(); + unsigned Opcode = Node->getOpcode(); + DebugLoc dl = Node->getDebugLoc(); + + // 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 (Node->isMachineOpcode()) { + #ifndef NDEBUG + DOUT << std::string(Indent-2, ' ') << "== "; + DEBUG(Node->dump(CurDAG)); + DOUT << "\n"; + Indent -= 2; + #endif + return NULL; + } + + /// + // Instruction Selection not handled by the auto-generated + // tablegen selection should be handled here. + /// + switch(Opcode) { + + default: break; + + case ISD::SUBE: + case ISD::ADDE: { + SDValue InFlag = Node->getOperand(2), CmpLHS; + unsigned Opc = InFlag.getOpcode(); Opc=Opc; + assert(((Opc == ISD::ADDC || Opc == ISD::ADDE) || + (Opc == ISD::SUBC || Opc == ISD::SUBE)) && + "(ADD|SUB)E flag operand must come from (ADD|SUB)C/E insn"); + + unsigned MOp; + if (Opcode == ISD::ADDE) { + CmpLHS = InFlag.getValue(0); + MOp = Mips::ADDu; + } else { + CmpLHS = InFlag.getOperand(0); + MOp = Mips::SUBu; + } + + SDValue Ops[] = { CmpLHS, InFlag.getOperand(1) }; + + SDValue LHS = Node->getOperand(0); + SDValue RHS = Node->getOperand(1); + + MVT VT = LHS.getValueType(); + SDNode *Carry = CurDAG->getTargetNode(Mips::SLTu, dl, VT, Ops, 2); + SDNode *AddCarry = CurDAG->getTargetNode(Mips::ADDu, dl, VT, + SDValue(Carry,0), RHS); + + return CurDAG->SelectNodeTo(N.getNode(), MOp, VT, MVT::Flag, + LHS, SDValue(AddCarry,0)); + } + + /// Mul/Div with two results + case ISD::SDIVREM: + case ISD::UDIVREM: + case ISD::SMUL_LOHI: + case ISD::UMUL_LOHI: { + SDValue Op1 = Node->getOperand(0); + SDValue Op2 = Node->getOperand(1); + + unsigned Op; + if (Opcode == ISD::UMUL_LOHI || Opcode == ISD::SMUL_LOHI) + Op = (Opcode == ISD::UMUL_LOHI ? Mips::MULTu : Mips::MULT); + else + Op = (Opcode == ISD::UDIVREM ? Mips::DIVu : Mips::DIV); + + SDNode *Node = CurDAG->getTargetNode(Op, dl, MVT::Flag, Op1, Op2); + + SDValue InFlag = SDValue(Node, 0); + SDNode *Lo = CurDAG->getTargetNode(Mips::MFLO, dl, MVT::i32, + MVT::Flag, InFlag); + InFlag = SDValue(Lo,1); + SDNode *Hi = CurDAG->getTargetNode(Mips::MFHI, dl, MVT::i32, InFlag); + + if (!N.getValue(0).use_empty()) + ReplaceUses(N.getValue(0), SDValue(Lo,0)); + + if (!N.getValue(1).use_empty()) + ReplaceUses(N.getValue(1), SDValue(Hi,0)); + + return NULL; + } + + /// Special Muls + case ISD::MUL: + case ISD::MULHS: + case ISD::MULHU: { + SDValue MulOp1 = Node->getOperand(0); + SDValue MulOp2 = Node->getOperand(1); + + unsigned MulOp = (Opcode == ISD::MULHU ? Mips::MULTu : Mips::MULT); + SDNode *MulNode = CurDAG->getTargetNode(MulOp, dl, + MVT::Flag, MulOp1, MulOp2); + + SDValue InFlag = SDValue(MulNode, 0); + + if (MulOp == ISD::MUL) + return CurDAG->getTargetNode(Mips::MFLO, dl, MVT::i32, InFlag); + else + return CurDAG->getTargetNode(Mips::MFHI, dl, MVT::i32, InFlag); + } + + /// Div/Rem operations + case ISD::SREM: + case ISD::UREM: + case ISD::SDIV: + case ISD::UDIV: { + SDValue Op1 = Node->getOperand(0); + SDValue Op2 = Node->getOperand(1); + + unsigned Op, MOp; + if (Opcode == ISD::SDIV || Opcode == ISD::UDIV) { + Op = (Opcode == ISD::SDIV ? Mips::DIV : Mips::DIVu); + MOp = Mips::MFLO; + } else { + Op = (Opcode == ISD::SREM ? Mips::DIV : Mips::DIVu); + MOp = Mips::MFHI; + } + SDNode *Node = CurDAG->getTargetNode(Op, dl, MVT::Flag, Op1, Op2); + + SDValue InFlag = SDValue(Node, 0); + return CurDAG->getTargetNode(MOp, dl, MVT::i32, InFlag); + } + + // Get target GOT address. + case ISD::GLOBAL_OFFSET_TABLE: { + SDValue Result = getGlobalBaseReg(); + ReplaceUses(N, Result); + return NULL; + } + + /// Handle direct and indirect calls when using PIC. On PIC, when + /// GOT is smaller than about 64k (small code) the GA target is + /// loaded with only one instruction. Otherwise GA's target must + /// be loaded with 3 instructions. + case MipsISD::JmpLink: { + if (TM.getRelocationModel() == Reloc::PIC_) { + //bool isCodeLarge = (TM.getCodeModel() == CodeModel::Large); + SDValue Chain = Node->getOperand(0); + SDValue Callee = Node->getOperand(1); + SDValue T9Reg = CurDAG->getRegister(Mips::T9, MVT::i32); + SDValue InFlag(0, 0); + + if ( (isa<GlobalAddressSDNode>(Callee)) || + (isa<ExternalSymbolSDNode>(Callee)) ) + { + /// Direct call for global addresses and external symbols + SDValue GPReg = CurDAG->getRegister(Mips::GP, MVT::i32); + + // Use load to get GOT target + SDValue Ops[] = { Callee, GPReg, Chain }; + SDValue Load = SDValue(CurDAG->getTargetNode(Mips::LW, dl, MVT::i32, + MVT::Other, Ops, 3), 0); + Chain = Load.getValue(1); + + // Call target must be on T9 + Chain = CurDAG->getCopyToReg(Chain, dl, T9Reg, Load, InFlag); + } else + /// Indirect call + Chain = CurDAG->getCopyToReg(Chain, dl, T9Reg, Callee, InFlag); + + // Emit Jump and Link Register + SDNode *ResNode = CurDAG->getTargetNode(Mips::JALR, dl, MVT::Other, + MVT::Flag, T9Reg, Chain); + Chain = SDValue(ResNode, 0); + InFlag = SDValue(ResNode, 1); + ReplaceUses(SDValue(Node, 0), Chain); + ReplaceUses(SDValue(Node, 1), InFlag); + return ResNode; + } + } + } + + // Select the default instruction + SDNode *ResNode = SelectCode(N); + + #ifndef NDEBUG + DOUT << std::string(Indent-2, ' ') << "=> "; + if (ResNode == NULL || ResNode == N.getNode()) + DEBUG(N.getNode()->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 000000000000..9281940019a9 --- /dev/null +++ b/lib/Target/Mips/MipsISelLowering.cpp @@ -0,0 +1,1254 @@ +//===-- MipsISelLowering.cpp - Mips DAG Lowering Implementation -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file 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 "MipsMachineFunction.h" +#include "MipsTargetMachine.h" +#include "MipsSubtarget.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Function.h" +#include "llvm/GlobalVariable.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/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/Support/Debug.h" +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::GPRel : return "MipsISD::GPRel"; + case MipsISD::Ret : return "MipsISD::Ret"; + case MipsISD::CMov : return "MipsISD::CMov"; + case MipsISD::SelectCC : return "MipsISD::SelectCC"; + case MipsISD::FPSelectCC : return "MipsISD::FPSelectCC"; + case MipsISD::FPBrcond : return "MipsISD::FPBrcond"; + case MipsISD::FPCmp : return "MipsISD::FPCmp"; + case MipsISD::FPRound : return "MipsISD::FPRound"; + default : return NULL; + } +} + +MipsTargetLowering:: +MipsTargetLowering(MipsTargetMachine &TM): TargetLowering(TM) +{ + Subtarget = &TM.getSubtarget<MipsSubtarget>(); + + // Mips does not have i1 type, so use i32 for + // setcc operations results (slt, sgt, ...). + setBooleanContents(ZeroOrOneBooleanContent); + + // JumpTable targets must use GOT when using PIC_ + setUsesGlobalOffsetTable(true); + + // Set up the register classes + addRegisterClass(MVT::i32, Mips::CPURegsRegisterClass); + addRegisterClass(MVT::f32, Mips::FGR32RegisterClass); + + // When dealing with single precision only, use libcalls + if (!Subtarget->isSingleFloat()) + if (!Subtarget->isFP64bit()) + addRegisterClass(MVT::f64, Mips::AFGR64RegisterClass); + + // Legal fp constants + addLegalFPImmediate(APFloat(+0.0f)); + + // Load extented operations for i1 types must be promoted + setLoadExtAction(ISD::EXTLOAD, MVT::i1, Promote); + setLoadExtAction(ISD::ZEXTLOAD, MVT::i1, Promote); + setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote); + + // Used by legalize types to correctly generate the setcc result. + // Without this, every float setcc comes with a AND/OR with the result, + // we don't want this, since the fpcmp result goes to a flag register, + // which is used implicitly by brcond and select operations. + AddPromotedToType(ISD::SETCC, MVT::i1, MVT::i32); + + // Mips Custom Operations + setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); + setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom); + setOperationAction(ISD::RET, MVT::Other, Custom); + setOperationAction(ISD::JumpTable, MVT::i32, Custom); + setOperationAction(ISD::ConstantPool, MVT::i32, Custom); + setOperationAction(ISD::SELECT, MVT::f32, Custom); + setOperationAction(ISD::SELECT, MVT::i32, Custom); + setOperationAction(ISD::SETCC, MVT::f32, Custom); + setOperationAction(ISD::SETCC, MVT::f64, Custom); + setOperationAction(ISD::BRCOND, MVT::Other, Custom); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Custom); + setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); + + // We custom lower AND/OR to handle the case where the DAG contain 'ands/ors' + // with operands comming from setcc fp comparions. This is necessary since + // the result from these setcc are in a flag registers (FCR31). + setOperationAction(ISD::AND, MVT::i32, Custom); + setOperationAction(ISD::OR, MVT::i32, Custom); + + // Operations not directly supported by Mips. + setOperationAction(ISD::BR_JT, MVT::Other, Expand); + setOperationAction(ISD::BR_CC, MVT::Other, Expand); + setOperationAction(ISD::SELECT_CC, MVT::Other, Expand); + setOperationAction(ISD::UINT_TO_FP, MVT::i32, Expand); + setOperationAction(ISD::FP_TO_UINT, MVT::i32, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); + setOperationAction(ISD::CTPOP, MVT::i32, Expand); + setOperationAction(ISD::CTTZ, MVT::i32, Expand); + setOperationAction(ISD::ROTL, MVT::i32, Expand); + setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand); + setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand); + setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand); + setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand); + + // We don't have line number support yet. + setOperationAction(ISD::DBG_STOPPOINT, MVT::Other, Expand); + setOperationAction(ISD::DEBUG_LOC, MVT::Other, Expand); + setOperationAction(ISD::DBG_LABEL, MVT::Other, Expand); + setOperationAction(ISD::EH_LABEL, MVT::Other, Expand); + + // Use the default for now + setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); + setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); + setOperationAction(ISD::MEMBARRIER, MVT::Other, Expand); + + if (Subtarget->isSingleFloat()) + setOperationAction(ISD::SELECT_CC, MVT::f64, Expand); + + if (!Subtarget->hasSEInReg()) { + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand); + } + + if (!Subtarget->hasBitCount()) + setOperationAction(ISD::CTLZ, MVT::i32, Expand); + + if (!Subtarget->hasSwap()) + setOperationAction(ISD::BSWAP, MVT::i32, Expand); + + setStackPointerRegisterToSaveRestore(Mips::SP); + computeRegisterProperties(); +} + + +MVT MipsTargetLowering::getSetCCResultType(MVT VT) const { + return MVT::i32; +} + + +SDValue MipsTargetLowering:: +LowerOperation(SDValue Op, SelectionDAG &DAG) +{ + switch (Op.getOpcode()) + { + case ISD::AND: return LowerANDOR(Op, DAG); + case ISD::BRCOND: return LowerBRCOND(Op, DAG); + case ISD::CALL: return LowerCALL(Op, DAG); + case ISD::ConstantPool: return LowerConstantPool(Op, DAG); + case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG); + case ISD::FORMAL_ARGUMENTS: return LowerFORMAL_ARGUMENTS(Op, DAG); + case ISD::FP_TO_SINT: return LowerFP_TO_SINT(Op, DAG); + case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); + case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG); + case ISD::JumpTable: return LowerJumpTable(Op, DAG); + case ISD::OR: return LowerANDOR(Op, DAG); + case ISD::RET: return LowerRET(Op, DAG); + case ISD::SELECT: return LowerSELECT(Op, DAG); + case ISD::SETCC: return LowerSETCC(Op, DAG); + } + return SDValue(); +} + +//===----------------------------------------------------------------------===// +// 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.getRegInfo().createVirtualRegister(RC); + MF.getRegInfo().addLiveIn(PReg, VReg); + return VReg; +} + +// A address must be loaded from a small section if its size is less than the +// small section size threshold. Data in this section must be addressed using +// gp_rel operator. +bool MipsTargetLowering::IsInSmallSection(unsigned Size) { + return (Size > 0 && (Size <= Subtarget->getSSectionThreshold())); +} + +// Discover if this global address can be placed into small data/bss section. +bool MipsTargetLowering::IsGlobalInSmallSection(GlobalValue *GV) +{ + const TargetData *TD = getTargetData(); + const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GV); + + if (!GVA) + return false; + + const Type *Ty = GV->getType()->getElementType(); + unsigned Size = TD->getTypeAllocSize(Ty); + + // if this is a internal constant string, there is a special + // section for it, but not in small data/bss. + if (GVA->hasInitializer() && GV->hasLocalLinkage()) { + Constant *C = GVA->getInitializer(); + const ConstantArray *CVA = dyn_cast<ConstantArray>(C); + if (CVA && CVA->isCString()) + return false; + } + + return IsInSmallSection(Size); +} + +// Get fp branch code (not opcode) from condition code. +static Mips::FPBranchCode GetFPBranchCodeFromCond(Mips::CondCode CC) { + if (CC >= Mips::FCOND_F && CC <= Mips::FCOND_NGT) + return Mips::BRANCH_T; + + if (CC >= Mips::FCOND_T && CC <= Mips::FCOND_GT) + return Mips::BRANCH_F; + + return Mips::BRANCH_INVALID; +} + +static unsigned FPBranchCodeToOpc(Mips::FPBranchCode BC) { + switch(BC) { + default: + assert(0 && "Unknown branch code"); + case Mips::BRANCH_T : return Mips::BC1T; + case Mips::BRANCH_F : return Mips::BC1F; + case Mips::BRANCH_TL : return Mips::BC1TL; + case Mips::BRANCH_FL : return Mips::BC1FL; + } +} + +static Mips::CondCode FPCondCCodeToFCC(ISD::CondCode CC) { + switch (CC) { + default: assert(0 && "Unknown fp condition code!"); + case ISD::SETEQ: + case ISD::SETOEQ: return Mips::FCOND_EQ; + case ISD::SETUNE: return Mips::FCOND_OGL; + case ISD::SETLT: + case ISD::SETOLT: return Mips::FCOND_OLT; + case ISD::SETGT: + case ISD::SETOGT: return Mips::FCOND_OGT; + case ISD::SETLE: + case ISD::SETOLE: return Mips::FCOND_OLE; + case ISD::SETGE: + case ISD::SETOGE: return Mips::FCOND_OGE; + case ISD::SETULT: return Mips::FCOND_ULT; + case ISD::SETULE: return Mips::FCOND_ULE; + case ISD::SETUGT: return Mips::FCOND_UGT; + case ISD::SETUGE: return Mips::FCOND_UGE; + case ISD::SETUO: return Mips::FCOND_UN; + case ISD::SETO: return Mips::FCOND_OR; + case ISD::SETNE: + case ISD::SETONE: return Mips::FCOND_NEQ; + case ISD::SETUEQ: return Mips::FCOND_UEQ; + } +} + +MachineBasicBlock * +MipsTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *BB) const { + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + bool isFPCmp = false; + DebugLoc dl = MI->getDebugLoc(); + + switch (MI->getOpcode()) { + default: assert(false && "Unexpected instr type to insert"); + case Mips::Select_FCC: + case Mips::Select_FCC_S32: + case Mips::Select_FCC_D32: + isFPCmp = true; // FALL THROUGH + case Mips::Select_CC: + case Mips::Select_CC_S32: + case Mips::Select_CC_D32: { + // To "insert" a SELECT_CC instruction, we actually have to insert the + // diamond control-flow pattern. The incoming instruction knows the + // destination vreg to set, the condition code register to branch on, the + // true/false values to select between, and a branch opcode to use. + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = BB; + ++It; + + // thisMBB: + // ... + // TrueVal = ... + // setcc r1, r2, r3 + // bNE r1, r0, copy1MBB + // fallthrough --> copy0MBB + MachineBasicBlock *thisMBB = BB; + MachineFunction *F = BB->getParent(); + MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB); + + // Emit the right instruction according to the type of the operands compared + if (isFPCmp) { + // Find the condiction code present in the setcc operation. + Mips::CondCode CC = (Mips::CondCode)MI->getOperand(4).getImm(); + // Get the branch opcode from the branch code. + unsigned Opc = FPBranchCodeToOpc(GetFPBranchCodeFromCond(CC)); + BuildMI(BB, dl, TII->get(Opc)).addMBB(sinkMBB); + } else + BuildMI(BB, dl, TII->get(Mips::BNE)).addReg(MI->getOperand(1).getReg()) + .addReg(Mips::ZERO).addMBB(sinkMBB); + + F->insert(It, copy0MBB); + F->insert(It, sinkMBB); + // Update machine-CFG edges by first adding all successors of the current + // block to the new block which will contain the Phi node for the select. + for(MachineBasicBlock::succ_iterator i = BB->succ_begin(), + e = BB->succ_end(); i != e; ++i) + sinkMBB->addSuccessor(*i); + // Next, remove all successors of the current block, and add the true + // and fallthrough blocks as its successors. + while(!BB->succ_empty()) + BB->removeSuccessor(BB->succ_begin()); + BB->addSuccessor(copy0MBB); + BB->addSuccessor(sinkMBB); + + // copy0MBB: + // %FalseValue = ... + // # fallthrough to sinkMBB + BB = copy0MBB; + + // Update machine-CFG edges + BB->addSuccessor(sinkMBB); + + // sinkMBB: + // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ] + // ... + BB = sinkMBB; + BuildMI(BB, dl, TII->get(Mips::PHI), MI->getOperand(0).getReg()) + .addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB) + .addReg(MI->getOperand(3).getReg()).addMBB(thisMBB); + + F->DeleteMachineInstr(MI); // The pseudo instruction is gone now. + return BB; + } + } +} + +//===----------------------------------------------------------------------===// +// Misc Lower Operation implementation +//===----------------------------------------------------------------------===// + +SDValue MipsTargetLowering:: +LowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG) +{ + if (!Subtarget->isMips1()) + return Op; + + MachineFunction &MF = DAG.getMachineFunction(); + unsigned CCReg = AddLiveIn(MF, Mips::FCR31, Mips::CCRRegisterClass); + + SDValue Chain = DAG.getEntryNode(); + DebugLoc dl = Op.getDebugLoc(); + SDValue Src = Op.getOperand(0); + + // Set the condition register + SDValue CondReg = DAG.getCopyFromReg(Chain, dl, CCReg, MVT::i32); + CondReg = DAG.getCopyToReg(Chain, dl, Mips::AT, CondReg); + CondReg = DAG.getCopyFromReg(CondReg, dl, Mips::AT, MVT::i32); + + SDValue Cst = DAG.getConstant(3, MVT::i32); + SDValue Or = DAG.getNode(ISD::OR, dl, MVT::i32, CondReg, Cst); + Cst = DAG.getConstant(2, MVT::i32); + SDValue Xor = DAG.getNode(ISD::XOR, dl, MVT::i32, Or, Cst); + + SDValue InFlag(0, 0); + CondReg = DAG.getCopyToReg(Chain, dl, Mips::FCR31, Xor, InFlag); + + // Emit the round instruction and bit convert to integer + SDValue Trunc = DAG.getNode(MipsISD::FPRound, dl, MVT::f32, + Src, CondReg.getValue(1)); + SDValue BitCvt = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i32, Trunc); + return BitCvt; +} + +SDValue MipsTargetLowering:: +LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) +{ + SDValue Chain = Op.getOperand(0); + SDValue Size = Op.getOperand(1); + DebugLoc dl = Op.getDebugLoc(); + + // Get a reference from Mips stack pointer + SDValue StackPointer = DAG.getCopyFromReg(Chain, dl, Mips::SP, MVT::i32); + + // Subtract the dynamic size from the actual stack size to + // obtain the new stack size. + SDValue Sub = DAG.getNode(ISD::SUB, dl, MVT::i32, StackPointer, Size); + + // The Sub result contains the new stack start address, so it + // must be placed in the stack pointer register. + Chain = DAG.getCopyToReg(StackPointer.getValue(1), dl, Mips::SP, Sub); + + // This node always has two return values: a new stack pointer + // value and a chain + SDValue Ops[2] = { Sub, Chain }; + return DAG.getMergeValues(Ops, 2, dl); +} + +SDValue MipsTargetLowering:: +LowerANDOR(SDValue Op, SelectionDAG &DAG) +{ + SDValue LHS = Op.getOperand(0); + SDValue RHS = Op.getOperand(1); + DebugLoc dl = Op.getDebugLoc(); + + if (LHS.getOpcode() != MipsISD::FPCmp || RHS.getOpcode() != MipsISD::FPCmp) + return Op; + + SDValue True = DAG.getConstant(1, MVT::i32); + SDValue False = DAG.getConstant(0, MVT::i32); + + SDValue LSEL = DAG.getNode(MipsISD::FPSelectCC, dl, True.getValueType(), + LHS, True, False, LHS.getOperand(2)); + SDValue RSEL = DAG.getNode(MipsISD::FPSelectCC, dl, True.getValueType(), + RHS, True, False, RHS.getOperand(2)); + + return DAG.getNode(Op.getOpcode(), dl, MVT::i32, LSEL, RSEL); +} + +SDValue MipsTargetLowering:: +LowerBRCOND(SDValue Op, SelectionDAG &DAG) +{ + // The first operand is the chain, the second is the condition, the third is + // the block to branch to if the condition is true. + SDValue Chain = Op.getOperand(0); + SDValue Dest = Op.getOperand(2); + DebugLoc dl = Op.getDebugLoc(); + + if (Op.getOperand(1).getOpcode() != MipsISD::FPCmp) + return Op; + + SDValue CondRes = Op.getOperand(1); + SDValue CCNode = CondRes.getOperand(2); + Mips::CondCode CC = + (Mips::CondCode)cast<ConstantSDNode>(CCNode)->getZExtValue(); + SDValue BrCode = DAG.getConstant(GetFPBranchCodeFromCond(CC), MVT::i32); + + return DAG.getNode(MipsISD::FPBrcond, dl, Op.getValueType(), Chain, BrCode, + Dest, CondRes); +} + +SDValue MipsTargetLowering:: +LowerSETCC(SDValue Op, SelectionDAG &DAG) +{ + // The operands to this are the left and right operands to compare (ops #0, + // and #1) and the condition code to compare them with (op #2) as a + // CondCodeSDNode. + SDValue LHS = Op.getOperand(0); + SDValue RHS = Op.getOperand(1); + DebugLoc dl = Op.getDebugLoc(); + + ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(2))->get(); + + return DAG.getNode(MipsISD::FPCmp, dl, Op.getValueType(), LHS, RHS, + DAG.getConstant(FPCondCCodeToFCC(CC), MVT::i32)); +} + +SDValue MipsTargetLowering:: +LowerSELECT(SDValue Op, SelectionDAG &DAG) +{ + SDValue Cond = Op.getOperand(0); + SDValue True = Op.getOperand(1); + SDValue False = Op.getOperand(2); + DebugLoc dl = Op.getDebugLoc(); + + // if the incomming condition comes from a integer compare, the select + // operation must be SelectCC or a conditional move if the subtarget + // supports it. + if (Cond.getOpcode() != MipsISD::FPCmp) { + if (Subtarget->hasCondMov() && !True.getValueType().isFloatingPoint()) + return Op; + return DAG.getNode(MipsISD::SelectCC, dl, True.getValueType(), + Cond, True, False); + } + + // if the incomming condition comes from fpcmp, the select + // operation must use FPSelectCC. + SDValue CCNode = Cond.getOperand(2); + return DAG.getNode(MipsISD::FPSelectCC, dl, True.getValueType(), + Cond, True, False, CCNode); +} + +SDValue MipsTargetLowering:: +LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) +{ + // FIXME there isn't actually debug info here + DebugLoc dl = Op.getDebugLoc(); + GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal(); + SDValue GA = DAG.getTargetGlobalAddress(GV, MVT::i32); + + if (!Subtarget->hasABICall()) { + SDVTList VTs = DAG.getVTList(MVT::i32); + SDValue Ops[] = { GA }; + // %gp_rel relocation + if (!isa<Function>(GV) && IsGlobalInSmallSection(GV)) { + SDValue GPRelNode = DAG.getNode(MipsISD::GPRel, dl, VTs, Ops, 1); + SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(MVT::i32); + return DAG.getNode(ISD::ADD, dl, MVT::i32, GOT, GPRelNode); + } + // %hi/%lo relocation + SDValue HiPart = DAG.getNode(MipsISD::Hi, dl, VTs, Ops, 1); + SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, GA); + return DAG.getNode(ISD::ADD, dl, MVT::i32, HiPart, Lo); + + } else { // Abicall relocations, TODO: make this cleaner. + SDValue ResNode = DAG.getLoad(MVT::i32, dl, + DAG.getEntryNode(), GA, NULL, 0); + // On functions and global targets not internal linked only + // a load from got/GP is necessary for PIC to work. + if (!GV->hasLocalLinkage() || isa<Function>(GV)) + return ResNode; + SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, GA); + return DAG.getNode(ISD::ADD, dl, MVT::i32, ResNode, Lo); + } + + assert(0 && "Dont know how to handle GlobalAddress"); + return SDValue(0,0); +} + +SDValue MipsTargetLowering:: +LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) +{ + assert(0 && "TLS not implemented for MIPS."); + return SDValue(); // Not reached +} + +SDValue MipsTargetLowering:: +LowerJumpTable(SDValue Op, SelectionDAG &DAG) +{ + SDValue ResNode; + SDValue HiPart; + // FIXME there isn't actually debug info here + DebugLoc dl = Op.getDebugLoc(); + + MVT PtrVT = Op.getValueType(); + JumpTableSDNode *JT = cast<JumpTableSDNode>(Op); + SDValue JTI = DAG.getTargetJumpTable(JT->getIndex(), PtrVT); + + if (getTargetMachine().getRelocationModel() != Reloc::PIC_) { + SDVTList VTs = DAG.getVTList(MVT::i32); + SDValue Ops[] = { JTI }; + HiPart = DAG.getNode(MipsISD::Hi, dl, VTs, Ops, 1); + } else // Emit Load from Global Pointer + HiPart = DAG.getLoad(MVT::i32, dl, DAG.getEntryNode(), JTI, NULL, 0); + + SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, JTI); + ResNode = DAG.getNode(ISD::ADD, dl, MVT::i32, HiPart, Lo); + + return ResNode; +} + +SDValue MipsTargetLowering:: +LowerConstantPool(SDValue Op, SelectionDAG &DAG) +{ + SDValue ResNode; + ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op); + Constant *C = N->getConstVal(); + SDValue CP = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment()); + // FIXME there isn't actually debug info here + DebugLoc dl = Op.getDebugLoc(); + + // gp_rel relocation + // FIXME: we should reference the constant pool using small data sections, + // but the asm printer currently doens't support this feature without + // hacking it. This feature should come soon so we can uncomment the + // stuff below. + //if (!Subtarget->hasABICall() && + // IsInSmallSection(getTargetData()->getTypeAllocSize(C->getType()))) { + // SDValue GPRelNode = DAG.getNode(MipsISD::GPRel, MVT::i32, CP); + // SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(MVT::i32); + // ResNode = DAG.getNode(ISD::ADD, MVT::i32, GOT, GPRelNode); + //} else { // %hi/%lo relocation + SDValue HiPart = DAG.getNode(MipsISD::Hi, dl, MVT::i32, CP); + SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, CP); + ResNode = DAG.getNode(ISD::ADD, dl, MVT::i32, HiPart, Lo); + //} + + return ResNode; +} + +//===----------------------------------------------------------------------===// +// 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" + +//===----------------------------------------------------------------------===// +// TODO: Implement a generic logic using tblgen that can support this. +// Mips O32 ABI rules: +// --- +// i32 - Passed in A0, A1, A2, A3 and stack +// f32 - Only passed in f32 registers if no int reg has been used yet to hold +// an argument. Otherwise, passed in A1, A2, A3 and stack. +// f64 - Only passed in two aliased f32 registers if no int reg has been used +// yet to hold an argument. Otherwise, use A2, A3 and stack. If A1 is +// not used, it must be shadowed. If only A3 is avaiable, shadow it and +// go to stack. +//===----------------------------------------------------------------------===// + +static bool CC_MipsO32(unsigned ValNo, MVT ValVT, + MVT LocVT, CCValAssign::LocInfo LocInfo, + ISD::ArgFlagsTy ArgFlags, CCState &State) { + + static const unsigned IntRegsSize=4, FloatRegsSize=2; + + static const unsigned IntRegs[] = { + Mips::A0, Mips::A1, Mips::A2, Mips::A3 + }; + static const unsigned F32Regs[] = { + Mips::F12, Mips::F14 + }; + static const unsigned F64Regs[] = { + Mips::D6, Mips::D7 + }; + + unsigned Reg=0; + unsigned UnallocIntReg = State.getFirstUnallocated(IntRegs, IntRegsSize); + bool IntRegUsed = (IntRegs[UnallocIntReg] != (unsigned (Mips::A0))); + + // Promote i8 and i16 + if (LocVT == MVT::i8 || LocVT == MVT::i16) { + LocVT = MVT::i32; + if (ArgFlags.isSExt()) + LocInfo = CCValAssign::SExt; + else if (ArgFlags.isZExt()) + LocInfo = CCValAssign::ZExt; + else + LocInfo = CCValAssign::AExt; + } + + if (ValVT == MVT::i32 || (ValVT == MVT::f32 && IntRegUsed)) { + Reg = State.AllocateReg(IntRegs, IntRegsSize); + IntRegUsed = true; + LocVT = MVT::i32; + } + + if (ValVT.isFloatingPoint() && !IntRegUsed) { + if (ValVT == MVT::f32) + Reg = State.AllocateReg(F32Regs, FloatRegsSize); + else + Reg = State.AllocateReg(F64Regs, FloatRegsSize); + } + + if (ValVT == MVT::f64 && IntRegUsed) { + if (UnallocIntReg != IntRegsSize) { + // If we hit register A3 as the first not allocated, we must + // mark it as allocated (shadow) and use the stack instead. + if (IntRegs[UnallocIntReg] != (unsigned (Mips::A3))) + Reg = Mips::A2; + for (;UnallocIntReg < IntRegsSize; ++UnallocIntReg) + State.AllocateReg(UnallocIntReg); + } + LocVT = MVT::i32; + } + + if (!Reg) { + unsigned SizeInBytes = ValVT.getSizeInBits() >> 3; + unsigned Offset = State.AllocateStack(SizeInBytes, SizeInBytes); + State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); + } else + State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); + + return false; // CC must always match +} + +//===----------------------------------------------------------------------===// +// CALL Calling Convention Implementation +//===----------------------------------------------------------------------===// + +/// LowerCALL - functions arguments are copied from virtual regs to +/// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted. +/// TODO: isVarArg, isTailCall. +SDValue MipsTargetLowering:: +LowerCALL(SDValue Op, SelectionDAG &DAG) +{ + MachineFunction &MF = DAG.getMachineFunction(); + + CallSDNode *TheCall = cast<CallSDNode>(Op.getNode()); + SDValue Chain = TheCall->getChain(); + SDValue Callee = TheCall->getCallee(); + bool isVarArg = TheCall->isVarArg(); + unsigned CC = TheCall->getCallingConv(); + DebugLoc dl = TheCall->getDebugLoc(); + + MachineFrameInfo *MFI = MF.getFrameInfo(); + + // Analyze operands of the call, assigning locations to each operand. + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CC, isVarArg, getTargetMachine(), ArgLocs); + + // To meet O32 ABI, Mips must always allocate 16 bytes on + // the stack (even if less than 4 are used as arguments) + if (Subtarget->isABI_O32()) { + int VTsize = MVT(MVT::i32).getSizeInBits()/8; + MFI->CreateFixedObject(VTsize, (VTsize*3)); + CCInfo.AnalyzeCallOperands(TheCall, CC_MipsO32); + } else + CCInfo.AnalyzeCallOperands(TheCall, 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.getIntPtrConstant(NumBytes, true)); + + // With EABI is it possible to have 16 args on registers. + SmallVector<std::pair<unsigned, SDValue>, 16> RegsToPass; + SmallVector<SDValue, 8> MemOpChains; + + // First/LastArgStackLoc contains the first/last + // "at stack" argument location. + int LastArgStackLoc = 0; + unsigned FirstStackArgLoc = (Subtarget->isABI_EABI() ? 0 : 16); + + // Walk the register/memloc assignments, inserting copies/loads. + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + SDValue Arg = TheCall->getArg(i); + CCValAssign &VA = ArgLocs[i]; + + // Promote the value if needed. + switch (VA.getLocInfo()) { + default: assert(0 && "Unknown loc info!"); + case CCValAssign::Full: + if (Subtarget->isABI_O32() && VA.isRegLoc()) { + if (VA.getValVT() == MVT::f32 && VA.getLocVT() == MVT::i32) + Arg = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i32, Arg); + if (VA.getValVT() == MVT::f64 && VA.getLocVT() == MVT::i32) { + Arg = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i64, Arg); + SDValue Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, Arg, + DAG.getConstant(0, getPointerTy())); + SDValue Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, Arg, + DAG.getConstant(1, getPointerTy())); + RegsToPass.push_back(std::make_pair(VA.getLocReg(), Lo)); + RegsToPass.push_back(std::make_pair(VA.getLocReg()+1, Hi)); + continue; + } + } + break; + case CCValAssign::SExt: + Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg); + break; + case CCValAssign::ZExt: + Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg); + break; + case CCValAssign::AExt: + Arg = DAG.getNode(ISD::ANY_EXTEND, dl, 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)); + continue; + } + + // Register can't get to this point... + assert(VA.isMemLoc()); + + // Create the frame index object for this incoming parameter + // This guarantees that when allocating Local Area the firsts + // 16 bytes which are alwayes reserved won't be overwritten + // if O32 ABI is used. For EABI the first address is zero. + LastArgStackLoc = (FirstStackArgLoc + VA.getLocMemOffset()); + int FI = MFI->CreateFixedObject(VA.getValVT().getSizeInBits()/8, + LastArgStackLoc); + + SDValue PtrOff = DAG.getFrameIndex(FI,getPointerTy()); + + // emit ISD::STORE whichs stores the + // parameter value to a stack Location + MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff, NULL, 0)); + } + + // Transform all store nodes into one single node because all store + // nodes are independent of each other. + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, dl, 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. + SDValue InFlag; + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { + Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first, + RegsToPass[i].second, InFlag); + InFlag = Chain.getValue(1); + } + + // If the callee is a GlobalAddress/ExternalSymbol node (quite common, every + // direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol + // node so that legalize doesn't hack it. + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), getPointerTy()); + else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(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<SDValue, 8> 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.getNode()) + Ops.push_back(InFlag); + + Chain = DAG.getNode(MipsISD::JmpLink, dl, NodeTys, &Ops[0], Ops.size()); + InFlag = Chain.getValue(1); + + // Create the CALLSEQ_END node. + Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(NumBytes, true), + DAG.getIntPtrConstant(0, true), InFlag); + InFlag = Chain.getValue(1); + + // Create a stack location to hold GP when PIC is used. This stack + // location is used on function prologue to save GP and also after all + // emited CALL's to restore GP. + if (getTargetMachine().getRelocationModel() == Reloc::PIC_) { + // Function can have an arbitrary number of calls, so + // hold the LastArgStackLoc with the biggest offset. + int FI; + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + if (LastArgStackLoc >= MipsFI->getGPStackOffset()) { + LastArgStackLoc = (!LastArgStackLoc) ? (16) : (LastArgStackLoc+4); + // Create the frame index only once. SPOffset here can be anything + // (this will be fixed on processFunctionBeforeFrameFinalized) + if (MipsFI->getGPStackOffset() == -1) { + FI = MFI->CreateFixedObject(4, 0); + MipsFI->setGPFI(FI); + } + MipsFI->setGPStackOffset(LastArgStackLoc); + } + + // Reload GP value. + FI = MipsFI->getGPFI(); + SDValue FIN = DAG.getFrameIndex(FI,getPointerTy()); + SDValue GPLoad = DAG.getLoad(MVT::i32, dl, Chain, FIN, NULL, 0); + Chain = GPLoad.getValue(1); + Chain = DAG.getCopyToReg(Chain, dl, DAG.getRegister(Mips::GP, MVT::i32), + GPLoad, SDValue(0,0)); + InFlag = Chain.getValue(1); + } + + // Handle result values, copying them out of physregs into vregs that we + // return. + return SDValue(LowerCallResult(Chain, InFlag, TheCall, CC, DAG), Op.getResNo()); +} + +/// 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(SDValue Chain, SDValue InFlag, CallSDNode *TheCall, + unsigned CallingConv, SelectionDAG &DAG) { + + bool isVarArg = TheCall->isVarArg(); + DebugLoc dl = TheCall->getDebugLoc(); + + // Assign locations to each value returned by this call. + SmallVector<CCValAssign, 16> RVLocs; + CCState CCInfo(CallingConv, isVarArg, getTargetMachine(), RVLocs); + + CCInfo.AnalyzeCallResult(TheCall, RetCC_Mips); + SmallVector<SDValue, 8> ResultVals; + + // Copy all of the result registers out of their specified physreg. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + Chain = DAG.getCopyFromReg(Chain, dl, RVLocs[i].getLocReg(), + RVLocs[i].getValVT(), InFlag).getValue(1); + InFlag = Chain.getValue(2); + ResultVals.push_back(Chain.getValue(0)); + } + + ResultVals.push_back(Chain); + + // Merge everything together with a MERGE_VALUES node. + return DAG.getNode(ISD::MERGE_VALUES, dl, TheCall->getVTList(), + &ResultVals[0], ResultVals.size()).getNode(); +} + +//===----------------------------------------------------------------------===// +// FORMAL_ARGUMENTS Calling Convention Implementation +//===----------------------------------------------------------------------===// + +/// LowerFORMAL_ARGUMENTS - transform physical registers into +/// virtual registers and generate load operations for +/// arguments places on the stack. +/// TODO: isVarArg +SDValue MipsTargetLowering:: +LowerFORMAL_ARGUMENTS(SDValue Op, SelectionDAG &DAG) +{ + SDValue Root = Op.getOperand(0); + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + DebugLoc dl = Op.getDebugLoc(); + + bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue() != 0; + unsigned CC = DAG.getMachineFunction().getFunction()->getCallingConv(); + + unsigned StackReg = MF.getTarget().getRegisterInfo()->getFrameRegister(MF); + + // GP must be live into PIC and non-PIC call target. + AddLiveIn(MF, Mips::GP, Mips::CPURegsRegisterClass); + + // Assign locations to all of the incoming arguments. + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CC, isVarArg, getTargetMachine(), ArgLocs); + + if (Subtarget->isABI_O32()) + CCInfo.AnalyzeFormalArguments(Op.getNode(), CC_MipsO32); + else + CCInfo.AnalyzeFormalArguments(Op.getNode(), CC_Mips); + + SmallVector<SDValue, 16> ArgValues; + SDValue StackPtr; + + unsigned FirstStackArgLoc = (Subtarget->isABI_EABI() ? 0 : 16); + + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + + // Arguments stored on registers + if (VA.isRegLoc()) { + MVT RegVT = VA.getLocVT(); + TargetRegisterClass *RC = 0; + + if (RegVT == MVT::i32) + RC = Mips::CPURegsRegisterClass; + else if (RegVT == MVT::f32) + RC = Mips::FGR32RegisterClass; + else if (RegVT == MVT::f64) { + if (!Subtarget->isSingleFloat()) + RC = Mips::AFGR64RegisterClass; + } else + assert(0 && "RegVT not supported by FORMAL_ARGUMENTS Lowering"); + + // Transform the arguments stored on + // physical registers into virtual ones + unsigned Reg = AddLiveIn(DAG.getMachineFunction(), VA.getLocReg(), RC); + SDValue ArgValue = DAG.getCopyFromReg(Root, dl, Reg, RegVT); + + // If this is an 8 or 16-bit value, it has been passed promoted + // to 32 bits. Insert an assert[sz]ext to capture this, then + // truncate to the right size. + if (VA.getLocInfo() != CCValAssign::Full) { + unsigned Opcode = 0; + if (VA.getLocInfo() == CCValAssign::SExt) + Opcode = ISD::AssertSext; + else if (VA.getLocInfo() == CCValAssign::ZExt) + Opcode = ISD::AssertZext; + if (Opcode) + ArgValue = DAG.getNode(Opcode, dl, RegVT, ArgValue, + DAG.getValueType(VA.getValVT())); + ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue); + } + + // Handle O32 ABI cases: i32->f32 and (i32,i32)->f64 + if (Subtarget->isABI_O32()) { + if (RegVT == MVT::i32 && VA.getValVT() == MVT::f32) + ArgValue = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::f32, ArgValue); + if (RegVT == MVT::i32 && VA.getValVT() == MVT::f64) { + unsigned Reg2 = AddLiveIn(DAG.getMachineFunction(), + VA.getLocReg()+1, RC); + SDValue ArgValue2 = DAG.getCopyFromReg(Root, dl, Reg2, RegVT); + SDValue Hi = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::f32, ArgValue); + SDValue Lo = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::f32, ArgValue2); + ArgValue = DAG.getNode(ISD::BUILD_PAIR, dl, MVT::f64, Lo, Hi); + } + } + + ArgValues.push_back(ArgValue); + + // To meet ABI, when VARARGS are passed on registers, the registers + // must have their values written to the caller stack frame. + if ((isVarArg) && (Subtarget->isABI_O32())) { + if (StackPtr.getNode() == 0) + StackPtr = DAG.getRegister(StackReg, getPointerTy()); + + // The stack pointer offset is relative to the caller stack frame. + // Since the real stack size is unknown here, a negative SPOffset + // is used so there's a way to adjust these offsets when the stack + // size get known (on EliminateFrameIndex). A dummy SPOffset is + // used instead of a direct negative address (which is recorded to + // be used on emitPrologue) to avoid mis-calc of the first stack + // offset on PEI::calculateFrameObjectOffsets. + // Arguments are always 32-bit. + int FI = MFI->CreateFixedObject(4, 0); + MipsFI->recordStoreVarArgsFI(FI, -(4+(i*4))); + SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy()); + + // emit ISD::STORE whichs stores the + // parameter value to a stack Location + ArgValues.push_back(DAG.getStore(Root, dl, ArgValue, PtrOff, NULL, 0)); + } + + } else { // VA.isRegLoc() + + // sanity check + assert(VA.isMemLoc()); + + // The stack pointer offset is relative to the caller stack frame. + // Since the real stack size is unknown here, a negative SPOffset + // is used so there's a way to adjust these offsets when the stack + // size get known (on EliminateFrameIndex). A dummy SPOffset is + // used instead of a direct negative address (which is recorded to + // be used on emitPrologue) to avoid mis-calc of the first stack + // offset on PEI::calculateFrameObjectOffsets. + // Arguments are always 32-bit. + unsigned ArgSize = VA.getLocVT().getSizeInBits()/8; + int FI = MFI->CreateFixedObject(ArgSize, 0); + MipsFI->recordLoadArgsFI(FI, -(ArgSize+ + (FirstStackArgLoc + VA.getLocMemOffset()))); + + // Create load nodes to retrieve arguments from the stack + SDValue FIN = DAG.getFrameIndex(FI, getPointerTy()); + ArgValues.push_back(DAG.getLoad(VA.getValVT(), dl, Root, FIN, NULL, 0)); + } + } + + // The mips ABIs for returning structs by value requires that we copy + // the sret argument into $v0 for the return. Save the argument into + // a virtual register so that we can access it from the return points. + if (DAG.getMachineFunction().getFunction()->hasStructRetAttr()) { + unsigned Reg = MipsFI->getSRetReturnReg(); + if (!Reg) { + Reg = MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::i32)); + MipsFI->setSRetReturnReg(Reg); + } + SDValue Copy = DAG.getCopyToReg(DAG.getEntryNode(), dl, Reg, ArgValues[0]); + Root = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Copy, Root); + } + + ArgValues.push_back(Root); + + // Return the new list of results. + return DAG.getNode(ISD::MERGE_VALUES, dl, Op.getNode()->getVTList(), + &ArgValues[0], ArgValues.size()).getValue(Op.getResNo()); +} + +//===----------------------------------------------------------------------===// +// Return Value Calling Convention Implementation +//===----------------------------------------------------------------------===// + +SDValue MipsTargetLowering:: +LowerRET(SDValue Op, SelectionDAG &DAG) +{ + // CCValAssign - represent the assignment of + // the return value to a location + SmallVector<CCValAssign, 16> RVLocs; + unsigned CC = DAG.getMachineFunction().getFunction()->getCallingConv(); + bool isVarArg = DAG.getMachineFunction().getFunction()->isVarArg(); + DebugLoc dl = Op.getDebugLoc(); + + // CCState - Info about the registers and stack slot. + CCState CCInfo(CC, isVarArg, getTargetMachine(), RVLocs); + + // Analize return values of ISD::RET + CCInfo.AnalyzeReturn(Op.getNode(), 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().getRegInfo().liveout_empty()) { + for (unsigned i = 0; i != RVLocs.size(); ++i) + if (RVLocs[i].isRegLoc()) + DAG.getMachineFunction().getRegInfo().addLiveOut(RVLocs[i].getLocReg()); + } + + // The chain is always operand #0 + SDValue Chain = Op.getOperand(0); + SDValue 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, dl, VA.getLocReg(), + Op.getOperand(i*2+1), Flag); + + // guarantee that all emitted copies are + // stuck together, avoiding something bad + Flag = Chain.getValue(1); + } + + // The mips ABIs for returning structs by value requires that we copy + // the sret argument into $v0 for the return. We saved the argument into + // a virtual register in the entry block, so now we copy the value out + // and into $v0. + if (DAG.getMachineFunction().getFunction()->hasStructRetAttr()) { + MachineFunction &MF = DAG.getMachineFunction(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + unsigned Reg = MipsFI->getSRetReturnReg(); + + if (!Reg) + assert(0 && "sret virtual register not created in the entry block"); + SDValue Val = DAG.getCopyFromReg(Chain, dl, Reg, getPointerTy()); + + Chain = DAG.getCopyToReg(Chain, dl, Mips::V0, Val, Flag); + Flag = Chain.getValue(1); + } + + // Return on Mips is always a "jr $ra" + if (Flag.getNode()) + return DAG.getNode(MipsISD::Ret, dl, MVT::Other, + Chain, DAG.getRegister(Mips::RA, MVT::i32), Flag); + else // Return Void + return DAG.getNode(MipsISD::Ret, dl, MVT::Other, + Chain, DAG.getRegister(Mips::RA, MVT::i32)); +} + +//===----------------------------------------------------------------------===// +// Mips Inline Assembly Support +//===----------------------------------------------------------------------===// + +/// getConstraintType - Given a constraint letter, return the type of +/// constraint it is for this target. +MipsTargetLowering::ConstraintType MipsTargetLowering:: +getConstraintType(const std::string &Constraint) const +{ + // Mips specific constrainy + // GCC config/mips/constraints.md + // + // 'd' : An address register. Equivalent to r + // unless generating MIPS16 code. + // 'y' : Equivalent to r; retained for + // backwards compatibility. + // 'f' : Floating Point registers. + if (Constraint.size() == 1) { + switch (Constraint[0]) { + default : break; + case 'd': + case 'y': + case 'f': + return C_RegisterClass; + break; + } + } + return TargetLowering::getConstraintType(Constraint); +} + +/// getRegClassForInlineAsmConstraint - Given a constraint letter (e.g. "r"), +/// return a list of registers that can be used to satisfy the constraint. +/// This should only be used for C_RegisterClass constraints. +std::pair<unsigned, const TargetRegisterClass*> MipsTargetLowering:: +getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const +{ + if (Constraint.size() == 1) { + switch (Constraint[0]) { + case 'r': + return std::make_pair(0U, Mips::CPURegsRegisterClass); + case 'f': + if (VT == MVT::f32) + return std::make_pair(0U, Mips::FGR32RegisterClass); + if (VT == MVT::f64) + if ((!Subtarget->isSingleFloat()) && (!Subtarget->isFP64bit())) + return std::make_pair(0U, Mips::AFGR64RegisterClass); + } + } + return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT); +} + +/// Given a register class constraint, like 'r', if this corresponds directly +/// to an LLVM register class, return a register of 0 and the register class +/// pointer. +std::vector<unsigned> MipsTargetLowering:: +getRegClassForInlineAsmConstraint(const std::string &Constraint, + MVT VT) const +{ + if (Constraint.size() != 1) + return std::vector<unsigned>(); + + switch (Constraint[0]) { + default : break; + case 'r': + // GCC Mips Constraint Letters + case 'd': + case 'y': + return make_vector<unsigned>(Mips::T0, Mips::T1, Mips::T2, Mips::T3, + Mips::T4, Mips::T5, Mips::T6, Mips::T7, Mips::S0, Mips::S1, + Mips::S2, Mips::S3, Mips::S4, Mips::S5, Mips::S6, Mips::S7, + Mips::T8, 0); + + case 'f': + if (VT == MVT::f32) { + if (Subtarget->isSingleFloat()) + return make_vector<unsigned>(Mips::F2, Mips::F3, Mips::F4, Mips::F5, + Mips::F6, Mips::F7, Mips::F8, Mips::F9, Mips::F10, Mips::F11, + Mips::F20, Mips::F21, Mips::F22, Mips::F23, Mips::F24, + Mips::F25, Mips::F26, Mips::F27, Mips::F28, Mips::F29, + Mips::F30, Mips::F31, 0); + else + return make_vector<unsigned>(Mips::F2, Mips::F4, Mips::F6, Mips::F8, + Mips::F10, Mips::F20, Mips::F22, Mips::F24, Mips::F26, + Mips::F28, Mips::F30, 0); + } + + if (VT == MVT::f64) + if ((!Subtarget->isSingleFloat()) && (!Subtarget->isFP64bit())) + return make_vector<unsigned>(Mips::D1, Mips::D2, Mips::D3, Mips::D4, + Mips::D5, Mips::D10, Mips::D11, Mips::D12, Mips::D13, + Mips::D14, Mips::D15, 0); + } + return std::vector<unsigned>(); +} + +bool +MipsTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { + // The Mips target isn't yet aware of offsets. + return false; +} diff --git a/lib/Target/Mips/MipsISelLowering.h b/lib/Target/Mips/MipsISelLowering.h new file mode 100644 index 000000000000..55cd6eadd096 --- /dev/null +++ b/lib/Target/Mips/MipsISelLowering.h @@ -0,0 +1,130 @@ +//===-- MipsISelLowering.h - Mips DAG Lowering Interface --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file 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, + + // 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, + + // Handle gp_rel (small data/bss sections) relocation. + GPRel, + + // Conditional Move + CMov, + + // Select CC Pseudo Instruction + SelectCC, + + // Floating Point Select CC Pseudo Instruction + FPSelectCC, + + // Floating Point Branch Conditional + FPBrcond, + + // Floating Point Compare + FPCmp, + + // Floating Point Rounding + FPRound, + + // Return + Ret + }; + } + + //===--------------------------------------------------------------------===// + // TargetLowering Implementation + //===--------------------------------------------------------------------===// + class MipsTargetLowering : public TargetLowering + { + // FrameIndex for return slot. + int ReturnAddrIndex; + public: + + explicit MipsTargetLowering(MipsTargetMachine &TM); + + /// LowerOperation - Provide custom lowering hooks for some operations. + virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG); + + /// getTargetNodeName - This method returns the name of a target specific + // DAG node. + virtual const char *getTargetNodeName(unsigned Opcode) const; + + /// getSetCCResultType - get the ISD::SETCC result ValueType + MVT getSetCCResultType(MVT VT) const; + + private: + // Subtarget Info + const MipsSubtarget *Subtarget; + + // Lower Operand helpers + SDNode *LowerCallResult(SDValue Chain, SDValue InFlag, CallSDNode *TheCall, + unsigned CallingConv, SelectionDAG &DAG); + bool IsGlobalInSmallSection(GlobalValue *GV); + bool IsInSmallSection(unsigned Size); + + // Lower Operand specifics + SDValue LowerANDOR(SDValue Op, SelectionDAG &DAG); + SDValue LowerBRCOND(SDValue Op, SelectionDAG &DAG); + SDValue LowerCALL(SDValue Op, SelectionDAG &DAG); + SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG); + SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG); + SDValue LowerFORMAL_ARGUMENTS(SDValue Op, SelectionDAG &DAG); + SDValue LowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG); + SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG); + SDValue LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG); + SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG); + SDValue LowerRET(SDValue Op, SelectionDAG &DAG); + SDValue LowerSELECT(SDValue Op, SelectionDAG &DAG); + SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG); + + virtual MachineBasicBlock *EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *MBB) const; + + // Inline asm support + ConstraintType getConstraintType(const std::string &Constraint) const; + + std::pair<unsigned, const TargetRegisterClass*> + getRegForInlineAsmConstraint(const std::string &Constraint, + MVT VT) const; + + std::vector<unsigned> + getRegClassForInlineAsmConstraint(const std::string &Constraint, + MVT VT) const; + + virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const; + }; +} + +#endif // MipsISELLOWERING_H diff --git a/lib/Target/Mips/MipsInstrFPU.td b/lib/Target/Mips/MipsInstrFPU.td new file mode 100644 index 000000000000..b6a6d2f5c052 --- /dev/null +++ b/lib/Target/Mips/MipsInstrFPU.td @@ -0,0 +1,304 @@ +//===- MipsInstrFPU.td - Mips FPU Instruction Information -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file 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. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Floating Point Instructions +// ------------------------ +// * 64bit fp: +// - 32 64-bit registers (default mode) +// - 16 even 32-bit registers (32-bit compatible mode) for +// single and double access. +// * 32bit fp: +// - 16 even 32-bit registers - single and double (aliased) +// - 32 32-bit registers (within single-only mode) +//===----------------------------------------------------------------------===// + +// Floating Point Compare and Branch +def SDT_MipsFPBrcond : SDTypeProfile<0, 3, [SDTCisSameAs<0, 2>, SDTCisInt<0>, + SDTCisVT<1, OtherVT>]>; +def SDT_MipsFPCmp : SDTypeProfile<0, 3, [SDTCisSameAs<0, 1>, SDTCisFP<0>, + SDTCisInt<2>]>; +def SDT_MipsFPSelectCC : SDTypeProfile<1, 4, [SDTCisInt<1>, SDTCisInt<4>, + SDTCisSameAs<0, 2>, SDTCisSameAs<2, 3>]>; + +def MipsFPRound : SDNode<"MipsISD::FPRound", SDTFPRoundOp, [SDNPOptInFlag]>; +def MipsFPBrcond : SDNode<"MipsISD::FPBrcond", SDT_MipsFPBrcond, + [SDNPHasChain]>; +def MipsFPCmp : SDNode<"MipsISD::FPCmp", SDT_MipsFPCmp>; +def MipsFPSelectCC : SDNode<"MipsISD::FPSelectCC", SDT_MipsFPSelectCC>; + +// Operand for printing out a condition code. +let PrintMethod = "printFCCOperand" in + def condcode : Operand<i32>; + +//===----------------------------------------------------------------------===// +// Feature predicates. +//===----------------------------------------------------------------------===// + +def In32BitMode : Predicate<"!Subtarget.isFP64bit()">; +def IsSingleFloat : Predicate<"Subtarget.isSingleFloat()">; +def IsNotSingleFloat : Predicate<"!Subtarget.isSingleFloat()">; + +//===----------------------------------------------------------------------===// +// Instruction Class Templates +// +// A set of multiclasses is used to address the register usage. +// +// S32 - single precision in 16 32bit even fp registers +// single precision in 32 32bit fp registers in SingleOnly mode +// S64 - single precision in 32 64bit fp registers (In64BitMode) +// D32 - double precision in 16 32bit even fp registers +// D64 - double precision in 32 64bit fp registers (In64BitMode) +// +// Only S32 and D32 are supported right now. +//===----------------------------------------------------------------------===// + +multiclass FFR1_1<bits<6> funct, string asmstr> +{ + def _S32 : FFR<0x11, funct, 0x0, (outs FGR32:$fd), (ins FGR32:$fs), + !strconcat(asmstr, ".s $fd, $fs"), []>; + + def _D32 : FFR<0x11, funct, 0x1, (outs FGR32:$fd), (ins AFGR64:$fs), + !strconcat(asmstr, ".d $fd, $fs"), []>, Requires<[In32BitMode]>; +} + +multiclass FFR1_2<bits<6> funct, string asmstr, SDNode FOp> +{ + def _S32 : FFR<0x11, funct, 0x0, (outs FGR32:$fd), (ins FGR32:$fs), + !strconcat(asmstr, ".s $fd, $fs"), + [(set FGR32:$fd, (FOp FGR32:$fs))]>; + + def _D32 : FFR<0x11, funct, 0x1, (outs AFGR64:$fd), (ins AFGR64:$fs), + !strconcat(asmstr, ".d $fd, $fs"), + [(set AFGR64:$fd, (FOp AFGR64:$fs))]>, Requires<[In32BitMode]>; +} + +class FFR1_3<bits<6> funct, bits<5> fmt, RegisterClass RcSrc, + RegisterClass RcDst, string asmstr>: + FFR<0x11, funct, fmt, (outs RcSrc:$fd), (ins RcDst:$fs), + !strconcat(asmstr, " $fd, $fs"), []>; + + +multiclass FFR1_4<bits<6> funct, string asmstr, SDNode FOp> { + def _S32 : FFR<0x11, funct, 0x0, (outs FGR32:$fd), + (ins FGR32:$fs, FGR32:$ft), + !strconcat(asmstr, ".s $fd, $fs, $ft"), + [(set FGR32:$fd, (FOp FGR32:$fs, FGR32:$ft))]>; + + def _D32 : FFR<0x11, funct, 0x1, (outs AFGR64:$fd), + (ins AFGR64:$fs, AFGR64:$ft), + !strconcat(asmstr, ".d $fd, $fs, $ft"), + [(set AFGR64:$fd, (FOp AFGR64:$fs, AFGR64:$ft))]>, + Requires<[In32BitMode]>; +} + +//===----------------------------------------------------------------------===// +// Floating Point Instructions +//===----------------------------------------------------------------------===// + +let ft = 0 in { + defm FLOOR_W : FFR1_1<0b001111, "floor.w">; + defm CEIL_W : FFR1_1<0b001110, "ceil.w">; + defm ROUND_W : FFR1_1<0b001100, "round.w">; + defm TRUNC_W : FFR1_1<0b001101, "trunc.w">; + defm CVTW : FFR1_1<0b100100, "cvt.w">; + defm FMOV : FFR1_1<0b000110, "mov">; + + defm FABS : FFR1_2<0b000101, "abs", fabs>; + defm FNEG : FFR1_2<0b000111, "neg", fneg>; + defm FSQRT : FFR1_2<0b000100, "sqrt", fsqrt>; + + /// Convert to Single Precison + def CVTS_W32 : FFR1_3<0b100000, 0x2, FGR32, FGR32, "cvt.s.w">; + + let Predicates = [IsNotSingleFloat] in { + /// Ceil to long signed integer + def CEIL_LS : FFR1_3<0b001010, 0x0, FGR32, FGR32, "ceil.l">; + def CEIL_LD : FFR1_3<0b001010, 0x1, AFGR64, AFGR64, "ceil.l">; + + /// Round to long signed integer + def ROUND_LS : FFR1_3<0b001000, 0x0, FGR32, FGR32, "round.l">; + def ROUND_LD : FFR1_3<0b001000, 0x1, AFGR64, AFGR64, "round.l">; + + /// Floor to long signed integer + def FLOOR_LS : FFR1_3<0b001011, 0x0, FGR32, FGR32, "floor.l">; + def FLOOR_LD : FFR1_3<0b001011, 0x1, AFGR64, AFGR64, "floor.l">; + + /// Trunc to long signed integer + def TRUNC_LS : FFR1_3<0b001001, 0x0, FGR32, FGR32, "trunc.l">; + def TRUNC_LD : FFR1_3<0b001001, 0x1, AFGR64, AFGR64, "trunc.l">; + + /// Convert to long signed integer + def CVTL_S : FFR1_3<0b100101, 0x0, FGR32, FGR32, "cvt.l">; + def CVTL_D : FFR1_3<0b100101, 0x1, AFGR64, AFGR64, "cvt.l">; + + /// Convert to Double Precison + def CVTD_S32 : FFR1_3<0b100001, 0x0, AFGR64, FGR32, "cvt.d.s">; + def CVTD_W32 : FFR1_3<0b100001, 0x2, AFGR64, FGR32, "cvt.d.w">; + def CVTD_L32 : FFR1_3<0b100001, 0x3, AFGR64, AFGR64, "cvt.d.l">; + + /// Convert to Single Precison + def CVTS_D32 : FFR1_3<0b100000, 0x1, FGR32, AFGR64, "cvt.s.d">; + def CVTS_L32 : FFR1_3<0b100000, 0x3, FGR32, AFGR64, "cvt.s.l">; + } +} + +// The odd-numbered registers are only referenced when doing loads, +// stores, and moves between floating-point and integer registers. +// When defining instructions, we reference all 32-bit registers, +// regardless of register aliasing. +let fd = 0 in { + /// Move Control Registers From/To CPU Registers + def CFC1 : FFR<0x11, 0x0, 0x2, (outs CPURegs:$rt), (ins CCR:$fs), + "cfc1 $rt, $fs", []>; + + def CTC1 : FFR<0x11, 0x0, 0x6, (outs CCR:$rt), (ins CPURegs:$fs), + "ctc1 $fs, $rt", []>; + + def MFC1 : FFR<0x11, 0x00, 0x00, (outs CPURegs:$rt), (ins FGR32:$fs), + "mfc1 $rt, $fs", []>; + + def MTC1 : FFR<0x11, 0x00, 0x04, (outs FGR32:$fs), (ins CPURegs:$rt), + "mtc1 $rt, $fs", []>; +} + +/// Floating Point Memory Instructions +let Predicates = [IsNotSingleFloat] in { + def LDC1 : FFI<0b110101, (outs AFGR64:$ft), (ins mem:$addr), + "ldc1 $ft, $addr", [(set AFGR64:$ft, (load addr:$addr))]>; + + def SDC1 : FFI<0b111101, (outs), (ins AFGR64:$ft, mem:$addr), + "sdc1 $ft, $addr", [(store AFGR64:$ft, addr:$addr)]>; +} + +// LWC1 and SWC1 can always be emited with odd registers. +def LWC1 : FFI<0b110001, (outs FGR32:$ft), (ins mem:$addr), "lwc1 $ft, $addr", + [(set FGR32:$ft, (load addr:$addr))]>; +def SWC1 : FFI<0b111001, (outs), (ins FGR32:$ft, mem:$addr), "swc1 $ft, $addr", + [(store FGR32:$ft, addr:$addr)]>; + +/// Floating-point Aritmetic +defm FADD : FFR1_4<0x10, "add", fadd>; +defm FDIV : FFR1_4<0x03, "div", fdiv>; +defm FMUL : FFR1_4<0x02, "mul", fmul>; +defm FSUB : FFR1_4<0x01, "sub", fsub>; + +//===----------------------------------------------------------------------===// +// Floating Point Branch Codes +//===----------------------------------------------------------------------===// +// Mips branch codes. These correspond to condcode in MipsInstrInfo.h. +// They must be kept in synch. +def MIPS_BRANCH_F : PatLeaf<(i32 0)>; +def MIPS_BRANCH_T : PatLeaf<(i32 1)>; +def MIPS_BRANCH_FL : PatLeaf<(i32 2)>; +def MIPS_BRANCH_TL : PatLeaf<(i32 3)>; + +/// Floating Point Branch of False/True (Likely) +let isBranch=1, isTerminator=1, hasDelaySlot=1, base=0x8, Uses=[FCR31] in { + class FBRANCH<PatLeaf op, string asmstr> : FFI<0x11, (outs), + (ins brtarget:$dst), !strconcat(asmstr, " $dst"), + [(MipsFPBrcond op, bb:$dst, FCR31)]>; +} +def BC1F : FBRANCH<MIPS_BRANCH_F, "bc1f">; +def BC1T : FBRANCH<MIPS_BRANCH_T, "bc1t">; +def BC1FL : FBRANCH<MIPS_BRANCH_FL, "bc1fl">; +def BC1TL : FBRANCH<MIPS_BRANCH_TL, "bc1tl">; + +//===----------------------------------------------------------------------===// +// Floating Point Flag Conditions +//===----------------------------------------------------------------------===// +// Mips condition codes. They must correspond to condcode in MipsInstrInfo.h. +// They must be kept in synch. +def MIPS_FCOND_F : PatLeaf<(i32 0)>; +def MIPS_FCOND_UN : PatLeaf<(i32 1)>; +def MIPS_FCOND_EQ : PatLeaf<(i32 2)>; +def MIPS_FCOND_UEQ : PatLeaf<(i32 3)>; +def MIPS_FCOND_OLT : PatLeaf<(i32 4)>; +def MIPS_FCOND_ULT : PatLeaf<(i32 5)>; +def MIPS_FCOND_OLE : PatLeaf<(i32 6)>; +def MIPS_FCOND_ULE : PatLeaf<(i32 7)>; +def MIPS_FCOND_SF : PatLeaf<(i32 8)>; +def MIPS_FCOND_NGLE : PatLeaf<(i32 9)>; +def MIPS_FCOND_SEQ : PatLeaf<(i32 10)>; +def MIPS_FCOND_NGL : PatLeaf<(i32 11)>; +def MIPS_FCOND_LT : PatLeaf<(i32 12)>; +def MIPS_FCOND_NGE : PatLeaf<(i32 13)>; +def MIPS_FCOND_LE : PatLeaf<(i32 14)>; +def MIPS_FCOND_NGT : PatLeaf<(i32 15)>; + +/// Floating Point Compare +let hasDelaySlot = 1, Defs=[FCR31] in { + def FCMP_S32 : FCC<0x0, (outs), (ins FGR32:$fs, FGR32:$ft, condcode:$cc), + "c.$cc.s $fs, $ft", [(MipsFPCmp FGR32:$fs, FGR32:$ft, imm:$cc), + (implicit FCR31)]>; + + def FCMP_D32 : FCC<0x1, (outs), (ins AFGR64:$fs, AFGR64:$ft, condcode:$cc), + "c.$cc.d $fs, $ft", [(MipsFPCmp AFGR64:$fs, AFGR64:$ft, imm:$cc), + (implicit FCR31)]>, Requires<[In32BitMode]>; +} + +//===----------------------------------------------------------------------===// +// Floating Point Pseudo-Instructions +//===----------------------------------------------------------------------===// + +// For some explanation, see Select_CC at MipsInstrInfo.td. We also embedd a +// condiciton code to enable easy handling by the Custom Inserter. +let usesCustomDAGSchedInserter = 1, Uses=[FCR31] in { + class PseudoFPSelCC<RegisterClass RC, string asmstr> : + MipsPseudo<(outs RC:$dst), + (ins CPURegs:$CmpRes, RC:$T, RC:$F, condcode:$cc), asmstr, + [(set RC:$dst, (MipsFPSelectCC CPURegs:$CmpRes, RC:$T, RC:$F, + imm:$cc))]>; +} + +// The values to be selected are fp but the condition test is with integers. +def Select_CC_S32 : PseudoSelCC<FGR32, "# MipsSelect_CC_S32_f32">; +def Select_CC_D32 : PseudoSelCC<AFGR64, "# MipsSelect_CC_D32_f32">, + Requires<[In32BitMode]>; + +// The values to be selected are int but the condition test is done with fp. +def Select_FCC : PseudoFPSelCC<CPURegs, "# MipsSelect_FCC">; + +// The values to be selected and the condition test is done with fp. +def Select_FCC_S32 : PseudoFPSelCC<FGR32, "# MipsSelect_FCC_S32_f32">; +def Select_FCC_D32 : PseudoFPSelCC<AFGR64, "# MipsSelect_FCC_D32_f32">, + Requires<[In32BitMode]>; + +def MOVCCRToCCR : MipsPseudo<(outs CCR:$dst), (ins CCR:$src), + "# MOVCCRToCCR", []>; + +//===----------------------------------------------------------------------===// +// Floating Point Patterns +//===----------------------------------------------------------------------===// +def fpimm0 : PatLeaf<(fpimm), [{ + return N->isExactlyValue(+0.0); +}]>; + +def : Pat<(f32 fpimm0), (MTC1 ZERO)>; + +def : Pat<(f32 (sint_to_fp CPURegs:$src)), (CVTS_W32 (MTC1 CPURegs:$src))>; +def : Pat<(f64 (sint_to_fp CPURegs:$src)), (CVTD_W32 (MTC1 CPURegs:$src))>; + +def : Pat<(i32 (fp_to_sint FGR32:$src)), (MFC1 (TRUNC_W_S32 FGR32:$src))>; + +def : Pat<(i32 (bitconvert FGR32:$src)), (MFC1 FGR32:$src)>; +def : Pat<(f32 (bitconvert CPURegs:$src)), (MTC1 CPURegs:$src)>; + +let Predicates = [In32BitMode] in { + def : Pat<(f32 (fround AFGR64:$src)), (CVTS_D32 AFGR64:$src)>; + def : Pat<(f64 (fextend FGR32:$src)), (CVTD_S32 FGR32:$src)>; +} + +// MipsFPRound is only emitted for MipsI targets. +def : Pat<(f32 (MipsFPRound AFGR64:$src)), (CVTW_D32 AFGR64:$src)>; + diff --git a/lib/Target/Mips/MipsInstrFormats.td b/lib/Target/Mips/MipsInstrFormats.td new file mode 100644 index 000000000000..0853272f7280 --- /dev/null +++ b/lib/Target/Mips/MipsInstrFormats.td @@ -0,0 +1,182 @@ +//===- MipsRegisterInfo.td - Mips Register defs -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Describe MIPS instructions format +// +// CPU INSTRUCTION FORMATS +// +// 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<dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin>: Instruction +{ + field bits<32> Inst; + + let Namespace = "Mips"; + + bits<6> opcode; + + // Top 5 bits are the 'opcode' field + let Inst{31-26} = opcode; + + dag OutOperandList = outs; + dag InOperandList = ins; + + let AsmString = asmstr; + let Pattern = pattern; + let Itinerary = itin; +} + +// Mips Pseudo Instructions Format +class MipsPseudo<dag outs, dag ins, string asmstr, list<dag> pattern>: + MipsInst<outs, ins, asmstr, pattern, IIPseudo>; + +//===----------------------------------------------------------------------===// +// Format R instruction class in Mips : <|opcode|rs|rt|rd|shamt|funct|> +//===----------------------------------------------------------------------===// + +class FR<bits<6> op, bits<6> _funct, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst<outs, ins, asmstr, pattern, itin> +{ + 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<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin>: MipsInst<outs, ins, asmstr, pattern, itin> +{ + 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<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin>: MipsInst<outs, ins, asmstr, pattern, itin> +{ + bits<26> addr; + + let opcode = op; + + let Inst{25-0} = addr; +} + +//===----------------------------------------------------------------------===// +// +// FLOATING POINT INSTRUCTION FORMATS +// +// opcode - operation code. +// fs - src reg. +// ft - dst reg (on a 2 regs instr) or src reg (on a 3 reg instr). +// fd - dst reg, only used on 3 regs instr. +// fmt - double or single precision. +// funct - combined with opcode field give us an operation code. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Format FR instruction class in Mips : <|opcode|fmt|ft|fs|fd|funct|> +//===----------------------------------------------------------------------===// + +class FFR<bits<6> op, bits<6> _funct, bits<5> _fmt, dag outs, dag ins, + string asmstr, list<dag> pattern> : + MipsInst<outs, ins, asmstr, pattern, NoItinerary> +{ + bits<5> fd; + bits<5> fs; + bits<5> ft; + bits<5> fmt; + bits<6> funct; + + let opcode = op; + let funct = _funct; + let fmt = _fmt; + + let Inst{25-21} = fmt; + let Inst{20-16} = ft; + let Inst{15-11} = fs; + let Inst{10-6} = fd; + let Inst{5-0} = funct; +} + +//===----------------------------------------------------------------------===// +// Format FI instruction class in Mips : <|opcode|base|ft|immediate|> +//===----------------------------------------------------------------------===// + +class FFI<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern>: + MipsInst<outs, ins, asmstr, pattern, NoItinerary> +{ + bits<5> ft; + bits<5> base; + bits<16> imm16; + + let opcode = op; + + let Inst{25-21} = base; + let Inst{20-16} = ft; + let Inst{15-0} = imm16; +} + +//===----------------------------------------------------------------------===// +// Compare instruction class in Mips : <|010001|fmt|ft|fs|0000011|condcode|> +//===----------------------------------------------------------------------===// + +class FCC<bits<5> _fmt, dag outs, dag ins, string asmstr, list<dag> pattern> : + MipsInst<outs, ins, asmstr, pattern, NoItinerary> +{ + bits<5> fs; + bits<5> ft; + bits<4> cc; + bits<5> fmt; + + let opcode = 0x11; + let fmt = _fmt; + + let Inst{25-21} = fmt; + let Inst{20-16} = ft; + let Inst{15-11} = fs; + let Inst{10-6} = 0; + let Inst{5-4} = 0b11; + let Inst{3-0} = cc; +} diff --git a/lib/Target/Mips/MipsInstrInfo.cpp b/lib/Target/Mips/MipsInstrInfo.cpp new file mode 100644 index 000000000000..6225fa9c9884 --- /dev/null +++ b/lib/Target/Mips/MipsInstrInfo.cpp @@ -0,0 +1,623 @@ +//===- MipsInstrInfo.cpp - Mips Instruction Information ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file 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 "MipsInstrInfo.h" +#include "MipsTargetMachine.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "MipsGenInstrInfo.inc" + +using namespace llvm; + +MipsInstrInfo::MipsInstrInfo(MipsTargetMachine &tm) + : TargetInstrInfoImpl(MipsInsts, array_lengthof(MipsInsts)), + TM(tm), RI(*TM.getSubtargetImpl(), *this) {} + +static bool isZeroImm(const MachineOperand &op) { + return op.isImm() && op.getImm() == 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, + unsigned &SrcSubIdx, unsigned &DstSubIdx) const +{ + SrcSubIdx = DstSubIdx = 0; // No sub-registers. + + // 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; + } + } + + // mov $fpDst, $fpSrc + // mfc $gpDst, $fpSrc + // mtc $fpDst, $gpSrc + if (MI.getOpcode() == Mips::FMOV_S32 || + MI.getOpcode() == Mips::FMOV_D32 || + MI.getOpcode() == Mips::MFC1 || + MI.getOpcode() == Mips::MTC1 || + MI.getOpcode() == Mips::MOVCCRToCCR) { + 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).isReg()) && (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(const MachineInstr *MI, int &FrameIndex) const +{ + if ((MI->getOpcode() == Mips::LW) || (MI->getOpcode() == Mips::LWC1) || + (MI->getOpcode() == Mips::LDC1)) { + if ((MI->getOperand(2).isFI()) && // is a stack slot + (MI->getOperand(1).isImm()) && // the imm is zero + (isZeroImm(MI->getOperand(1)))) { + FrameIndex = MI->getOperand(2).getIndex(); + 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(const MachineInstr *MI, int &FrameIndex) const +{ + if ((MI->getOpcode() == Mips::SW) || (MI->getOpcode() == Mips::SWC1) || + (MI->getOpcode() == Mips::SDC1)) { + if ((MI->getOperand(2).isFI()) && // is a stack slot + (MI->getOperand(1).isImm()) && // the imm is zero + (isZeroImm(MI->getOperand(1)))) { + FrameIndex = MI->getOperand(2).getIndex(); + return MI->getOperand(0).getReg(); + } + } + return 0; +} + +/// insertNoop - If data hazard condition is found insert the target nop +/// instruction. +void MipsInstrInfo:: +insertNoop(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const +{ + DebugLoc DL = DebugLoc::getUnknownLoc(); + if (MI != MBB.end()) DL = MI->getDebugLoc(); + BuildMI(MBB, MI, DL, get(Mips::NOP)); +} + +bool MipsInstrInfo:: +copyRegToReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned DestReg, unsigned SrcReg, + const TargetRegisterClass *DestRC, + const TargetRegisterClass *SrcRC) const { + DebugLoc DL = DebugLoc::getUnknownLoc(); + if (I != MBB.end()) DL = I->getDebugLoc(); + + if (DestRC != SrcRC) { + + // Copy to/from FCR31 condition register + if ((DestRC == Mips::CPURegsRegisterClass) && + (SrcRC == Mips::CCRRegisterClass)) + BuildMI(MBB, I, DL, get(Mips::CFC1), DestReg).addReg(SrcReg); + else if ((DestRC == Mips::CCRRegisterClass) && + (SrcRC == Mips::CPURegsRegisterClass)) + BuildMI(MBB, I, DL, get(Mips::CTC1), DestReg).addReg(SrcReg); + + // Moves between coprocessors and cpu + else if ((DestRC == Mips::CPURegsRegisterClass) && + (SrcRC == Mips::FGR32RegisterClass)) + BuildMI(MBB, I, DL, get(Mips::MFC1), DestReg).addReg(SrcReg); + else if ((DestRC == Mips::FGR32RegisterClass) && + (SrcRC == Mips::CPURegsRegisterClass)) + BuildMI(MBB, I, DL, get(Mips::MTC1), DestReg).addReg(SrcReg); + + // Move from/to Hi/Lo registers + else if ((DestRC == Mips::HILORegisterClass) && + (SrcRC == Mips::CPURegsRegisterClass)) { + unsigned Opc = (DestReg == Mips::HI) ? Mips::MTHI : Mips::MTLO; + BuildMI(MBB, I, DL, get(Opc), DestReg); + } else if ((SrcRC == Mips::HILORegisterClass) && + (DestRC == Mips::CPURegsRegisterClass)) { + unsigned Opc = (SrcReg == Mips::HI) ? Mips::MFHI : Mips::MFLO; + BuildMI(MBB, I, DL, get(Opc), DestReg); + + // Can't copy this register + } else + return false; + + return true; + } + + if (DestRC == Mips::CPURegsRegisterClass) + BuildMI(MBB, I, DL, get(Mips::ADDu), DestReg).addReg(Mips::ZERO) + .addReg(SrcReg); + else if (DestRC == Mips::FGR32RegisterClass) + BuildMI(MBB, I, DL, get(Mips::FMOV_S32), DestReg).addReg(SrcReg); + else if (DestRC == Mips::AFGR64RegisterClass) + BuildMI(MBB, I, DL, get(Mips::FMOV_D32), DestReg).addReg(SrcReg); + else if (DestRC == Mips::CCRRegisterClass) + BuildMI(MBB, I, DL, get(Mips::MOVCCRToCCR), DestReg).addReg(SrcReg); + else + // Can't copy this register + return false; + + return true; +} + +void MipsInstrInfo:: +storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned SrcReg, bool isKill, int FI, + const TargetRegisterClass *RC) const { + unsigned Opc; + + DebugLoc DL = DebugLoc::getUnknownLoc(); + if (I != MBB.end()) DL = I->getDebugLoc(); + + if (RC == Mips::CPURegsRegisterClass) + Opc = Mips::SW; + else if (RC == Mips::FGR32RegisterClass) + Opc = Mips::SWC1; + else { + assert(RC == Mips::AFGR64RegisterClass); + Opc = Mips::SDC1; + } + + BuildMI(MBB, I, DL, get(Opc)).addReg(SrcReg, getKillRegState(isKill)) + .addImm(0).addFrameIndex(FI); +} + +void MipsInstrInfo::storeRegToAddr(MachineFunction &MF, unsigned SrcReg, + bool isKill, SmallVectorImpl<MachineOperand> &Addr, + const TargetRegisterClass *RC, SmallVectorImpl<MachineInstr*> &NewMIs) const +{ + unsigned Opc; + if (RC == Mips::CPURegsRegisterClass) + Opc = Mips::SW; + else if (RC == Mips::FGR32RegisterClass) + Opc = Mips::SWC1; + else { + assert(RC == Mips::AFGR64RegisterClass); + Opc = Mips::SDC1; + } + + DebugLoc DL = DebugLoc::getUnknownLoc(); + MachineInstrBuilder MIB = BuildMI(MF, DL, get(Opc)) + .addReg(SrcReg, getKillRegState(isKill)); + for (unsigned i = 0, e = Addr.size(); i != e; ++i) + MIB.addOperand(Addr[i]); + NewMIs.push_back(MIB); + return; +} + +void MipsInstrInfo:: +loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned DestReg, int FI, + const TargetRegisterClass *RC) const +{ + unsigned Opc; + if (RC == Mips::CPURegsRegisterClass) + Opc = Mips::LW; + else if (RC == Mips::FGR32RegisterClass) + Opc = Mips::LWC1; + else { + assert(RC == Mips::AFGR64RegisterClass); + Opc = Mips::LDC1; + } + + DebugLoc DL = DebugLoc::getUnknownLoc(); + if (I != MBB.end()) DL = I->getDebugLoc(); + BuildMI(MBB, I, DL, get(Opc), DestReg).addImm(0).addFrameIndex(FI); +} + +void MipsInstrInfo::loadRegFromAddr(MachineFunction &MF, unsigned DestReg, + SmallVectorImpl<MachineOperand> &Addr, + const TargetRegisterClass *RC, + SmallVectorImpl<MachineInstr*> &NewMIs) const { + unsigned Opc; + if (RC == Mips::CPURegsRegisterClass) + Opc = Mips::LW; + else if (RC == Mips::FGR32RegisterClass) + Opc = Mips::LWC1; + else { + assert(RC == Mips::AFGR64RegisterClass); + Opc = Mips::LDC1; + } + + DebugLoc DL = DebugLoc::getUnknownLoc(); + MachineInstrBuilder MIB = BuildMI(MF, DL, get(Opc), DestReg); + for (unsigned i = 0, e = Addr.size(); i != e; ++i) + MIB.addOperand(Addr[i]); + NewMIs.push_back(MIB); + return; +} + +MachineInstr *MipsInstrInfo:: +foldMemoryOperandImpl(MachineFunction &MF, + MachineInstr* MI, + const SmallVectorImpl<unsigned> &Ops, int FI) const +{ + if (Ops.size() != 1) return NULL; + + MachineInstr *NewMI = NULL; + + switch (MI->getOpcode()) { + case Mips::ADDu: + if ((MI->getOperand(0).isReg()) && + (MI->getOperand(1).isReg()) && + (MI->getOperand(1).getReg() == Mips::ZERO) && + (MI->getOperand(2).isReg())) { + if (Ops[0] == 0) { // COPY -> STORE + unsigned SrcReg = MI->getOperand(2).getReg(); + bool isKill = MI->getOperand(2).isKill(); + NewMI = BuildMI(MF, MI->getDebugLoc(), get(Mips::SW)) + .addReg(SrcReg, getKillRegState(isKill)) + .addImm(0).addFrameIndex(FI); + } else { // COPY -> LOAD + unsigned DstReg = MI->getOperand(0).getReg(); + bool isDead = MI->getOperand(0).isDead(); + NewMI = BuildMI(MF, MI->getDebugLoc(), get(Mips::LW)) + .addReg(DstReg, RegState::Define | getDeadRegState(isDead)) + .addImm(0).addFrameIndex(FI); + } + } + break; + case Mips::FMOV_S32: + case Mips::FMOV_D32: + if ((MI->getOperand(0).isReg()) && + (MI->getOperand(1).isReg())) { + const TargetRegisterClass + *RC = RI.getRegClass(MI->getOperand(0).getReg()); + unsigned StoreOpc, LoadOpc; + + if (RC == Mips::FGR32RegisterClass) { + LoadOpc = Mips::LWC1; StoreOpc = Mips::SWC1; + } else { + assert(RC == Mips::AFGR64RegisterClass); + LoadOpc = Mips::LDC1; StoreOpc = Mips::SDC1; + } + + if (Ops[0] == 0) { // COPY -> STORE + unsigned SrcReg = MI->getOperand(1).getReg(); + bool isKill = MI->getOperand(1).isKill(); + NewMI = BuildMI(MF, MI->getDebugLoc(), get(StoreOpc)) + .addReg(SrcReg, getKillRegState(isKill)) + .addImm(0).addFrameIndex(FI) ; + } else { // COPY -> LOAD + unsigned DstReg = MI->getOperand(0).getReg(); + bool isDead = MI->getOperand(0).isDead(); + NewMI = BuildMI(MF, MI->getDebugLoc(), get(LoadOpc)) + .addReg(DstReg, RegState::Define | getDeadRegState(isDead)) + .addImm(0).addFrameIndex(FI); + } + } + break; + } + + return NewMI; +} + +//===----------------------------------------------------------------------===// +// Branch Analysis +//===----------------------------------------------------------------------===// + +/// GetCondFromBranchOpc - Return the Mips CC that matches +/// the correspondent Branch instruction opcode. +static Mips::CondCode GetCondFromBranchOpc(unsigned BrOpc) +{ + switch (BrOpc) { + default: return Mips::COND_INVALID; + case Mips::BEQ : return Mips::COND_E; + case Mips::BNE : return Mips::COND_NE; + case Mips::BGTZ : return Mips::COND_GZ; + case Mips::BGEZ : return Mips::COND_GEZ; + case Mips::BLTZ : return Mips::COND_LZ; + case Mips::BLEZ : return Mips::COND_LEZ; + + // We dont do fp branch analysis yet! + case Mips::BC1T : + case Mips::BC1F : return Mips::COND_INVALID; + } +} + +/// GetCondBranchFromCond - Return the Branch instruction +/// opcode that matches the cc. +unsigned Mips::GetCondBranchFromCond(Mips::CondCode CC) +{ + switch (CC) { + default: assert(0 && "Illegal condition code!"); + case Mips::COND_E : return Mips::BEQ; + case Mips::COND_NE : return Mips::BNE; + case Mips::COND_GZ : return Mips::BGTZ; + case Mips::COND_GEZ : return Mips::BGEZ; + case Mips::COND_LZ : return Mips::BLTZ; + case Mips::COND_LEZ : return Mips::BLEZ; + + case Mips::FCOND_F: + case Mips::FCOND_UN: + case Mips::FCOND_EQ: + case Mips::FCOND_UEQ: + case Mips::FCOND_OLT: + case Mips::FCOND_ULT: + case Mips::FCOND_OLE: + case Mips::FCOND_ULE: + case Mips::FCOND_SF: + case Mips::FCOND_NGLE: + case Mips::FCOND_SEQ: + case Mips::FCOND_NGL: + case Mips::FCOND_LT: + case Mips::FCOND_NGE: + case Mips::FCOND_LE: + case Mips::FCOND_NGT: return Mips::BC1T; + + case Mips::FCOND_T: + case Mips::FCOND_OR: + case Mips::FCOND_NEQ: + case Mips::FCOND_OGL: + case Mips::FCOND_UGE: + case Mips::FCOND_OGE: + case Mips::FCOND_UGT: + case Mips::FCOND_OGT: + case Mips::FCOND_ST: + case Mips::FCOND_GLE: + case Mips::FCOND_SNE: + case Mips::FCOND_GL: + case Mips::FCOND_NLT: + case Mips::FCOND_GE: + case Mips::FCOND_NLE: + case Mips::FCOND_GT: return Mips::BC1F; + } +} + +/// GetOppositeBranchCondition - Return the inverse of the specified +/// condition, e.g. turning COND_E to COND_NE. +Mips::CondCode Mips::GetOppositeBranchCondition(Mips::CondCode CC) +{ + switch (CC) { + default: assert(0 && "Illegal condition code!"); + case Mips::COND_E : return Mips::COND_NE; + case Mips::COND_NE : return Mips::COND_E; + case Mips::COND_GZ : return Mips::COND_LEZ; + case Mips::COND_GEZ : return Mips::COND_LZ; + case Mips::COND_LZ : return Mips::COND_GEZ; + case Mips::COND_LEZ : return Mips::COND_GZ; + case Mips::FCOND_F : return Mips::FCOND_T; + case Mips::FCOND_UN : return Mips::FCOND_OR; + case Mips::FCOND_EQ : return Mips::FCOND_NEQ; + case Mips::FCOND_UEQ: return Mips::FCOND_OGL; + case Mips::FCOND_OLT: return Mips::FCOND_UGE; + case Mips::FCOND_ULT: return Mips::FCOND_OGE; + case Mips::FCOND_OLE: return Mips::FCOND_UGT; + case Mips::FCOND_ULE: return Mips::FCOND_OGT; + case Mips::FCOND_SF: return Mips::FCOND_ST; + case Mips::FCOND_NGLE:return Mips::FCOND_GLE; + case Mips::FCOND_SEQ: return Mips::FCOND_SNE; + case Mips::FCOND_NGL: return Mips::FCOND_GL; + case Mips::FCOND_LT: return Mips::FCOND_NLT; + case Mips::FCOND_NGE: return Mips::FCOND_GE; + case Mips::FCOND_LE: return Mips::FCOND_NLE; + case Mips::FCOND_NGT: return Mips::FCOND_GT; + } +} + +bool MipsInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const +{ + // If the block has no terminators, it just falls into the block after it. + MachineBasicBlock::iterator I = MBB.end(); + if (I == MBB.begin() || !isUnpredicatedTerminator(--I)) + return false; + + // Get the last instruction in the block. + MachineInstr *LastInst = I; + + // If there is only one terminator instruction, process it. + unsigned LastOpc = LastInst->getOpcode(); + if (I == MBB.begin() || !isUnpredicatedTerminator(--I)) { + if (!LastInst->getDesc().isBranch()) + return true; + + // Unconditional branch + if (LastOpc == Mips::J) { + TBB = LastInst->getOperand(0).getMBB(); + return false; + } + + Mips::CondCode BranchCode = GetCondFromBranchOpc(LastInst->getOpcode()); + if (BranchCode == Mips::COND_INVALID) + return true; // Can't handle indirect branch. + + // Conditional branch + // Block ends with fall-through condbranch. + if (LastOpc != Mips::COND_INVALID) { + int LastNumOp = LastInst->getNumOperands(); + + TBB = LastInst->getOperand(LastNumOp-1).getMBB(); + Cond.push_back(MachineOperand::CreateImm(BranchCode)); + + for (int i=0; i<LastNumOp-1; i++) { + Cond.push_back(LastInst->getOperand(i)); + } + + return false; + } + } + + // Get the instruction before it if it is a terminator. + MachineInstr *SecondLastInst = I; + + // If there are three terminators, we don't know what sort of block this is. + if (SecondLastInst && I != MBB.begin() && isUnpredicatedTerminator(--I)) + return true; + + // If the block ends with Mips::J and a Mips::BNE/Mips::BEQ, handle it. + unsigned SecondLastOpc = SecondLastInst->getOpcode(); + Mips::CondCode BranchCode = GetCondFromBranchOpc(SecondLastOpc); + + if (BranchCode != Mips::COND_INVALID && LastOpc == Mips::J) { + int SecondNumOp = SecondLastInst->getNumOperands(); + + TBB = SecondLastInst->getOperand(SecondNumOp-1).getMBB(); + Cond.push_back(MachineOperand::CreateImm(BranchCode)); + + for (int i=0; i<SecondNumOp-1; i++) { + Cond.push_back(SecondLastInst->getOperand(i)); + } + + FBB = LastInst->getOperand(0).getMBB(); + return false; + } + + // If the block ends with two unconditional branches, handle it. The last + // one is not executed, so remove it. + if ((SecondLastOpc == Mips::J) && (LastOpc == Mips::J)) { + TBB = SecondLastInst->getOperand(0).getMBB(); + I = LastInst; + if (AllowModify) + I->eraseFromParent(); + return false; + } + + // Otherwise, can't handle this. + return true; +} + +unsigned MipsInstrInfo:: +InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond) const { + // FIXME this should probably have a DebugLoc argument + DebugLoc dl = DebugLoc::getUnknownLoc(); + // Shouldn't be a fall through. + assert(TBB && "InsertBranch must not be told to insert a fallthrough"); + assert((Cond.size() == 3 || Cond.size() == 2 || Cond.size() == 0) && + "Mips branch conditions can have two|three components!"); + + if (FBB == 0) { // One way branch. + if (Cond.empty()) { + // Unconditional branch? + BuildMI(&MBB, dl, get(Mips::J)).addMBB(TBB); + } else { + // Conditional branch. + unsigned Opc = GetCondBranchFromCond((Mips::CondCode)Cond[0].getImm()); + const TargetInstrDesc &TID = get(Opc); + + if (TID.getNumOperands() == 3) + BuildMI(&MBB, dl, TID).addReg(Cond[1].getReg()) + .addReg(Cond[2].getReg()) + .addMBB(TBB); + else + BuildMI(&MBB, dl, TID).addReg(Cond[1].getReg()) + .addMBB(TBB); + + } + return 1; + } + + // Two-way Conditional branch. + unsigned Opc = GetCondBranchFromCond((Mips::CondCode)Cond[0].getImm()); + const TargetInstrDesc &TID = get(Opc); + + if (TID.getNumOperands() == 3) + BuildMI(&MBB, dl, TID).addReg(Cond[1].getReg()).addReg(Cond[2].getReg()) + .addMBB(TBB); + else + BuildMI(&MBB, dl, TID).addReg(Cond[1].getReg()).addMBB(TBB); + + BuildMI(&MBB, dl, get(Mips::J)).addMBB(FBB); + return 2; +} + +unsigned MipsInstrInfo:: +RemoveBranch(MachineBasicBlock &MBB) const +{ + MachineBasicBlock::iterator I = MBB.end(); + if (I == MBB.begin()) return 0; + --I; + if (I->getOpcode() != Mips::J && + GetCondFromBranchOpc(I->getOpcode()) == Mips::COND_INVALID) + return 0; + + // Remove the branch. + I->eraseFromParent(); + + I = MBB.end(); + + if (I == MBB.begin()) return 1; + --I; + if (GetCondFromBranchOpc(I->getOpcode()) == Mips::COND_INVALID) + return 1; + + // Remove the branch. + I->eraseFromParent(); + return 2; +} + +/// BlockHasNoFallThrough - Analyze if MachineBasicBlock does not +/// fall-through into its successor block. +bool MipsInstrInfo:: +BlockHasNoFallThrough(const MachineBasicBlock &MBB) const +{ + if (MBB.empty()) return false; + + switch (MBB.back().getOpcode()) { + case Mips::RET: // Return. + case Mips::JR: // Indirect branch. + case Mips::J: // Uncond branch. + return true; + default: return false; + } +} + +/// ReverseBranchCondition - Return the inverse opcode of the +/// specified Branch instruction. +bool MipsInstrInfo:: +ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const +{ + assert( (Cond.size() == 3 || Cond.size() == 2) && + "Invalid Mips branch condition!"); + Cond[0].setImm(GetOppositeBranchCondition((Mips::CondCode)Cond[0].getImm())); + return false; +} diff --git a/lib/Target/Mips/MipsInstrInfo.h b/lib/Target/Mips/MipsInstrInfo.h new file mode 100644 index 000000000000..334244e6601a --- /dev/null +++ b/lib/Target/Mips/MipsInstrInfo.h @@ -0,0 +1,223 @@ +//===- MipsInstrInfo.h - Mips Instruction Information -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file 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 { + +namespace Mips { + + // Mips Branch Codes + enum FPBranchCode { + BRANCH_F, + BRANCH_T, + BRANCH_FL, + BRANCH_TL, + BRANCH_INVALID + }; + + // Mips Condition Codes + enum CondCode { + // To be used with float branch True + FCOND_F, + FCOND_UN, + FCOND_EQ, + FCOND_UEQ, + FCOND_OLT, + FCOND_ULT, + FCOND_OLE, + FCOND_ULE, + FCOND_SF, + FCOND_NGLE, + FCOND_SEQ, + FCOND_NGL, + FCOND_LT, + FCOND_NGE, + FCOND_LE, + FCOND_NGT, + + // To be used with float branch False + // This conditions have the same mnemonic as the + // above ones, but are used with a branch False; + FCOND_T, + FCOND_OR, + FCOND_NEQ, + FCOND_OGL, + FCOND_UGE, + FCOND_OGE, + FCOND_UGT, + FCOND_OGT, + FCOND_ST, + FCOND_GLE, + FCOND_SNE, + FCOND_GL, + FCOND_NLT, + FCOND_GE, + FCOND_NLE, + FCOND_GT, + + // Only integer conditions + COND_E, + COND_GZ, + COND_GEZ, + COND_LZ, + COND_LEZ, + COND_NE, + COND_INVALID + }; + + // Turn condition code into conditional branch opcode. + unsigned GetCondBranchFromCond(CondCode CC); + + /// GetOppositeBranchCondition - Return the inverse of the specified cond, + /// e.g. turning COND_E to COND_NE. + CondCode GetOppositeBranchCondition(Mips::CondCode CC); + + /// MipsCCToString - Map each FP condition code to its string + inline static const char *MipsFCCToString(Mips::CondCode CC) + { + switch (CC) { + default: assert(0 && "Unknown condition code"); + case FCOND_F: + case FCOND_T: return "f"; + case FCOND_UN: + case FCOND_OR: return "un"; + case FCOND_EQ: + case FCOND_NEQ: return "eq"; + case FCOND_UEQ: + case FCOND_OGL: return "ueq"; + case FCOND_OLT: + case FCOND_UGE: return "olt"; + case FCOND_ULT: + case FCOND_OGE: return "ult"; + case FCOND_OLE: + case FCOND_UGT: return "ole"; + case FCOND_ULE: + case FCOND_OGT: return "ule"; + case FCOND_SF: + case FCOND_ST: return "sf"; + case FCOND_NGLE: + case FCOND_GLE: return "ngle"; + case FCOND_SEQ: + case FCOND_SNE: return "seq"; + case FCOND_NGL: + case FCOND_GL: return "ngl"; + case FCOND_LT: + case FCOND_NLT: return "lt"; + case FCOND_NGE: + case FCOND_GE: return "ge"; + case FCOND_LE: + case FCOND_NLE: return "nle"; + case FCOND_NGT: + case FCOND_GT: return "gt"; + } + } +} + +class MipsInstrInfo : public TargetInstrInfoImpl { + MipsTargetMachine &TM; + const MipsRegisterInfo RI; +public: + explicit 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 MipsRegisterInfo &getRegisterInfo() const { return RI; } + + /// Return true if the instruction is a register to register move and return + /// the source and dest operands and their sub-register indices by reference. + virtual bool isMoveInstr(const MachineInstr &MI, + unsigned &SrcReg, unsigned &DstReg, + unsigned &SrcSubIdx, unsigned &DstSubIdx) 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(const 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(const MachineInstr *MI, + int &FrameIndex) const; + + /// Branch Analysis + virtual bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const; + virtual unsigned RemoveBranch(MachineBasicBlock &MBB) const; + virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond) const; + virtual bool copyRegToReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned DestReg, unsigned SrcReg, + const TargetRegisterClass *DestRC, + const TargetRegisterClass *SrcRC) const; + virtual void storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned SrcReg, bool isKill, int FrameIndex, + const TargetRegisterClass *RC) const; + + virtual void storeRegToAddr(MachineFunction &MF, unsigned SrcReg, bool isKill, + SmallVectorImpl<MachineOperand> &Addr, + const TargetRegisterClass *RC, + SmallVectorImpl<MachineInstr*> &NewMIs) const; + + virtual void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC) const; + + virtual void loadRegFromAddr(MachineFunction &MF, unsigned DestReg, + SmallVectorImpl<MachineOperand> &Addr, + const TargetRegisterClass *RC, + SmallVectorImpl<MachineInstr*> &NewMIs) const; + + virtual MachineInstr* foldMemoryOperandImpl(MachineFunction &MF, + MachineInstr* MI, + const SmallVectorImpl<unsigned> &Ops, + int FrameIndex) const; + + virtual MachineInstr* foldMemoryOperandImpl(MachineFunction &MF, + MachineInstr* MI, + const SmallVectorImpl<unsigned> &Ops, + MachineInstr* LoadMI) const { + return 0; + } + + virtual bool BlockHasNoFallThrough(const MachineBasicBlock &MBB) const; + virtual + bool ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const; + + /// Insert nop instruction when hazard condition is found + virtual void insertNoop(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const; +}; + +} + +#endif diff --git a/lib/Target/Mips/MipsInstrInfo.td b/lib/Target/Mips/MipsInstrInfo.td new file mode 100644 index 000000000000..b9276fe495eb --- /dev/null +++ b/lib/Target/Mips/MipsInstrInfo.td @@ -0,0 +1,707 @@ +//===- MipsInstrInfo.td - Mips Register defs --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file 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 +//===----------------------------------------------------------------------===// + +def SDT_MipsRet : SDTypeProfile<0, 1, [SDTCisInt<0>]>; +def SDT_MipsJmpLink : SDTypeProfile<0, 1, [SDTCisVT<0, iPTR>]>; +def SDT_MipsSelectCC : SDTypeProfile<1, 3, [SDTCisSameAs<0, 2>, + SDTCisSameAs<2, 3>, SDTCisInt<1>]>; +def SDT_MipsCMov : SDTypeProfile<1, 4, [SDTCisSameAs<0, 1>, + SDTCisSameAs<1, 2>, SDTCisSameAs<3, 4>, + SDTCisInt<4>]>; +def SDT_MipsCallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>]>; +def SDT_MipsCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; + +// Call +def MipsJmpLink : SDNode<"MipsISD::JmpLink",SDT_MipsJmpLink, [SDNPHasChain, + SDNPOutFlag]>; + +// Hi and Lo nodes are used to handle global addresses. Used on +// MipsISelLowering to lower stuff like GlobalAddress, ExternalSymbol +// static model. (nothing to do with Mips Registers Hi and Lo) +def MipsHi : SDNode<"MipsISD::Hi", SDTIntUnaryOp>; +def MipsLo : SDNode<"MipsISD::Lo", SDTIntUnaryOp>; +def MipsGPRel : SDNode<"MipsISD::GPRel", SDTIntUnaryOp>; + +// Return +def MipsRet : SDNode<"MipsISD::Ret", SDT_MipsRet, [SDNPHasChain, + SDNPOptInFlag]>; + +// These are target-independent nodes, but have target-specific formats. +def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_MipsCallSeqStart, + [SDNPHasChain, SDNPOutFlag]>; +def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_MipsCallSeqEnd, + [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>; + +// Select Condition Code +def MipsSelectCC : SDNode<"MipsISD::SelectCC", SDT_MipsSelectCC>; + +// Conditional Move +def MipsCMov : SDNode<"MipsISD::CMov", SDT_MipsCMov>; + +//===----------------------------------------------------------------------===// +// Mips Instruction Predicate Definitions. +//===----------------------------------------------------------------------===// +def HasSEInReg : Predicate<"Subtarget.hasSEInReg()">; +def HasBitCount : Predicate<"Subtarget.hasBitCount()">; +def HasSwap : Predicate<"Subtarget.hasSwap()">; +def HasCondMov : Predicate<"Subtarget.hasCondMov()">; + +//===----------------------------------------------------------------------===// +// Mips Operand, Complex Patterns and Transformations Definitions. +//===----------------------------------------------------------------------===// + +// Instruction operand types +def brtarget : Operand<OtherVT>; +def calltarget : Operand<i32>; +def simm16 : Operand<i32>; +def shamt : Operand<i32>; + +// Unsigned Operand +def uimm16 : Operand<i32> { + let PrintMethod = "printUnsignedImm"; +} + +// Address operand +def mem : Operand<i32> { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops simm16, CPURegs); +} + +// Transformation Function - get the lower 16 bits. +def LO16 : SDNodeXForm<imm, [{ + return getI32Imm((unsigned)N->getZExtValue() & 0xFFFF); +}]>; + +// Transformation Function - get the higher 16 bits. +def HI16 : SDNodeXForm<imm, [{ + return getI32Imm((unsigned)N->getZExtValue() >> 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->getZExtValue() == (short)N->getZExtValue(); + else + return (int64_t)N->getZExtValue() == (short)N->getZExtValue(); +}]>; + +// 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), [{ + if (N->getValueType(0) == MVT::i32) + return (uint32_t)N->getZExtValue() == (unsigned short)N->getZExtValue(); + else + return (uint64_t)N->getZExtValue() == (unsigned short)N->getZExtValue(); +}], LO16>; + +// shamt field must fit in 5 bits. +def immZExt5 : PatLeaf<(imm), [{ + return N->getZExtValue() == ((N->getZExtValue()) & 0x1f) ; +}]>; + +// Mips Address Mode! SDNode frameindex could possibily be a match +// since load and store instructions from stack used it. +def addr : ComplexPattern<i32, 2, "SelectAddr", [frameindex], []>; + +//===----------------------------------------------------------------------===// +// Instructions specific format +//===----------------------------------------------------------------------===// + +// Arithmetic 3 register operands +let isCommutable = 1 in +class ArithR<bits<6> op, bits<6> func, string instr_asm, SDNode OpNode, + InstrItinClass itin>: + FR< op, + func, + (outs CPURegs:$dst), + (ins CPURegs:$b, CPURegs:$c), + !strconcat(instr_asm, "\t$dst, $b, $c"), + [(set CPURegs:$dst, (OpNode CPURegs:$b, CPURegs:$c))], itin>; + +let isCommutable = 1 in +class ArithOverflowR<bits<6> op, bits<6> func, string instr_asm>: + FR< op, + func, + (outs CPURegs:$dst), + (ins CPURegs:$b, CPURegs:$c), + !strconcat(instr_asm, "\t$dst, $b, $c"), + [], IIAlu>; + +// Arithmetic 2 register operands +class ArithI<bits<6> op, string instr_asm, SDNode OpNode, + Operand Od, PatLeaf imm_type> : + FI< op, + (outs CPURegs:$dst), + (ins CPURegs:$b, Od:$c), + !strconcat(instr_asm, "\t$dst, $b, $c"), + [(set CPURegs:$dst, (OpNode CPURegs:$b, imm_type:$c))], IIAlu>; + +class ArithOverflowI<bits<6> op, string instr_asm, SDNode OpNode, + Operand Od, PatLeaf imm_type> : + FI< op, + (outs CPURegs:$dst), + (ins CPURegs:$b, Od:$c), + !strconcat(instr_asm, "\t$dst, $b, $c"), + [], IIAlu>; + +// Arithmetic Multiply ADD/SUB +let rd=0 in +class MArithR<bits<6> func, string instr_asm> : + FR< 0x1c, + func, + (outs CPURegs:$rs), + (ins CPURegs:$rt), + !strconcat(instr_asm, "\t$rs, $rt"), + [], IIImul>; + +// Logical +class LogicR<bits<6> func, string instr_asm, SDNode OpNode>: + FR< 0x00, + func, + (outs CPURegs:$dst), + (ins CPURegs:$b, CPURegs:$c), + !strconcat(instr_asm, "\t$dst, $b, $c"), + [(set CPURegs:$dst, (OpNode CPURegs:$b, CPURegs:$c))], IIAlu>; + +class LogicI<bits<6> op, string instr_asm, SDNode OpNode>: + FI< op, + (outs CPURegs:$dst), + (ins CPURegs:$b, uimm16:$c), + !strconcat(instr_asm, "\t$dst, $b, $c"), + [(set CPURegs:$dst, (OpNode CPURegs:$b, immZExt16:$c))], IIAlu>; + +class LogicNOR<bits<6> op, bits<6> func, string instr_asm>: + FR< op, + func, + (outs CPURegs:$dst), + (ins CPURegs:$b, CPURegs:$c), + !strconcat(instr_asm, "\t$dst, $b, $c"), + [(set CPURegs:$dst, (not (or CPURegs:$b, CPURegs:$c)))], IIAlu>; + +// Shifts +let rt = 0 in +class LogicR_shift_imm<bits<6> func, string instr_asm, SDNode OpNode>: + FR< 0x00, + func, + (outs CPURegs:$dst), + (ins CPURegs:$b, shamt:$c), + !strconcat(instr_asm, "\t$dst, $b, $c"), + [(set CPURegs:$dst, (OpNode CPURegs:$b, immZExt5:$c))], IIAlu>; + +class LogicR_shift_reg<bits<6> func, string instr_asm, SDNode OpNode>: + FR< 0x00, + func, + (outs CPURegs:$dst), + (ins CPURegs:$b, CPURegs:$c), + !strconcat(instr_asm, "\t$dst, $b, $c"), + [(set CPURegs:$dst, (OpNode CPURegs:$b, CPURegs:$c))], IIAlu>; + +// Load Upper Imediate +class LoadUpper<bits<6> op, string instr_asm>: + FI< op, + (outs CPURegs:$dst), + (ins uimm16:$imm), + !strconcat(instr_asm, "\t$dst, $imm"), + [], IIAlu>; + +// Memory Load/Store +let canFoldAsLoad = 1, hasDelaySlot = 1 in +class LoadM<bits<6> op, string instr_asm, PatFrag OpNode>: + FI< op, + (outs CPURegs:$dst), + (ins mem:$addr), + !strconcat(instr_asm, "\t$dst, $addr"), + [(set CPURegs:$dst, (OpNode addr:$addr))], IILoad>; + +class StoreM<bits<6> op, string instr_asm, PatFrag OpNode>: + FI< op, + (outs), + (ins CPURegs:$dst, mem:$addr), + !strconcat(instr_asm, "\t$dst, $addr"), + [(OpNode CPURegs:$dst, addr:$addr)], IIStore>; + +// Conditional Branch +let isBranch = 1, isTerminator=1, hasDelaySlot = 1 in { +class CBranch<bits<6> op, string instr_asm, PatFrag cond_op>: + FI< op, + (outs), + (ins CPURegs:$a, CPURegs:$b, brtarget:$offset), + !strconcat(instr_asm, "\t$a, $b, $offset"), + [(brcond (cond_op CPURegs:$a, CPURegs:$b), bb:$offset)], + IIBranch>; + + +class CBranchZero<bits<6> op, string instr_asm, PatFrag cond_op>: + FI< op, + (outs), + (ins CPURegs:$src, brtarget:$offset), + !strconcat(instr_asm, "\t$src, $offset"), + [(brcond (cond_op CPURegs:$src, 0), bb:$offset)], + IIBranch>; +} + +// SetCC +class SetCC_R<bits<6> op, bits<6> func, string instr_asm, + PatFrag cond_op>: + FR< op, + func, + (outs CPURegs:$dst), + (ins CPURegs:$b, CPURegs:$c), + !strconcat(instr_asm, "\t$dst, $b, $c"), + [(set CPURegs:$dst, (cond_op CPURegs:$b, CPURegs:$c))], + IIAlu>; + +class SetCC_I<bits<6> op, string instr_asm, PatFrag cond_op, + Operand Od, PatLeaf imm_type>: + FI< op, + (outs CPURegs:$dst), + (ins CPURegs:$b, Od:$c), + !strconcat(instr_asm, "\t$dst, $b, $c"), + [(set CPURegs:$dst, (cond_op CPURegs:$b, imm_type:$c))], + IIAlu>; + +// Unconditional branch +let isBranch=1, isTerminator=1, isBarrier=1, hasDelaySlot = 1 in +class JumpFJ<bits<6> op, string instr_asm>: + FJ< op, + (outs), + (ins brtarget:$target), + !strconcat(instr_asm, "\t$target"), + [(br bb:$target)], IIBranch>; + +let isBranch=1, isTerminator=1, isBarrier=1, rd=0, hasDelaySlot = 1 in +class JumpFR<bits<6> op, bits<6> func, string instr_asm>: + FR< op, + func, + (outs), + (ins CPURegs:$target), + !strconcat(instr_asm, "\t$target"), + [(brind CPURegs:$target)], IIBranch>; + +// Jump and Link (Call) +let isCall=1, hasDelaySlot=1, + // All calls clobber the non-callee saved registers... + Defs = [AT, V0, V1, A0, A1, A2, A3, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, + K0, K1, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, + F14, F15, F16, F17, F18, F19], Uses = [GP] in { + class JumpLink<bits<6> op, string instr_asm>: + FJ< op, + (outs), + (ins calltarget:$target), + !strconcat(instr_asm, "\t$target"), + [(MipsJmpLink imm:$target)], IIBranch>; + + let rd=31 in + class JumpLinkReg<bits<6> op, bits<6> func, string instr_asm>: + FR< op, + func, + (outs), + (ins CPURegs:$rs), + !strconcat(instr_asm, "\t$rs"), + [(MipsJmpLink CPURegs:$rs)], IIBranch>; + + class BranchLink<string instr_asm>: + FI< 0x1, + (outs), + (ins CPURegs:$rs, brtarget:$target), + !strconcat(instr_asm, "\t$rs, $target"), + [], IIBranch>; +} + +// Mul, Div +class MulDiv<bits<6> func, string instr_asm, InstrItinClass itin>: + FR< 0x00, + func, + (outs), + (ins CPURegs:$a, CPURegs:$b), + !strconcat(instr_asm, "\t$a, $b"), + [], itin>; + +// Move from Hi/Lo +class MoveFromLOHI<bits<6> func, string instr_asm>: + FR< 0x00, + func, + (outs CPURegs:$dst), + (ins), + !strconcat(instr_asm, "\t$dst"), + [], IIHiLo>; + +class MoveToLOHI<bits<6> func, string instr_asm>: + FR< 0x00, + func, + (outs), + (ins CPURegs:$src), + !strconcat(instr_asm, "\t$src"), + [], IIHiLo>; + +class EffectiveAddress<string instr_asm> : + FI<0x09, + (outs CPURegs:$dst), + (ins mem:$addr), + instr_asm, + [(set CPURegs:$dst, addr:$addr)], IIAlu>; + +// Count Leading Ones/Zeros in Word +class CountLeading<bits<6> func, string instr_asm, SDNode CountOp>: + FR< 0x1c, func, (outs CPURegs:$dst), (ins CPURegs:$src), + !strconcat(instr_asm, "\t$dst, $src"), + [(set CPURegs:$dst, (CountOp CPURegs:$src))], IIAlu>; + +// Sign Extend in Register. +class SignExtInReg<bits<6> func, string instr_asm, ValueType vt>: + FR< 0x3f, func, (outs CPURegs:$dst), (ins CPURegs:$src), + !strconcat(instr_asm, "\t$dst, $src"), + [(set CPURegs:$dst, (sext_inreg CPURegs:$src, vt))], NoItinerary>; + +// Byte Swap +class ByteSwap<bits<6> func, string instr_asm>: + FR< 0x1f, func, (outs CPURegs:$dst), (ins CPURegs:$src), + !strconcat(instr_asm, "\t$dst, $src"), + [(set CPURegs:$dst, (bswap CPURegs:$src))], NoItinerary>; + +// Conditional Move +class CondMov<bits<6> func, string instr_asm, PatLeaf MovCode>: + FR< 0x00, func, (outs CPURegs:$dst), (ins CPURegs:$F, CPURegs:$T, + CPURegs:$cond), !strconcat(instr_asm, "\t$dst, $T, $cond"), + [(set CPURegs:$dst, (MipsCMov CPURegs:$F, CPURegs:$T, + CPURegs:$cond, MovCode))], NoItinerary>; + +//===----------------------------------------------------------------------===// +// Pseudo instructions +//===----------------------------------------------------------------------===// + +// As stack alignment is always done with addiu, we need a 16-bit immediate +let Defs = [SP], Uses = [SP] in { +def ADJCALLSTACKDOWN : MipsPseudo<(outs), (ins uimm16:$amt), + "!ADJCALLSTACKDOWN $amt", + [(callseq_start timm:$amt)]>; +def ADJCALLSTACKUP : MipsPseudo<(outs), (ins uimm16:$amt1, uimm16:$amt2), + "!ADJCALLSTACKUP $amt1", + [(callseq_end timm:$amt1, timm:$amt2)]>; +} + +// Some assembly macros need to avoid pseudoinstructions and assembler +// automatic reodering, we should reorder ourselves. +def MACRO : MipsPseudo<(outs), (ins), ".set\tmacro", []>; +def REORDER : MipsPseudo<(outs), (ins), ".set\treorder", []>; +def NOMACRO : MipsPseudo<(outs), (ins), ".set\tnomacro", []>; +def NOREORDER : MipsPseudo<(outs), (ins), ".set\tnoreorder", []>; + +// When handling PIC code the assembler needs .cpload and .cprestore +// directives. If the real instructions corresponding these directives +// are used, we have the same behavior, but get also a bunch of warnings +// from the assembler. +def CPLOAD : MipsPseudo<(outs), (ins CPURegs:$picreg), ".cpload\t$picreg", []>; +def CPRESTORE : MipsPseudo<(outs), (ins uimm16:$loc), ".cprestore\t$loc\n", []>; + +// The supported Mips ISAs dont have any instruction close to the SELECT_CC +// operation. The solution is to create a Mips pseudo SELECT_CC instruction +// (MipsSelectCC), use LowerSELECT_CC to generate this instruction and finally +// replace it for real supported nodes into EmitInstrWithCustomInserter +let usesCustomDAGSchedInserter = 1 in { + class PseudoSelCC<RegisterClass RC, string asmstr>: + MipsPseudo<(outs RC:$dst), (ins CPURegs:$CmpRes, RC:$T, RC:$F), asmstr, + [(set RC:$dst, (MipsSelectCC CPURegs:$CmpRes, RC:$T, RC:$F))]>; +} + +def Select_CC : PseudoSelCC<CPURegs, "# MipsSelect_CC_i32">; + +//===----------------------------------------------------------------------===// +// Instruction definition +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// MipsI Instructions +//===----------------------------------------------------------------------===// + +/// Arithmetic Instructions (ALU Immediate) +def ADDiu : ArithI<0x09, "addiu", add, simm16, immSExt16>; +def ADDi : ArithOverflowI<0x08, "addi", add, simm16, immSExt16>; +def SLTi : SetCC_I<0x0a, "slti", setlt, simm16, immSExt16>; +def SLTiu : SetCC_I<0x0b, "sltiu", setult, simm16, immSExt16>; +def ANDi : LogicI<0x0c, "andi", and>; +def ORi : LogicI<0x0d, "ori", or>; +def XORi : LogicI<0x0e, "xori", xor>; +def LUi : LoadUpper<0x0f, "lui">; + +/// Arithmetic Instructions (3-Operand, R-Type) +def ADDu : ArithR<0x00, 0x21, "addu", add, IIAlu>; +def SUBu : ArithR<0x00, 0x23, "subu", sub, IIAlu>; +def ADD : ArithOverflowR<0x00, 0x20, "add">; +def SUB : ArithOverflowR<0x00, 0x22, "sub">; +def SLT : SetCC_R<0x00, 0x2a, "slt", setlt>; +def SLTu : SetCC_R<0x00, 0x2b, "sltu", setult>; +def AND : LogicR<0x24, "and", and>; +def OR : LogicR<0x25, "or", or>; +def XOR : LogicR<0x26, "xor", xor>; +def NOR : LogicNOR<0x00, 0x27, "nor">; + +/// Shift Instructions +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 and Store Instructions +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>; + +/// Jump and Branch Instructions +def J : JumpFJ<0x02, "j">; +def JR : JumpFR<0x00, 0x08, "jr">; +def JAL : JumpLink<0x03, "jal">; +def JALR : JumpLinkReg<0x00, 0x09, "jalr">; +def BEQ : CBranch<0x04, "beq", seteq>; +def BNE : CBranch<0x05, "bne", setne>; + +let rt=1 in + def BGEZ : CBranchZero<0x01, "bgez", setge>; + +let rt=0 in { + def BGTZ : CBranchZero<0x07, "bgtz", setgt>; + def BLEZ : CBranchZero<0x07, "blez", setle>; + def BLTZ : CBranchZero<0x01, "bltz", setlt>; +} + +def BGEZAL : BranchLink<"bgezal">; +def BLTZAL : BranchLink<"bltzal">; + +let isReturn=1, isTerminator=1, hasDelaySlot=1, + isBarrier=1, hasCtrlDep=1, rs=0, rt=0, shamt=0 in + def RET : FR <0x00, 0x02, (outs), (ins CPURegs:$target), + "jr\t$target", [(MipsRet CPURegs:$target)], IIBranch>; + +/// Multiply and Divide Instructions. +let Defs = [HI, LO] in { + def MULT : MulDiv<0x18, "mult", IIImul>; + def MULTu : MulDiv<0x19, "multu", IIImul>; + def DIV : MulDiv<0x1a, "div", IIIdiv>; + def DIVu : MulDiv<0x1b, "divu", IIIdiv>; +} + +let Defs = [HI] in + def MTHI : MoveToLOHI<0x11, "mthi">; +let Defs = [LO] in + def MTLO : MoveToLOHI<0x13, "mtlo">; + +let Uses = [HI] in + def MFHI : MoveFromLOHI<0x10, "mfhi">; +let Uses = [LO] in + def MFLO : MoveFromLOHI<0x12, "mflo">; + +/// Sign Ext In Register Instructions. +let Predicates = [HasSEInReg] in { + let shamt = 0x10, rs = 0 in + def SEB : SignExtInReg<0x21, "seb", i8>; + + let shamt = 0x18, rs = 0 in + def SEH : SignExtInReg<0x20, "seh", i16>; +} + +/// Count Leading +let Predicates = [HasBitCount] in { + let rt = 0 in + def CLZ : CountLeading<0b010110, "clz", ctlz>; +} + +/// Byte Swap +let Predicates = [HasSwap] in { + let shamt = 0x3, rs = 0 in + def WSBW : ByteSwap<0x20, "wsbw">; +} + +/// Conditional Move +def MIPS_CMOV_ZERO : PatLeaf<(i32 0)>; +def MIPS_CMOV_NZERO : PatLeaf<(i32 1)>; + +let Predicates = [HasCondMov], isTwoAddress = 1 in { + def MOVN : CondMov<0x0a, "movn", MIPS_CMOV_NZERO>; + def MOVZ : CondMov<0x0b, "movz", MIPS_CMOV_ZERO>; +} + +/// No operation +let addr=0 in + def NOP : FJ<0, (outs), (ins), "nop", [], IIAlu>; + +// FrameIndexes are legalized when they are operands from load/store +// instructions. The same not happens for stack address copies, so an +// add op with mem ComplexPattern is used and the stack address copy +// can be matched. It's similar to Sparc LEA_ADDRi +def LEA_ADDiu : EffectiveAddress<"addiu\t$dst, ${addr:stackloc}">; + +// MADD*/MSUB* are not part of MipsI either. +//def MADD : MArithR<0x00, "madd">; +//def MADDU : MArithR<0x01, "maddu">; +//def MSUB : MArithR<0x04, "msub">; +//def MSUBU : MArithR<0x05, "msubu">; + +// MUL is a assembly macro in the current used ISAs. In recent ISA's +// it is a real instruction. +//def MUL : ArithR<0x1c, 0x02, "mul", mul, IIImul>; + +//===----------------------------------------------------------------------===// +// Arbitrary patterns that map to one or more instructions +//===----------------------------------------------------------------------===// + +// Small immediates +def : Pat<(i32 immSExt16:$in), + (ADDiu ZERO, imm:$in)>; +def : Pat<(i32 immZExt16:$in), + (ORi ZERO, imm:$in)>; + +// Arbitrary immediates +def : Pat<(i32 imm:$imm), + (ORi (LUi (HI16 imm:$imm)), (LO16 imm:$imm))>; + +// Carry patterns +def : Pat<(subc CPURegs:$lhs, CPURegs:$rhs), + (SUBu CPURegs:$lhs, CPURegs:$rhs)>; +def : Pat<(addc CPURegs:$lhs, CPURegs:$rhs), + (ADDu CPURegs:$lhs, CPURegs:$rhs)>; +def : Pat<(addc CPURegs:$src, imm:$imm), + (ADDiu CPURegs:$src, imm:$imm)>; + +// Call +def : Pat<(MipsJmpLink (i32 tglobaladdr:$dst)), + (JAL tglobaladdr:$dst)>; +def : Pat<(MipsJmpLink (i32 texternalsym:$dst)), + (JAL texternalsym:$dst)>; +def : Pat<(MipsJmpLink CPURegs:$dst), + (JALR CPURegs:$dst)>; + +// hi/lo relocs +def : Pat<(MipsHi tglobaladdr:$in), (LUi tglobaladdr:$in)>; +def : Pat<(add CPURegs:$hi, (MipsLo tglobaladdr:$lo)), + (ADDiu CPURegs:$hi, tglobaladdr:$lo)>; + +def : Pat<(MipsHi tjumptable:$in), (LUi tjumptable:$in)>; +def : Pat<(add CPURegs:$hi, (MipsLo tjumptable:$lo)), + (ADDiu CPURegs:$hi, tjumptable:$lo)>; + +def : Pat<(MipsHi tconstpool:$in), (LUi tconstpool:$in)>; +def : Pat<(add CPURegs:$hi, (MipsLo tconstpool:$lo)), + (ADDiu CPURegs:$hi, tconstpool:$lo)>; + +// gp_rel relocs +def : Pat<(add CPURegs:$gp, (MipsGPRel tglobaladdr:$in)), + (ADDiu CPURegs:$gp, tglobaladdr:$in)>; +def : Pat<(add CPURegs:$gp, (MipsGPRel tconstpool:$in)), + (ADDiu CPURegs:$gp, tconstpool:$in)>; + +// Mips does not have "not", so we expand our way +def : Pat<(not CPURegs:$in), + (NOR CPURegs:$in, ZERO)>; + +// extended load and stores +def : Pat<(extloadi1 addr:$src), (LBu addr:$src)>; +def : Pat<(extloadi8 addr:$src), (LBu addr:$src)>; +def : Pat<(extloadi16 addr:$src), (LHu addr:$src)>; + +// peepholes +def : Pat<(store (i32 0), addr:$dst), (SW ZERO, addr:$dst)>; + +// brcond patterns +def : Pat<(brcond (setne CPURegs:$lhs, 0), bb:$dst), + (BNE CPURegs:$lhs, ZERO, bb:$dst)>; +def : Pat<(brcond (seteq CPURegs:$lhs, 0), bb:$dst), + (BEQ CPURegs:$lhs, ZERO, bb:$dst)>; + +def : Pat<(brcond (setge CPURegs:$lhs, CPURegs:$rhs), bb:$dst), + (BEQ (SLT CPURegs:$lhs, CPURegs:$rhs), ZERO, bb:$dst)>; +def : Pat<(brcond (setuge CPURegs:$lhs, CPURegs:$rhs), bb:$dst), + (BEQ (SLTu CPURegs:$lhs, CPURegs:$rhs), ZERO, bb:$dst)>; +def : Pat<(brcond (setge CPURegs:$lhs, immSExt16:$rhs), bb:$dst), + (BEQ (SLTi CPURegs:$lhs, immSExt16:$rhs), ZERO, bb:$dst)>; +def : Pat<(brcond (setuge CPURegs:$lhs, immSExt16:$rhs), bb:$dst), + (BEQ (SLTiu CPURegs:$lhs, immSExt16:$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 (setule CPURegs:$lhs, CPURegs:$rhs), bb:$dst), + (BEQ (SLTu CPURegs:$rhs, CPURegs:$lhs), ZERO, bb:$dst)>; + +def : Pat<(brcond CPURegs:$cond, bb:$dst), + (BNE CPURegs:$cond, ZERO, bb:$dst)>; + +// select patterns +def : Pat<(select (setge CPURegs:$lhs, CPURegs:$rhs), CPURegs:$T, CPURegs:$F), + (MOVZ CPURegs:$F, CPURegs:$T, (SLT CPURegs:$lhs, CPURegs:$rhs))>; +def : Pat<(select (setuge CPURegs:$lhs, CPURegs:$rhs), CPURegs:$T, CPURegs:$F), + (MOVZ CPURegs:$F, CPURegs:$T, (SLTu CPURegs:$lhs, CPURegs:$rhs))>; +def : Pat<(select (setge CPURegs:$lhs, immSExt16:$rhs), CPURegs:$T, CPURegs:$F), + (MOVZ CPURegs:$F, CPURegs:$T, (SLTi CPURegs:$lhs, immSExt16:$rhs))>; +def : Pat<(select (setuge CPURegs:$lh, immSExt16:$rh), CPURegs:$T, CPURegs:$F), + (MOVZ CPURegs:$F, CPURegs:$T, (SLTiu CPURegs:$lh, immSExt16:$rh))>; + +def : Pat<(select (setle CPURegs:$lhs, CPURegs:$rhs), CPURegs:$T, CPURegs:$F), + (MOVZ CPURegs:$F, CPURegs:$T, (SLT CPURegs:$rhs, CPURegs:$lhs))>; +def : Pat<(select (setule CPURegs:$lhs, CPURegs:$rhs), CPURegs:$T, CPURegs:$F), + (MOVZ CPURegs:$F, CPURegs:$T, (SLTu CPURegs:$rhs, CPURegs:$lhs))>; + +def : Pat<(select (seteq CPURegs:$lhs, CPURegs:$rhs), CPURegs:$T, CPURegs:$F), + (MOVZ CPURegs:$F, CPURegs:$T, (XOR CPURegs:$lhs, CPURegs:$rhs))>; +def : Pat<(select (setne CPURegs:$lhs, CPURegs:$rhs), CPURegs:$T, CPURegs:$F), + (MOVN CPURegs:$F, CPURegs:$T, (XOR CPURegs:$lhs, CPURegs:$rhs))>; + +def : Pat<(select CPURegs:$cond, CPURegs:$T, CPURegs:$F), + (MOVN CPURegs:$F, CPURegs:$T, CPURegs:$cond)>; + +// setcc patterns +def : Pat<(seteq CPURegs:$lhs, CPURegs:$rhs), + (SLTu (XOR CPURegs:$lhs, CPURegs:$rhs), 1)>; +def : Pat<(setne CPURegs:$lhs, CPURegs:$rhs), + (SLTu ZERO, (XOR CPURegs:$lhs, CPURegs:$rhs))>; + +def : Pat<(setle CPURegs:$lhs, CPURegs:$rhs), + (XORi (SLT CPURegs:$rhs, CPURegs:$lhs), 1)>; +def : Pat<(setule CPURegs:$lhs, CPURegs:$rhs), + (XORi (SLTu CPURegs:$rhs, CPURegs:$lhs), 1)>; + +def : Pat<(setgt CPURegs:$lhs, CPURegs:$rhs), + (SLT CPURegs:$rhs, CPURegs:$lhs)>; +def : Pat<(setugt CPURegs:$lhs, CPURegs:$rhs), + (SLTu CPURegs:$rhs, CPURegs:$lhs)>; + +def : Pat<(setge CPURegs:$lhs, CPURegs:$rhs), + (XORi (SLT CPURegs:$lhs, CPURegs:$rhs), 1)>; +def : Pat<(setuge CPURegs:$lhs, CPURegs:$rhs), + (XORi (SLTu CPURegs:$lhs, CPURegs:$rhs), 1)>; + +def : Pat<(setge CPURegs:$lhs, immSExt16:$rhs), + (XORi (SLTi CPURegs:$lhs, immSExt16:$rhs), 1)>; +def : Pat<(setuge CPURegs:$lhs, immSExt16:$rhs), + (XORi (SLTiu CPURegs:$lhs, immSExt16:$rhs), 1)>; + +//===----------------------------------------------------------------------===// +// Floating Point Support +//===----------------------------------------------------------------------===// + +include "MipsInstrFPU.td" + diff --git a/lib/Target/Mips/MipsMachineFunction.h b/lib/Target/Mips/MipsMachineFunction.h new file mode 100644 index 000000000000..b95394ec81ce --- /dev/null +++ b/lib/Target/Mips/MipsMachineFunction.h @@ -0,0 +1,131 @@ +//===-- MipsMachineFunctionInfo.h - Private data used for Mips ----*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the Mips specific subclass of MachineFunctionInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPS_MACHINE_FUNCTION_INFO_H +#define MIPS_MACHINE_FUNCTION_INFO_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/VectorExtras.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFrameInfo.h" + +namespace llvm { + +/// MipsFunctionInfo - This class is derived from MachineFunction private +/// Mips target-specific information for each MachineFunction. +class MipsFunctionInfo : public MachineFunctionInfo { + +private: + /// Holds for each function where on the stack the Frame Pointer must be + /// saved. This is used on Prologue and Epilogue to emit FP save/restore + int FPStackOffset; + + /// Holds for each function where on the stack the Return Address must be + /// saved. This is used on Prologue and Epilogue to emit RA save/restore + int RAStackOffset; + + /// At each function entry, two special bitmask directives must be emitted + /// to help debugging, for CPU and FPU callee saved registers. Both need + /// the negative offset from the final stack size and its higher registers + /// location on the stack. + int CPUTopSavedRegOff; + int FPUTopSavedRegOff; + + /// MipsFIHolder - Holds a FrameIndex and it's Stack Pointer Offset + struct MipsFIHolder { + + int FI; + int SPOffset; + + MipsFIHolder(int FrameIndex, int StackPointerOffset) + : FI(FrameIndex), SPOffset(StackPointerOffset) {} + }; + + /// When PIC is used the GP must be saved on the stack on the function + /// prologue and must be reloaded from this stack location after every + /// call. A reference to its stack location and frame index must be kept + /// to be used on emitPrologue and processFunctionBeforeFrameFinalized. + MipsFIHolder GPHolder; + + /// On LowerFORMAL_ARGUMENTS the stack size is unknown, so the Stack + /// Pointer Offset calculation of "not in register arguments" must be + /// postponed to emitPrologue. + SmallVector<MipsFIHolder, 16> FnLoadArgs; + bool HasLoadArgs; + + // When VarArgs, we must write registers back to caller stack, preserving + // on register arguments. Since the stack size is unknown on + // LowerFORMAL_ARGUMENTS, the Stack Pointer Offset calculation must be + // postponed to emitPrologue. + SmallVector<MipsFIHolder, 4> FnStoreVarArgs; + bool HasStoreVarArgs; + + /// SRetReturnReg - Some subtargets require that sret lowering includes + /// returning the value of the returned struct in a register. This field + /// holds the virtual register into which the sret argument is passed. + unsigned SRetReturnReg; + +public: + MipsFunctionInfo(MachineFunction& MF) + : FPStackOffset(0), RAStackOffset(0), CPUTopSavedRegOff(0), + FPUTopSavedRegOff(0), GPHolder(-1,-1), HasLoadArgs(false), + HasStoreVarArgs(false), SRetReturnReg(0) + {} + + int getFPStackOffset() const { return FPStackOffset; } + void setFPStackOffset(int Off) { FPStackOffset = Off; } + + int getRAStackOffset() const { return RAStackOffset; } + void setRAStackOffset(int Off) { RAStackOffset = Off; } + + int getCPUTopSavedRegOff() const { return CPUTopSavedRegOff; } + void setCPUTopSavedRegOff(int Off) { CPUTopSavedRegOff = Off; } + + int getFPUTopSavedRegOff() const { return FPUTopSavedRegOff; } + void setFPUTopSavedRegOff(int Off) { FPUTopSavedRegOff = Off; } + + int getGPStackOffset() const { return GPHolder.SPOffset; } + int getGPFI() const { return GPHolder.FI; } + void setGPStackOffset(int Off) { GPHolder.SPOffset = Off; } + void setGPFI(int FI) { GPHolder.FI = FI; } + + bool hasLoadArgs() const { return HasLoadArgs; } + bool hasStoreVarArgs() const { return HasStoreVarArgs; } + + void recordLoadArgsFI(int FI, int SPOffset) { + if (!HasLoadArgs) HasLoadArgs=true; + FnLoadArgs.push_back(MipsFIHolder(FI, SPOffset)); + } + void recordStoreVarArgsFI(int FI, int SPOffset) { + if (!HasStoreVarArgs) HasStoreVarArgs=true; + FnStoreVarArgs.push_back(MipsFIHolder(FI, SPOffset)); + } + + void adjustLoadArgsFI(MachineFrameInfo *MFI) const { + if (!hasLoadArgs()) return; + for (unsigned i = 0, e = FnLoadArgs.size(); i != e; ++i) + MFI->setObjectOffset( FnLoadArgs[i].FI, FnLoadArgs[i].SPOffset ); + } + void adjustStoreVarArgsFI(MachineFrameInfo *MFI) const { + if (!hasStoreVarArgs()) return; + for (unsigned i = 0, e = FnStoreVarArgs.size(); i != e; ++i) + MFI->setObjectOffset( FnStoreVarArgs[i].FI, FnStoreVarArgs[i].SPOffset ); + } + + unsigned getSRetReturnReg() const { return SRetReturnReg; } + void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; } +}; + +} // end of namespace llvm + +#endif // MIPS_MACHINE_FUNCTION_INFO_H diff --git a/lib/Target/Mips/MipsRegisterInfo.cpp b/lib/Target/Mips/MipsRegisterInfo.cpp new file mode 100644 index 000000000000..579d4db6422f --- /dev/null +++ b/lib/Target/Mips/MipsRegisterInfo.cpp @@ -0,0 +1,535 @@ +//===- MipsRegisterInfo.cpp - MIPS Register Information -== -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the MIPS implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mips-reg-info" + +#include "Mips.h" +#include "MipsSubtarget.h" +#include "MipsRegisterInfo.h" +#include "MipsMachineFunction.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" + +using namespace llvm; + +MipsRegisterInfo::MipsRegisterInfo(const MipsSubtarget &ST, + const TargetInstrInfo &tii) + : MipsGenRegisterInfo(Mips::ADJCALLSTACKDOWN, Mips::ADJCALLSTACKUP), + Subtarget(ST), TII(tii) {} + +/// getRegisterNumbering - Given the enum value for some register, e.g. +/// Mips::RA, return the number that it corresponds to (e.g. 31). +unsigned MipsRegisterInfo:: +getRegisterNumbering(unsigned RegEnum) +{ + switch (RegEnum) { + case Mips::ZERO : case Mips::F0 : case Mips::D0 : return 0; + case Mips::AT : case Mips::F1 : return 1; + case Mips::V0 : case Mips::F2 : case Mips::D1 : return 2; + case Mips::V1 : case Mips::F3 : return 3; + case Mips::A0 : case Mips::F4 : case Mips::D2 : return 4; + case Mips::A1 : case Mips::F5 : return 5; + case Mips::A2 : case Mips::F6 : case Mips::D3 : return 6; + case Mips::A3 : case Mips::F7 : return 7; + case Mips::T0 : case Mips::F8 : case Mips::D4 : return 8; + case Mips::T1 : case Mips::F9 : return 9; + case Mips::T2 : case Mips::F10: case Mips::D5: return 10; + case Mips::T3 : case Mips::F11: return 11; + case Mips::T4 : case Mips::F12: case Mips::D6: return 12; + case Mips::T5 : case Mips::F13: return 13; + case Mips::T6 : case Mips::F14: case Mips::D7: return 14; + case Mips::T7 : case Mips::F15: return 15; + case Mips::T8 : case Mips::F16: case Mips::D8: return 16; + case Mips::T9 : case Mips::F17: return 17; + case Mips::S0 : case Mips::F18: case Mips::D9: return 18; + case Mips::S1 : case Mips::F19: return 19; + case Mips::S2 : case Mips::F20: case Mips::D10: return 20; + case Mips::S3 : case Mips::F21: return 21; + case Mips::S4 : case Mips::F22: case Mips::D11: return 22; + case Mips::S5 : case Mips::F23: return 23; + case Mips::S6 : case Mips::F24: case Mips::D12: return 24; + case Mips::S7 : case Mips::F25: return 25; + case Mips::K0 : case Mips::F26: case Mips::D13: return 26; + case Mips::K1 : case Mips::F27: return 27; + case Mips::GP : case Mips::F28: case Mips::D14: return 28; + case Mips::SP : case Mips::F29: return 29; + case Mips::FP : case Mips::F30: case Mips::D15: return 30; + case Mips::RA : case Mips::F31: return 31; + default: assert(0 && "Unknown register number!"); + } + return 0; // Not reached +} + +unsigned MipsRegisterInfo::getPICCallReg(void) { return Mips::T9; } + +//===----------------------------------------------------------------------===// +// Callee Saved Registers methods +//===----------------------------------------------------------------------===// + +/// Mips Callee Saved Registers +const unsigned* MipsRegisterInfo:: +getCalleeSavedRegs(const MachineFunction *MF) const +{ + // Mips callee-save register range is $16-$23, $f20-$f30 + static const unsigned SingleFloatOnlyCalleeSavedRegs[] = { + Mips::S0, Mips::S1, Mips::S2, Mips::S3, + Mips::S4, Mips::S5, Mips::S6, Mips::S7, + Mips::F20, Mips::F21, Mips::F22, Mips::F23, Mips::F24, Mips::F25, + Mips::F26, Mips::F27, Mips::F28, Mips::F29, Mips::F30, 0 + }; + + static const unsigned BitMode32CalleeSavedRegs[] = { + Mips::S0, Mips::S1, Mips::S2, Mips::S3, + Mips::S4, Mips::S5, Mips::S6, Mips::S7, + Mips::F20, Mips::F22, Mips::F24, Mips::F26, Mips::F28, Mips::F30, + Mips::D10, Mips::D11, Mips::D12, Mips::D13, Mips::D14, Mips::D15,0 + }; + + if (Subtarget.isSingleFloat()) + return SingleFloatOnlyCalleeSavedRegs; + else + return BitMode32CalleeSavedRegs; +} + +/// Mips Callee Saved Register Classes +const TargetRegisterClass* const* +MipsRegisterInfo::getCalleeSavedRegClasses(const MachineFunction *MF) const +{ + static const TargetRegisterClass * const SingleFloatOnlyCalleeSavedRC[] = { + &Mips::CPURegsRegClass, &Mips::CPURegsRegClass, &Mips::CPURegsRegClass, + &Mips::CPURegsRegClass, &Mips::CPURegsRegClass, &Mips::CPURegsRegClass, + &Mips::CPURegsRegClass, &Mips::CPURegsRegClass, + &Mips::FGR32RegClass, &Mips::FGR32RegClass, &Mips::FGR32RegClass, + &Mips::FGR32RegClass, &Mips::FGR32RegClass, &Mips::FGR32RegClass, + &Mips::FGR32RegClass, &Mips::FGR32RegClass, &Mips::FGR32RegClass, + &Mips::FGR32RegClass, &Mips::FGR32RegClass, 0 + }; + + static const TargetRegisterClass * const BitMode32CalleeSavedRC[] = { + &Mips::CPURegsRegClass, &Mips::CPURegsRegClass, &Mips::CPURegsRegClass, + &Mips::CPURegsRegClass, &Mips::CPURegsRegClass, &Mips::CPURegsRegClass, + &Mips::CPURegsRegClass, &Mips::CPURegsRegClass, + &Mips::FGR32RegClass, &Mips::FGR32RegClass, &Mips::FGR32RegClass, + &Mips::FGR32RegClass, &Mips::FGR32RegClass, &Mips::FGR32RegClass, + &Mips::AFGR64RegClass, &Mips::AFGR64RegClass, &Mips::AFGR64RegClass, + &Mips::AFGR64RegClass, &Mips::AFGR64RegClass, &Mips::AFGR64RegClass, 0 + }; + + if (Subtarget.isSingleFloat()) + return SingleFloatOnlyCalleeSavedRC; + else + return BitMode32CalleeSavedRC; +} + +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); + + // SRV4 requires that odd register can't be used. + if (!Subtarget.isSingleFloat()) + for (unsigned FReg=(Mips::F0)+1; FReg < Mips::F30; FReg+=2) + Reserved.set(FReg); + + return Reserved; +} + +//===----------------------------------------------------------------------===// +// +// Stack Frame Processing methods +// +----------------------------+ +// +// The stack is allocated decrementing the stack pointer on +// the first instruction of a function prologue. Once decremented, +// all stack referencesare are done thought a positive offset +// from the stack/frame pointer, so the stack is considering +// to grow up! Otherwise terrible hacks would have to be made +// to get this stack ABI compliant :) +// +// The stack frame required by the ABI (after call): +// Offset +// +// 0 ---------- +// 4 Args to pass +// . saved $GP (used in PIC) +// . Alloca allocations +// . Local Area +// . CPU "Callee Saved" Registers +// . saved FP +// . saved RA +// . FPU "Callee Saved" Registers +// StackSize ----------- +// +// Offset - offset from sp after stack allocation on function prologue +// +// The sp is the stack pointer subtracted/added from the stack size +// at the Prologue/Epilogue +// +// References to the previous stack (to obtain arguments) are done +// with offsets that exceeds the stack size: (stacksize+(4*(num_arg-1)) +// +// Examples: +// - reference to the actual stack frame +// for any local area var there is smt like : FI >= 0, StackOffset: 4 +// sw REGX, 4(SP) +// +// - reference to previous stack frame +// suppose there's a load to the 5th arguments : FI < 0, StackOffset: 16. +// The emitted instruction will be something like: +// lw REGX, 16+StackSize(SP) +// +// Since the total stack size is unknown on LowerFORMAL_ARGUMENTS, all +// stack references (ObjectOffset) created to reference the function +// arguments, are negative numbers. This way, on eliminateFrameIndex it's +// possible to detect those references and the offsets are adjusted to +// their real location. +// +//===----------------------------------------------------------------------===// + +void MipsRegisterInfo::adjustMipsStackFrame(MachineFunction &MF) const +{ + MachineFrameInfo *MFI = MF.getFrameInfo(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); + unsigned StackAlign = MF.getTarget().getFrameInfo()->getStackAlignment(); + + // Min and Max CSI FrameIndex. + int MinCSFI = -1, MaxCSFI = -1; + + // See the description at MipsMachineFunction.h + int TopCPUSavedRegOff = -1, TopFPUSavedRegOff = -1; + + // Replace the dummy '0' SPOffset by the negative offsets, as explained on + // LowerFORMAL_ARGUMENTS. Leaving '0' for while is necessary to avoid + // the approach done by calculateFrameObjectOffsets to the stack frame. + MipsFI->adjustLoadArgsFI(MFI); + MipsFI->adjustStoreVarArgsFI(MFI); + + // It happens that the default stack frame allocation order does not directly + // map to the convention used for mips. So we must fix it. We move the callee + // save register slots after the local variables area, as described in the + // stack frame above. + unsigned CalleeSavedAreaSize = 0; + if (!CSI.empty()) { + MinCSFI = CSI[0].getFrameIdx(); + MaxCSFI = CSI[CSI.size()-1].getFrameIdx(); + } + for (unsigned i = 0, e = CSI.size(); i != e; ++i) + CalleeSavedAreaSize += MFI->getObjectAlignment(CSI[i].getFrameIdx()); + + // Adjust local variables. They should come on the stack right + // after the arguments. + int LastOffsetFI = -1; + for (int i = 0, e = MFI->getObjectIndexEnd(); i != e; ++i) { + if (i >= MinCSFI && i <= MaxCSFI) + continue; + if (MFI->isDeadObjectIndex(i)) + continue; + unsigned Offset = MFI->getObjectOffset(i) - CalleeSavedAreaSize; + if (LastOffsetFI == -1) + LastOffsetFI = i; + if (Offset > MFI->getObjectOffset(LastOffsetFI)) + LastOffsetFI = i; + MFI->setObjectOffset(i, Offset); + } + + // Adjust CPU Callee Saved Registers Area. Registers RA and FP must + // be saved in this CPU Area there is the need. This whole Area must + // be aligned to the default Stack Alignment requirements. + unsigned StackOffset = 0; + unsigned RegSize = Subtarget.isGP32bit() ? 4 : 8; + + if (LastOffsetFI >= 0) + StackOffset = MFI->getObjectOffset(LastOffsetFI)+ + MFI->getObjectSize(LastOffsetFI); + StackOffset = ((StackOffset+StackAlign-1)/StackAlign*StackAlign); + + for (unsigned i = 0, e = CSI.size(); i != e ; ++i) { + if (CSI[i].getRegClass() != Mips::CPURegsRegisterClass) + break; + MFI->setObjectOffset(CSI[i].getFrameIdx(), StackOffset); + TopCPUSavedRegOff = StackOffset; + StackOffset += MFI->getObjectAlignment(CSI[i].getFrameIdx()); + } + + if (hasFP(MF)) { + MFI->setObjectOffset(MFI->CreateStackObject(RegSize, RegSize), + StackOffset); + MipsFI->setFPStackOffset(StackOffset); + TopCPUSavedRegOff = StackOffset; + StackOffset += RegSize; + } + + if (MFI->hasCalls()) { + MFI->setObjectOffset(MFI->CreateStackObject(RegSize, RegSize), + StackOffset); + MipsFI->setRAStackOffset(StackOffset); + TopCPUSavedRegOff = StackOffset; + StackOffset += RegSize; + } + StackOffset = ((StackOffset+StackAlign-1)/StackAlign*StackAlign); + + // Adjust FPU Callee Saved Registers Area. This Area must be + // aligned to the default Stack Alignment requirements. + for (unsigned i = 0, e = CSI.size(); i != e; ++i) { + if (CSI[i].getRegClass() == Mips::CPURegsRegisterClass) + continue; + MFI->setObjectOffset(CSI[i].getFrameIdx(), StackOffset); + TopFPUSavedRegOff = StackOffset; + StackOffset += MFI->getObjectAlignment(CSI[i].getFrameIdx()); + } + StackOffset = ((StackOffset+StackAlign-1)/StackAlign*StackAlign); + + // Update frame info + MFI->setStackSize(StackOffset); + + // Recalculate the final tops offset. The final values must be '0' + // if there isn't a callee saved register for CPU or FPU, otherwise + // a negative offset is needed. + if (TopCPUSavedRegOff >= 0) + MipsFI->setCPUTopSavedRegOff(TopCPUSavedRegOff-StackOffset); + + if (TopFPUSavedRegOff >= 0) + MipsFI->setFPUTopSavedRegOff(TopFPUSavedRegOff-StackOffset); +} + +// hasFP - Return true if the specified function should have a dedicated frame +// pointer register. This is true if the function has variable sized allocas or +// if frame pointer elimination is disabled. +bool MipsRegisterInfo:: +hasFP(const MachineFunction &MF) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + return NoFramePointerElim || MFI->hasVarSizedObjects(); +} + +// 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 +{ + MachineInstr &MI = *II; + MachineFunction &MF = *MI.getParent()->getParent(); + + unsigned i = 0; + while (!MI.getOperand(i).isFI()) { + ++i; + assert(i < MI.getNumOperands() && + "Instr doesn't have FrameIndex operand!"); + } + + #ifndef NDEBUG + DOUT << "\nFunction : " << MF.getFunction()->getName() << "\n"; + DOUT << "<--------->\n"; + MI.print(DOUT); + #endif + + int FrameIndex = MI.getOperand(i).getIndex(); + int stackSize = MF.getFrameInfo()->getStackSize(); + int spOffset = MF.getFrameInfo()->getObjectOffset(FrameIndex); + + #ifndef NDEBUG + DOUT << "FrameIndex : " << FrameIndex << "\n"; + DOUT << "spOffset : " << spOffset << "\n"; + DOUT << "stackSize : " << stackSize << "\n"; + #endif + + // as explained on LowerFORMAL_ARGUMENTS, detect negative offsets + // and adjust SPOffsets considering the final stack size. + int Offset = ((spOffset < 0) ? (stackSize + (-(spOffset+4))) : (spOffset)); + Offset += MI.getOperand(i-1).getImm(); + + #ifndef NDEBUG + DOUT << "Offset : " << Offset << "\n"; + DOUT << "<--------->\n"; + #endif + + MI.getOperand(i-1).ChangeToImmediate(Offset); + MI.getOperand(i).ChangeToRegister(getFrameRegister(MF), false); +} + +void MipsRegisterInfo:: +emitPrologue(MachineFunction &MF) const +{ + MachineBasicBlock &MBB = MF.front(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + MachineBasicBlock::iterator MBBI = MBB.begin(); + DebugLoc dl = (MBBI != MBB.end() ? + MBBI->getDebugLoc() : DebugLoc::getUnknownLoc()); + bool isPIC = (MF.getTarget().getRelocationModel() == Reloc::PIC_); + + // Get the right frame order for Mips. + adjustMipsStackFrame(MF); + + // Get the number of bytes to allocate from the FrameInfo. + unsigned StackSize = MFI->getStackSize(); + + // No need to allocate space on the stack. + if (StackSize == 0 && !MFI->hasCalls()) return; + + int FPOffset = MipsFI->getFPStackOffset(); + int RAOffset = MipsFI->getRAStackOffset(); + + BuildMI(MBB, MBBI, dl, TII.get(Mips::NOREORDER)); + + // TODO: check need from GP here. + if (isPIC && Subtarget.isABI_O32()) + BuildMI(MBB, MBBI, dl, TII.get(Mips::CPLOAD)).addReg(getPICCallReg()); + BuildMI(MBB, MBBI, dl, TII.get(Mips::NOMACRO)); + + // Adjust stack : addi sp, sp, (-imm) + BuildMI(MBB, MBBI, dl, TII.get(Mips::ADDiu), Mips::SP) + .addReg(Mips::SP).addImm(-StackSize); + + // Save the return address only if the function isnt a leaf one. + // sw $ra, stack_loc($sp) + if (MFI->hasCalls()) { + BuildMI(MBB, MBBI, dl, TII.get(Mips::SW)) + .addReg(Mips::RA).addImm(RAOffset).addReg(Mips::SP); + } + + // if framepointer enabled, save it and set it + // to point to the stack pointer + if (hasFP(MF)) { + // sw $fp,stack_loc($sp) + BuildMI(MBB, MBBI, dl, TII.get(Mips::SW)) + .addReg(Mips::FP).addImm(FPOffset).addReg(Mips::SP); + + // move $fp, $sp + BuildMI(MBB, MBBI, dl, TII.get(Mips::ADDu), Mips::FP) + .addReg(Mips::SP).addReg(Mips::ZERO); + } + + // PIC speficic function prologue + if ((isPIC) && (MFI->hasCalls())) { + BuildMI(MBB, MBBI, dl, TII.get(Mips::CPRESTORE)) + .addImm(MipsFI->getGPStackOffset()); + } +} + +void MipsRegisterInfo:: +emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const +{ + MachineBasicBlock::iterator MBBI = prior(MBB.end()); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + DebugLoc dl = MBBI->getDebugLoc(); + + // Get the number of bytes from FrameInfo + int NumBytes = (int) MFI->getStackSize(); + + // Get the FI's where RA and FP are saved. + int FPOffset = MipsFI->getFPStackOffset(); + int RAOffset = MipsFI->getRAStackOffset(); + + // if framepointer enabled, restore it and restore the + // stack pointer + if (hasFP(MF)) { + // move $sp, $fp + BuildMI(MBB, MBBI, dl, TII.get(Mips::ADDu), Mips::SP) + .addReg(Mips::FP).addReg(Mips::ZERO); + + // lw $fp,stack_loc($sp) + BuildMI(MBB, MBBI, dl, TII.get(Mips::LW), Mips::FP) + .addImm(FPOffset).addReg(Mips::SP); + } + + // Restore the return address only if the function isnt a leaf one. + // lw $ra, stack_loc($sp) + if (MFI->hasCalls()) { + BuildMI(MBB, MBBI, dl, TII.get(Mips::LW), Mips::RA) + .addImm(RAOffset).addReg(Mips::SP); + } + + // adjust stack : insert addi sp, sp, (imm) + if (NumBytes) { + BuildMI(MBB, MBBI, dl, TII.get(Mips::ADDiu), Mips::SP) + .addReg(Mips::SP).addImm(NumBytes); + } +} + + +void MipsRegisterInfo:: +processFunctionBeforeFrameFinalized(MachineFunction &MF) const { + // Set the SPOffset on the FI where GP must be saved/loaded. + MachineFrameInfo *MFI = MF.getFrameInfo(); + bool isPIC = (MF.getTarget().getRelocationModel() == Reloc::PIC_); + if (MFI->hasCalls() && isPIC) { + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + MFI->setObjectOffset(MipsFI->getGPFI(), MipsFI->getGPStackOffset()); + } +} + +unsigned MipsRegisterInfo:: +getRARegister() const { + return Mips::RA; +} + +unsigned MipsRegisterInfo:: +getFrameRegister(MachineFunction &MF) const { + return hasFP(MF) ? Mips::FP : Mips::SP; +} + +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; +} + +int MipsRegisterInfo:: +getDwarfRegNum(unsigned RegNum, bool isEH) const { + assert(0 && "What is the dwarf register number"); + return -1; +} + +#include "MipsGenRegisterInfo.inc" + diff --git a/lib/Target/Mips/MipsRegisterInfo.h b/lib/Target/Mips/MipsRegisterInfo.h new file mode 100644 index 000000000000..808e995b4ed3 --- /dev/null +++ b/lib/Target/Mips/MipsRegisterInfo.h @@ -0,0 +1,78 @@ +//===- MipsRegisterInfo.h - Mips Register Information Impl ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSREGISTERINFO_H +#define MIPSREGISTERINFO_H + +#include "Mips.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "MipsGenRegisterInfo.h.inc" + +namespace llvm { +class MipsSubtarget; +class TargetInstrInfo; +class Type; + +struct MipsRegisterInfo : public MipsGenRegisterInfo { + const MipsSubtarget &Subtarget; + const TargetInstrInfo &TII; + + MipsRegisterInfo(const MipsSubtarget &Subtarget, const TargetInstrInfo &tii); + + /// getRegisterNumbering - Given the enum value for some register, e.g. + /// Mips::RA, return the number that it corresponds to (e.g. 31). + static unsigned getRegisterNumbering(unsigned RegEnum); + + /// Get PIC indirect call register + static unsigned getPICCallReg(void); + + /// Adjust the Mips stack frame. + void adjustMipsStackFrame(MachineFunction &MF) const; + + /// Code Generation virtual methods... + const unsigned *getCalleeSavedRegs(const MachineFunction* MF = 0) const; + + const TargetRegisterClass* const* + getCalleeSavedRegClasses(const MachineFunction* MF = 0) const; + + BitVector getReservedRegs(const MachineFunction &MF) const; + + bool hasFP(const MachineFunction &MF) const; + + void eliminateCallFramePseudoInstr(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + /// Stack Frame Processing Methods + 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; + + int getDwarfRegNum(unsigned RegNum, bool isEH) const; +}; + +} // end namespace llvm + +#endif diff --git a/lib/Target/Mips/MipsRegisterInfo.td b/lib/Target/Mips/MipsRegisterInfo.td new file mode 100644 index 000000000000..bbb275c66242 --- /dev/null +++ b/lib/Target/Mips/MipsRegisterInfo.td @@ -0,0 +1,252 @@ +//===- MipsRegisterInfo.td - Mips Register defs -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file 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<string n> : Register<n> { + field bits<5> Num; + let Namespace = "Mips"; +} + +// Mips CPU Registers +class MipsGPRReg<bits<5> num, string n> : MipsReg<n> { + let Num = num; +} + +// Mips 32-bit FPU Registers +class FPR<bits<5> num, string n> : MipsReg<n> { + let Num = num; +} + +// Mips 64-bit (aliased) FPU Registers +class AFPR<bits<5> num, string n, list<Register> aliases> : MipsReg<n> { + let Num = num; + let Aliases = aliases; +} + +//===----------------------------------------------------------------------===// +// Registers +//===----------------------------------------------------------------------===// + +let Namespace = "Mips" in { + + // General Purpose 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]>; + + /// Mips Single point precision FPU Registers + def F0 : FPR< 0, "F0">, DwarfRegNum<[32]>; + def F1 : FPR< 1, "F1">, DwarfRegNum<[33]>; + def F2 : FPR< 2, "F2">, DwarfRegNum<[34]>; + def F3 : FPR< 3, "F3">, DwarfRegNum<[35]>; + def F4 : FPR< 4, "F4">, DwarfRegNum<[36]>; + def F5 : FPR< 5, "F5">, DwarfRegNum<[37]>; + def F6 : FPR< 6, "F6">, DwarfRegNum<[38]>; + def F7 : FPR< 7, "F7">, DwarfRegNum<[39]>; + def F8 : FPR< 8, "F8">, DwarfRegNum<[40]>; + def F9 : FPR< 9, "F9">, DwarfRegNum<[41]>; + def F10 : FPR<10, "F10">, DwarfRegNum<[42]>; + def F11 : FPR<11, "F11">, DwarfRegNum<[43]>; + def F12 : FPR<12, "F12">, DwarfRegNum<[44]>; + def F13 : FPR<13, "F13">, DwarfRegNum<[45]>; + def F14 : FPR<14, "F14">, DwarfRegNum<[46]>; + def F15 : FPR<15, "F15">, DwarfRegNum<[47]>; + def F16 : FPR<16, "F16">, DwarfRegNum<[48]>; + def F17 : FPR<17, "F17">, DwarfRegNum<[49]>; + def F18 : FPR<18, "F18">, DwarfRegNum<[50]>; + def F19 : FPR<19, "F19">, DwarfRegNum<[51]>; + def F20 : FPR<20, "F20">, DwarfRegNum<[52]>; + def F21 : FPR<21, "F21">, DwarfRegNum<[53]>; + def F22 : FPR<22, "F22">, DwarfRegNum<[54]>; + def F23 : FPR<23, "F23">, DwarfRegNum<[55]>; + def F24 : FPR<24, "F24">, DwarfRegNum<[56]>; + def F25 : FPR<25, "F25">, DwarfRegNum<[57]>; + def F26 : FPR<26, "F26">, DwarfRegNum<[58]>; + def F27 : FPR<27, "F27">, DwarfRegNum<[59]>; + def F28 : FPR<28, "F28">, DwarfRegNum<[60]>; + def F29 : FPR<29, "F29">, DwarfRegNum<[61]>; + def F30 : FPR<30, "F30">, DwarfRegNum<[62]>; + def F31 : FPR<31, "F31">, DwarfRegNum<[63]>; + + /// Mips Double point precision FPU Registers (aliased + /// with the single precision to hold 64 bit values) + def D0 : AFPR< 0, "F0", [F0, F1]>, DwarfRegNum<[32]>; + def D1 : AFPR< 2, "F2", [F2, F3]>, DwarfRegNum<[34]>; + def D2 : AFPR< 4, "F4", [F4, F5]>, DwarfRegNum<[36]>; + def D3 : AFPR< 6, "F6", [F6, F7]>, DwarfRegNum<[38]>; + def D4 : AFPR< 8, "F8", [F8, F9]>, DwarfRegNum<[40]>; + def D5 : AFPR<10, "F10", [F10, F11]>, DwarfRegNum<[42]>; + def D6 : AFPR<12, "F12", [F12, F13]>, DwarfRegNum<[44]>; + def D7 : AFPR<14, "F14", [F14, F15]>, DwarfRegNum<[46]>; + def D8 : AFPR<16, "F16", [F16, F17]>, DwarfRegNum<[48]>; + def D9 : AFPR<18, "F18", [F18, F19]>, DwarfRegNum<[50]>; + def D10 : AFPR<20, "F20", [F20, F21]>, DwarfRegNum<[52]>; + def D11 : AFPR<22, "F22", [F22, F23]>, DwarfRegNum<[54]>; + def D12 : AFPR<24, "F24", [F24, F25]>, DwarfRegNum<[56]>; + def D13 : AFPR<26, "F26", [F26, F27]>, DwarfRegNum<[58]>; + def D14 : AFPR<28, "F28", [F28, F29]>, DwarfRegNum<[60]>; + def D15 : AFPR<30, "F30", [F30, F31]>, DwarfRegNum<[62]>; + + // Hi/Lo registers + def HI : Register<"hi">, DwarfRegNum<[64]>; + def LO : Register<"lo">, DwarfRegNum<[65]>; + + // Status flags register + def FCR31 : Register<"31">; +} + +//===----------------------------------------------------------------------===// +// Register Classes +//===----------------------------------------------------------------------===// + +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; + } + }]; +} + +// 64bit fp: +// * FGR64 - 32 64-bit registers +// * AFGR64 - 16 32-bit even registers (32-bit FP Mode) +// +// 32bit fp: +// * FGR32 - 16 32-bit even registers +// * FGR32 - 32 32-bit registers (single float only mode) +def FGR32 : RegisterClass<"Mips", [f32], 32, + // Return Values and Arguments + [F0, F1, F2, F3, F12, F13, F14, F15, + // Not preserved across procedure calls + F4, F5, F6, F7, F8, F9, F10, F11, F16, F17, F18, F19, + // Callee save + F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, + // Reserved + F31]> +{ + let MethodProtos = [{ + iterator allocation_order_begin(const MachineFunction &MF) const; + iterator allocation_order_end(const MachineFunction &MF) const; + }]; + let MethodBodies = [{ + + static const unsigned MIPS_FGR32[] = { + Mips::F0, Mips::F1, Mips::F2, Mips::F3, Mips::F12, Mips::F13, + Mips::F14, Mips::F15, Mips::F4, Mips::F5, Mips::F6, Mips::F7, + Mips::F8, Mips::F9, Mips::F10, Mips::F11, Mips::F16, Mips::F17, + Mips::F18, Mips::F19, Mips::F20, Mips::F21, Mips::F22, Mips::F23, + Mips::F24, Mips::F25, Mips::F26, Mips::F27, Mips::F28, Mips::F29, + Mips::F30 + }; + + static const unsigned MIPS_SVR4_FGR32[] = { + Mips::F0, Mips::F2, Mips::F12, Mips::F14, Mips::F4, + Mips::F6, Mips::F8, Mips::F10, Mips::F16, Mips::F18, + Mips::F20, Mips::F22, Mips::F24, Mips::F26, Mips::F28, Mips::F30, + }; + + FGR32Class::iterator + FGR32Class::allocation_order_begin(const MachineFunction &MF) const { + const TargetMachine &TM = MF.getTarget(); + const MipsSubtarget &Subtarget = TM.getSubtarget<MipsSubtarget>(); + + if (Subtarget.isSingleFloat()) + return MIPS_FGR32; + else + return MIPS_SVR4_FGR32; + } + + FGR32Class::iterator + FGR32Class::allocation_order_end(const MachineFunction &MF) const { + const TargetMachine &TM = MF.getTarget(); + const MipsSubtarget &Subtarget = TM.getSubtarget<MipsSubtarget>(); + + if (Subtarget.isSingleFloat()) + return MIPS_FGR32 + (sizeof(MIPS_FGR32) / sizeof(unsigned)); + else + return MIPS_SVR4_FGR32 + (sizeof(MIPS_SVR4_FGR32) / sizeof(unsigned)); + } + }]; +} + +def AFGR64 : RegisterClass<"Mips", [f64], 64, + // Return Values and Arguments + [D0, D1, D6, D7, + // Not preserved across procedure calls + D2, D3, D4, D5, D8, D9, + // Callee save + D10, D11, D12, D13, D14, + // Reserved + D15]> +{ + let MethodProtos = [{ + iterator allocation_order_end(const MachineFunction &MF) const; + }]; + let MethodBodies = [{ + AFGR64Class::iterator + AFGR64Class::allocation_order_end(const MachineFunction &MF) const { + // The last register on the list above is reserved + return end()-1; + } + }]; +} + +// Condition Register for floating point operations +def CCR : RegisterClass<"Mips", [i32], 32, [FCR31]>; + +// Hi/Lo Registers +def HILO : RegisterClass<"Mips", [i32], 32, [HI, LO]>; + diff --git a/lib/Target/Mips/MipsSchedule.td b/lib/Target/Mips/MipsSchedule.td new file mode 100644 index 000000000000..0c3ca57361cd --- /dev/null +++ b/lib/Target/Mips/MipsSchedule.td @@ -0,0 +1,63 @@ +//===- MipsSchedule.td - Mips Scheduling Definitions ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Functional units across Mips chips sets. Based on GCC/Mips backend files. +//===----------------------------------------------------------------------===// +def ALU : FuncUnit; +def IMULDIV : FuncUnit; + +//===----------------------------------------------------------------------===// +// Instruction Itinerary classes used for Mips +//===----------------------------------------------------------------------===// +def IIAlu : InstrItinClass; +def IILoad : InstrItinClass; +def IIStore : InstrItinClass; +def IIXfer : InstrItinClass; +def IIBranch : InstrItinClass; +def IIHiLo : InstrItinClass; +def IIImul : InstrItinClass; +def IIIdiv : InstrItinClass; +def IIFcvt : InstrItinClass; +def IIFmove : InstrItinClass; +def IIFcmp : InstrItinClass; +def IIFadd : InstrItinClass; +def IIFmulSingle : InstrItinClass; +def IIFmulDouble : InstrItinClass; +def IIFdivSingle : InstrItinClass; +def IIFdivDouble : InstrItinClass; +def IIFsqrtSingle : InstrItinClass; +def IIFsqrtDouble : InstrItinClass; +def IIFrecipFsqrtStep : InstrItinClass; +def IIPseudo : InstrItinClass; + +//===----------------------------------------------------------------------===// +// Mips Generic instruction itineraries. +//===----------------------------------------------------------------------===// +def MipsGenericItineraries : ProcessorItineraries<[ + InstrItinData<IIAlu , [InstrStage<1, [ALU]>]>, + InstrItinData<IILoad , [InstrStage<3, [ALU]>]>, + InstrItinData<IIStore , [InstrStage<1, [ALU]>]>, + InstrItinData<IIXfer , [InstrStage<2, [ALU]>]>, + InstrItinData<IIBranch , [InstrStage<1, [ALU]>]>, + InstrItinData<IIHiLo , [InstrStage<1, [IMULDIV]>]>, + InstrItinData<IIImul , [InstrStage<17, [IMULDIV]>]>, + InstrItinData<IIIdiv , [InstrStage<38, [IMULDIV]>]>, + InstrItinData<IIFcvt , [InstrStage<1, [ALU]>]>, + InstrItinData<IIFmove , [InstrStage<2, [ALU]>]>, + InstrItinData<IIFcmp , [InstrStage<3, [ALU]>]>, + InstrItinData<IIFadd , [InstrStage<4, [ALU]>]>, + InstrItinData<IIFmulSingle , [InstrStage<7, [ALU]>]>, + InstrItinData<IIFmulDouble , [InstrStage<8, [ALU]>]>, + InstrItinData<IIFdivSingle , [InstrStage<23, [ALU]>]>, + InstrItinData<IIFdivDouble , [InstrStage<36, [ALU]>]>, + InstrItinData<IIFsqrtSingle , [InstrStage<54, [ALU]>]>, + InstrItinData<IIFsqrtDouble , [InstrStage<12, [ALU]>]>, + InstrItinData<IIFrecipFsqrtStep , [InstrStage<5, [ALU]>]> +]>; diff --git a/lib/Target/Mips/MipsSubtarget.cpp b/lib/Target/Mips/MipsSubtarget.cpp new file mode 100644 index 000000000000..4245f274f8f0 --- /dev/null +++ b/lib/Target/Mips/MipsSubtarget.cpp @@ -0,0 +1,77 @@ +//===- MipsSubtarget.cpp - Mips Subtarget Information -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file 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" +#include "llvm/Module.h" +#include "llvm/Support/CommandLine.h" +using namespace llvm; + +static cl::opt<bool> +NotABICall("disable-mips-abicall", cl::Hidden, + cl::desc("Disable code for SVR4-style dynamic objects")); +static cl::opt<bool> +AbsoluteCall("enable-mips-absolute-call", cl::Hidden, + cl::desc("Enable absolute call within abicall")); +static cl::opt<unsigned> +SSThreshold("mips-ssection-threshold", cl::Hidden, + cl::desc("Small data and bss section threshold size (default=8)"), + cl::init(8)); + +MipsSubtarget::MipsSubtarget(const TargetMachine &TM, const Module &M, + const std::string &FS, bool little) : + MipsArchVersion(Mips1), MipsABI(O32), IsLittle(little), IsSingleFloat(false), + IsFP64bit(false), IsGP64bit(false), HasVFPU(false), HasABICall(true), + HasAbsoluteCall(false), IsLinux(true), HasSEInReg(false), HasCondMov(false), + HasMulDivAdd(false), HasMinMax(false), HasSwap(false), HasBitCount(false) +{ + std::string CPU = "mips1"; + MipsArchVersion = Mips1; + + // Parse features string. + ParseSubtargetFeatures(FS, CPU); + const std::string& TT = M.getTargetTriple(); + + // Small section size threshold + SSectionThreshold = SSThreshold; + + // Is the target system Linux ? + if (TT.find("linux") == std::string::npos) + IsLinux = false; + + // When only the target triple is specified and is + // a allegrex target, set the features. We also match + // big and little endian allegrex cores (dont really + // know if a big one exists) + if (TT.find("mipsallegrex") != std::string::npos || + TT.find("psp") != std::string::npos) { + MipsABI = EABI; + IsSingleFloat = true; + MipsArchVersion = Mips2; + HasVFPU = true; // Enables Allegrex Vector FPU (not supported yet) + HasSEInReg = true; + HasBitCount = true; + HasSwap = true; + HasCondMov = true; + } + + // Abicall is the default for O32 ABI, but is disabled within EABI and in + // static code. + if (NotABICall || isABI_EABI() || (TM.getRelocationModel() == Reloc::Static)) + HasABICall = false; + + // TODO: disable when handling 64 bit symbols in the future. + if (HasABICall && AbsoluteCall) + HasAbsoluteCall = true; +} diff --git a/lib/Target/Mips/MipsSubtarget.h b/lib/Target/Mips/MipsSubtarget.h new file mode 100644 index 000000000000..61c37c1d377e --- /dev/null +++ b/lib/Target/Mips/MipsSubtarget.h @@ -0,0 +1,139 @@ +//=====-- MipsSubtarget.h - Define Subtarget for the Mips -----*- C++ -*--====// +// +// The LLVM Compiler Infrastructure +// +// This file 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 <string> + +namespace llvm { +class Module; + +class MipsSubtarget : public TargetSubtarget { + +public: + enum MipsABIEnum { + O32, O64, N32, N64, EABI + }; + +protected: + + enum MipsArchEnum { + Mips1, Mips2, Mips3, Mips4, Mips32, Mips32r2, Mips64, Mips64r2 + }; + + // Mips architecture version + MipsArchEnum MipsArchVersion; + + // Mips supported ABIs + MipsABIEnum MipsABI; + + // IsLittle - The target is Little Endian + bool IsLittle; + + // IsSingleFloat - The target only supports single precision float + // point operations. This enable the target to use all 32 32-bit + // floating point registers instead of only using even ones. + bool IsSingleFloat; + + // IsFP64bit - The target processor has 64-bit floating point registers. + bool IsFP64bit; + + // IsFP64bit - General-purpose registers are 64 bits wide + bool IsGP64bit; + + // HasVFPU - Processor has a vector floating point unit. + bool HasVFPU; + + // IsABICall - Enable SRV4 code for SVR4-style dynamic objects + bool HasABICall; + + // HasAbsoluteCall - Enable code that is not fully position-independent. + // Only works with HasABICall enabled. + bool HasAbsoluteCall; + + // isLinux - Target system is Linux. Is false we consider ELFOS for now. + bool IsLinux; + + // Put global and static items less than or equal to SSectionThreshold + // bytes into the small data or bss section. The default is 8. + unsigned SSectionThreshold; + + /// Features related to the presence of specific instructions. + + // HasSEInReg - SEB and SEH (signext in register) instructions. + bool HasSEInReg; + + // HasCondMov - Conditional mov (MOVZ, MOVN) instructions. + bool HasCondMov; + + // HasMulDivAdd - Multiply add and sub (MADD, MADDu, MSUB, MSUBu) + // instructions. + bool HasMulDivAdd; + + // HasMinMax - MIN and MAX instructions. + bool HasMinMax; + + // HasSwap - Byte and half swap instructions. + bool HasSwap; + + // HasBitCount - Count leading '1' and '0' bits. + bool HasBitCount; + + InstrItineraryData InstrItins; + +public: + + /// Only O32 and EABI supported right now. + bool isABI_EABI() const { return MipsABI == EABI; } + bool isABI_O32() const { return MipsABI == O32; } + unsigned getTargetABI() const { return MipsABI; } + + /// This constructor initializes the data members to match that + /// of the specified module. + MipsSubtarget(const TargetMachine &TM, const Module &M, + const std::string &FS, bool little); + + /// ParseSubtargetFeatures - Parses features string setting specified + /// subtarget options. Definition of function is auto generated by tblgen. + std::string ParseSubtargetFeatures(const std::string &FS, + const std::string &CPU); + + bool isMips1() const { return MipsArchVersion == Mips1; } + + bool isLittle() const { return IsLittle; } + bool isFP64bit() const { return IsFP64bit; }; + bool isGP64bit() const { return IsGP64bit; }; + bool isGP32bit() const { return !IsGP64bit; }; + bool isSingleFloat() const { return IsSingleFloat; }; + bool isNotSingleFloat() const { return !IsSingleFloat; }; + bool hasVFPU() const { return HasVFPU; }; + bool hasABICall() const { return HasABICall; }; + bool hasAbsoluteCall() const { return HasAbsoluteCall; }; + bool isLinux() const { return IsLinux; }; + unsigned getSSectionThreshold() const { return SSectionThreshold; } + + /// Features related to the presence of specific instructions. + bool hasSEInReg() const { return HasSEInReg; }; + bool hasCondMov() const { return HasCondMov; }; + bool hasMulDivAdd() const { return HasMulDivAdd; }; + bool hasMinMax() const { return HasMinMax; }; + bool hasSwap() const { return HasSwap; }; + bool hasBitCount() const { return HasBitCount; }; +}; +} // End llvm namespace + +#endif diff --git a/lib/Target/Mips/MipsTargetAsmInfo.cpp b/lib/Target/Mips/MipsTargetAsmInfo.cpp new file mode 100644 index 000000000000..c197b0c2981c --- /dev/null +++ b/lib/Target/Mips/MipsTargetAsmInfo.cpp @@ -0,0 +1,98 @@ +//===-- MipsTargetAsmInfo.cpp - Mips asm properties -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file 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" +#include "MipsTargetMachine.h" +#include "llvm/GlobalVariable.h" + +using namespace llvm; + +MipsTargetAsmInfo::MipsTargetAsmInfo(const MipsTargetMachine &TM): + ELFTargetAsmInfo(TM) { + + Subtarget = &TM.getSubtarget<MipsSubtarget>(); + + AlignmentIsInBytes = false; + COMMDirectiveTakesAlignment = true; + Data16bitsDirective = "\t.half\t"; + Data32bitsDirective = "\t.word\t"; + Data64bitsDirective = NULL; + PrivateGlobalPrefix = "$"; + JumpTableDataSection = "\t.rdata"; + CommentString = "#"; + ZeroDirective = "\t.space\t"; + BSSSection = "\t.section\t.bss"; + CStringSection = ".rodata.str"; + + if (!Subtarget->hasABICall()) { + JumpTableDirective = "\t.word\t"; + SmallDataSection = getNamedSection("\t.sdata", SectionFlags::Writeable); + SmallBSSSection = getNamedSection("\t.sbss", + SectionFlags::Writeable | + SectionFlags::BSS); + } else + JumpTableDirective = "\t.gpword\t"; + +} + +unsigned MipsTargetAsmInfo:: +SectionFlagsForGlobal(const GlobalValue *GV, const char* Name) const { + unsigned Flags = ELFTargetAsmInfo::SectionFlagsForGlobal(GV, Name); + // Mask out Small Section flag bit, Mips doesnt support 's' section symbol + // for its small sections. + return (Flags & (~SectionFlags::Small)); +} + +SectionKind::Kind MipsTargetAsmInfo:: +SectionKindForGlobal(const GlobalValue *GV) const { + SectionKind::Kind K = ELFTargetAsmInfo::SectionKindForGlobal(GV); + + if (Subtarget->hasABICall()) + return K; + + if (K != SectionKind::Data && K != SectionKind::BSS && + K != SectionKind::RODataMergeConst) + return K; + + if (isa<GlobalVariable>(GV)) { + const TargetData *TD = TM.getTargetData(); + unsigned Size = TD->getTypeAllocSize(GV->getType()->getElementType()); + unsigned Threshold = Subtarget->getSSectionThreshold(); + + if (Size > 0 && Size <= Threshold) { + if (K == SectionKind::BSS) + return SectionKind::SmallBSS; + else + return SectionKind::SmallData; + } + } + + return K; +} + +const Section* MipsTargetAsmInfo:: +SelectSectionForGlobal(const GlobalValue *GV) const { + SectionKind::Kind K = SectionKindForGlobal(GV); + const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GV); + + if (GVA && (!GVA->isWeakForLinker())) + switch (K) { + case SectionKind::SmallData: + return getSmallDataSection(); + case SectionKind::SmallBSS: + return getSmallBSSSection(); + default: break; + } + + return ELFTargetAsmInfo::SelectSectionForGlobal(GV); +} diff --git a/lib/Target/Mips/MipsTargetAsmInfo.h b/lib/Target/Mips/MipsTargetAsmInfo.h new file mode 100644 index 000000000000..2b5a739e7219 --- /dev/null +++ b/lib/Target/Mips/MipsTargetAsmInfo.h @@ -0,0 +1,51 @@ +//=====-- MipsTargetAsmInfo.h - Mips asm properties -----------*- C++ -*--====// +// +// The LLVM Compiler Infrastructure +// +// This file 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 "MipsSubtarget.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/ELFTargetAsmInfo.h" + +namespace llvm { + + // Forward declaration. + class GlobalValue; + class MipsTargetMachine; + + struct MipsTargetAsmInfo : public ELFTargetAsmInfo { + explicit MipsTargetAsmInfo(const MipsTargetMachine &TM); + + /// SectionKindForGlobal - This hook allows the target to select proper + /// section kind used for global emission. + virtual SectionKind::Kind + SectionKindForGlobal(const GlobalValue *GV) const; + + /// SectionFlagsForGlobal - This hook allows the target to select proper + /// section flags either for given global or for section. + virtual unsigned + SectionFlagsForGlobal(const GlobalValue *GV = NULL, + const char* name = NULL) const; + + virtual const Section* SelectSectionForGlobal(const GlobalValue *GV) const; + + private: + const MipsSubtarget *Subtarget; + }; + +} // namespace llvm + +#endif diff --git a/lib/Target/Mips/MipsTargetMachine.cpp b/lib/Target/Mips/MipsTargetMachine.cpp new file mode 100644 index 000000000000..ef524e3ecd72 --- /dev/null +++ b/lib/Target/Mips/MipsTargetMachine.cpp @@ -0,0 +1,133 @@ +//===-- MipsTargetMachine.cpp - Define TargetMachine for Mips -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file 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; + +/// MipsTargetMachineModule - Note that this is used on hosts that +/// cannot link in a library unless there are references into the +/// library. In particular, it seems that it is not possible to get +/// things to work on Win32 without this. Though it is unused, do not +/// remove it. +extern "C" int MipsTargetMachineModule; +int MipsTargetMachineModule = 0; + +// Register the target. +static RegisterTarget<MipsTargetMachine> X("mips", "Mips"); +static RegisterTarget<MipselTargetMachine> Y("mipsel", "Mipsel"); + +const TargetAsmInfo *MipsTargetMachine:: +createTargetAsmInfo() const +{ + return new MipsTargetAsmInfo(*this); +} + +// DataLayout --> Big-endian, 32-bit pointer/ABI/alignment +// The stack is always 8 byte aligned +// On function prologue, the stack is created by decrementing +// its pointer. Once decremented, all references are done with positive +// offset from the stack/frame pointer, using StackGrowsUp enables +// an easier handling. +// Using CodeModel::Large enables different CALL behavior. +MipsTargetMachine:: +MipsTargetMachine(const Module &M, const std::string &FS, bool isLittle=false): + Subtarget(*this, M, FS, isLittle), + DataLayout(isLittle ? std::string("e-p:32:32:32-i8:8:32-i16:16:32") : + std::string("E-p:32:32:32-i8:8:32-i16:16:32")), + InstrInfo(*this), + FrameInfo(TargetFrameInfo::StackGrowsUp, 8, 0), + TLInfo(*this) +{ + // Abicall enables PIC by default + if (Subtarget.hasABICall()) + setRelocationModel(Reloc::PIC_); + + // TODO: create an option to enable long calls, like -mlong-calls, + // that would be our CodeModel::Large. It must not work with Abicall. + if (getCodeModel() == CodeModel::Default) + setCodeModel(CodeModel::Small); +} + +MipselTargetMachine:: +MipselTargetMachine(const Module &M, const std::string &FS) : + MipsTargetMachine(M, FS, true) {} + +// 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; + + if (TT.size() >= 13 && std::string(TT.begin(), + TT.begin()+13) == "mipsallegrex-") + return 20; + + return 0; +} + +// return 0 and must specify -march to gen MIPSEL code. +unsigned MipselTargetMachine:: +getModuleMatchQuality(const Module &M) +{ + // We strongly match "mips*el-*". + std::string TT = M.getTargetTriple(); + if (TT.size() >= 7 && std::string(TT.begin(), TT.begin()+7) == "mipsel-") + return 20; + + if (TT.size() >= 15 && std::string(TT.begin(), + TT.begin()+15) == "mipsallegrexel-") + return 20; + + if (TT.size() == 3 && std::string(TT.begin(), TT.begin()+3) == "psp") + return 20; + + return 0; +} + +// Install an instruction selector pass using +// the ISelDag to gen Mips code. +bool MipsTargetMachine:: +addInstSelector(PassManagerBase &PM, CodeGenOpt::Level OptLevel) +{ + 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. +bool MipsTargetMachine:: +addPreEmitPass(PassManagerBase &PM, CodeGenOpt::Level OptLevel) +{ + PM.add(createMipsDelaySlotFillerPass(*this)); + return true; +} + +// Implements the AssemblyEmitter for the target. Must return +// true if AssemblyEmitter is supported +bool MipsTargetMachine:: +addAssemblyEmitter(PassManagerBase &PM, CodeGenOpt::Level OptLevel, + bool Verbose, raw_ostream &Out) +{ + // Output assembly language. + PM.add(createMipsCodePrinterPass(Out, *this, OptLevel, Verbose)); + return false; +} diff --git a/lib/Target/Mips/MipsTargetMachine.h b/lib/Target/Mips/MipsTargetMachine.h new file mode 100644 index 000000000000..a9e1df27ae7f --- /dev/null +++ b/lib/Target/Mips/MipsTargetMachine.h @@ -0,0 +1,80 @@ +//===-- MipsTargetMachine.h - Define TargetMachine for Mips -00--*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file 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 raw_ostream; + + 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, bool isLittle); + + virtual const MipsInstrInfo *getInstrInfo() const + { return &InstrInfo; } + virtual const TargetFrameInfo *getFrameInfo() const + { return &FrameInfo; } + virtual const MipsSubtarget *getSubtargetImpl() const + { return &Subtarget; } + virtual const TargetData *getTargetData() const + { return &DataLayout;} + + virtual const MipsRegisterInfo *getRegisterInfo() const { + return &InstrInfo.getRegisterInfo(); + } + + virtual MipsTargetLowering *getTargetLowering() const { + return const_cast<MipsTargetLowering*>(&TLInfo); + } + + static unsigned getModuleMatchQuality(const Module &M); + + // Pass Pipeline Configuration + virtual bool addInstSelector(PassManagerBase &PM, + CodeGenOpt::Level OptLevel); + virtual bool addPreEmitPass(PassManagerBase &PM, + CodeGenOpt::Level OptLevel); + virtual bool addAssemblyEmitter(PassManagerBase &PM, + CodeGenOpt::Level OptLevel, + bool Verbose, raw_ostream &Out); + }; + +/// MipselTargetMachine - Mipsel target machine. +/// +class MipselTargetMachine : public MipsTargetMachine { +public: + MipselTargetMachine(const Module &M, const std::string &FS); + + static unsigned getModuleMatchQuality(const Module &M); +}; + +} // End llvm namespace + +#endif |
