diff options
Diffstat (limited to 'contrib/llvm/lib/Target/Mips')
35 files changed, 6562 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/Mips/AsmPrinter/CMakeLists.txt b/contrib/llvm/lib/Target/Mips/AsmPrinter/CMakeLists.txt new file mode 100644 index 0000000..d3099d2 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/AsmPrinter/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories( + ${CMAKE_CURRENT_BINARY_DIR}/.. + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ) + +add_llvm_library(LLVMMipsAsmPrinter + MipsAsmPrinter.cpp + ) +add_dependencies(LLVMMipsAsmPrinter MipsCodeGenTable_gen) diff --git a/contrib/llvm/lib/Target/Mips/AsmPrinter/Makefile b/contrib/llvm/lib/Target/Mips/AsmPrinter/Makefile new file mode 100644 index 0000000..b1efe9b --- /dev/null +++ b/contrib/llvm/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 +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/contrib/llvm/lib/Target/Mips/AsmPrinter/MipsAsmPrinter.cpp b/contrib/llvm/lib/Target/Mips/AsmPrinter/MipsAsmPrinter.cpp new file mode 100644 index 0000000..4d7fe4c --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/AsmPrinter/MipsAsmPrinter.cpp @@ -0,0 +1,365 @@ +//===-- 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/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetLoweringObjectFile.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetRegistry.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +namespace { + class MipsAsmPrinter : public AsmPrinter { + const MipsSubtarget *Subtarget; + public: + explicit MipsAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) + : AsmPrinter(TM, Streamer) { + 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, + raw_ostream &O); + void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O); + void printUnsignedImm(const MachineInstr *MI, int opNum, raw_ostream &O); + void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O, + const char *Modifier = 0); + void printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O, + const char *Modifier = 0); + void printSavedRegsBitmask(raw_ostream &O); + void printHex32(unsigned int Value, raw_ostream &O); + + const char *getCurrentABIString() const; + void emitFrameDirective(); + + void printInstruction(const MachineInstr *MI, raw_ostream &O); // autogen'd. + void EmitInstruction(const MachineInstr *MI) { + SmallString<128> Str; + raw_svector_ostream OS(Str); + printInstruction(MI, OS); + OutStreamer.EmitRawText(OS.str()); + } + virtual void EmitFunctionBodyStart(); + virtual void EmitFunctionBodyEnd(); + static const char *getRegisterName(unsigned RegNo); + + virtual void EmitFunctionEntryLabel(); + void EmitStartOfAsmFile(Module &M); + }; +} // end of anonymous namespace + +#include "MipsGenAsmWriter.inc" + +//===----------------------------------------------------------------------===// +// +// 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(raw_ostream &O) { + const TargetRegisterInfo &RI = *TM.getRegisterInfo(); + const 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 + const 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 (MFI->adjustsStack()) + CPUBitmask |= (1 << MipsRegisterInfo:: + getRegisterNumbering(RI.getRARegister())); + + // Print CPUBitmask + O << "\t.mask \t"; printHex32(CPUBitmask, O); + O << ',' << MipsFI->getCPUTopSavedRegOff() << '\n'; + + // Print FPUBitmask + O << "\t.fmask\t"; printHex32(FPUBitmask, O); O << "," + << MipsFI->getFPUTopSavedRegOff() << '\n'; +} + +// Print a 32 bit hex number with all numbers. +void MipsAsmPrinter::printHex32(unsigned Value, raw_ostream &O) { + 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() { + const TargetRegisterInfo &RI = *TM.getRegisterInfo(); + + unsigned stackReg = RI.getFrameRegister(*MF); + unsigned returnReg = RI.getRARegister(); + unsigned stackSize = MF->getFrameInfo()->getStackSize(); + + OutStreamer.EmitRawText("\t.frame\t$" + + Twine(LowercaseString(getRegisterName(stackReg))) + + "," + Twine(stackSize) + ",$" + + Twine(LowercaseString(getRegisterName(returnReg)))); +} + +/// Emit Set directives. +const char *MipsAsmPrinter::getCurrentABIString() const { + 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; + } + + llvm_unreachable("Unknown Mips ABI"); + return NULL; +} + +void MipsAsmPrinter::EmitFunctionEntryLabel() { + OutStreamer.EmitRawText("\t.ent\t" + Twine(CurrentFnSym->getName())); + OutStreamer.EmitLabel(CurrentFnSym); +} + +/// EmitFunctionBodyStart - Targets can override this to emit stuff before +/// the first basic block in the function. +void MipsAsmPrinter::EmitFunctionBodyStart() { + emitFrameDirective(); + + SmallString<128> Str; + raw_svector_ostream OS(Str); + printSavedRegsBitmask(OS); + OutStreamer.EmitRawText(OS.str()); +} + +/// EmitFunctionBodyEnd - Targets can override this to emit stuff after +/// the last basic block in the function. +void MipsAsmPrinter::EmitFunctionBodyEnd() { + // 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. + OutStreamer.EmitRawText(StringRef("\t.set\tmacro")); + OutStreamer.EmitRawText(StringRef("\t.set\treorder")); + OutStreamer.EmitRawText("\t.end\t" + Twine(CurrentFnSym->getName())); +} + + +// Print out an operand for an inline asm expression. +bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant,const char *ExtraCode, + raw_ostream &O) { + // Does this asm operand have a single letter operand modifier? + if (ExtraCode && ExtraCode[0]) + return true; // Unknown modifier. + + printOperand(MI, OpNo, O); + return false; +} + +void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(opNum); + bool closeP = false; + + if (MO.getTargetFlags()) + closeP = true; + + switch(MO.getTargetFlags()) { + case MipsII::MO_GPREL: O << "%gp_rel("; break; + case MipsII::MO_GOT_CALL: O << "%call16("; break; + case MipsII::MO_GOT: + if (MI->getOpcode() == Mips::LW) + O << "%got("; + else + O << "%lo("; + break; + case MipsII::MO_ABS_HILO: + if (MI->getOpcode() == Mips::LUi) + O << "%hi("; + else + O << "%lo("; + break; + } + + switch (MO.getType()) { + case MachineOperand::MO_Register: + O << '$' << LowercaseString(getRegisterName(MO.getReg())); + break; + + case MachineOperand::MO_Immediate: + O << (short int)MO.getImm(); + break; + + case MachineOperand::MO_MachineBasicBlock: + O << *MO.getMBB()->getSymbol(); + return; + + case MachineOperand::MO_GlobalAddress: + O << *Mang->getSymbol(MO.getGlobal()); + break; + + case MachineOperand::MO_ExternalSymbol: + O << *GetExternalSymbolSymbol(MO.getSymbolName()); + break; + + case MachineOperand::MO_JumpTableIndex: + O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() + << '_' << MO.getIndex(); + break; + + case MachineOperand::MO_ConstantPoolIndex: + O << MAI->getPrivateGlobalPrefix() << "CPI" + << getFunctionNumber() << "_" << MO.getIndex(); + if (MO.getOffset()) + O << "+" << MO.getOffset(); + break; + + default: + llvm_unreachable("<unknown operand type>"); + } + + if (closeP) O << ")"; +} + +void MipsAsmPrinter::printUnsignedImm(const MachineInstr *MI, int opNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(opNum); + if (MO.isImm()) + O << (unsigned short int)MO.getImm(); + else + printOperand(MI, opNum, O); +} + +void MipsAsmPrinter:: +printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O, + 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); + O << ", "; + printOperand(MI, opNum, O); + 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); + O << "("; + printOperand(MI, opNum+1, O); + O << ")"; +} + +void MipsAsmPrinter:: +printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O, + const char *Modifier) { + const MachineOperand& MO = MI->getOperand(opNum); + O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm()); +} + +void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) { + // FIXME: Use SwitchSection. + + // Tell the assembler which ABI we are using + OutStreamer.EmitRawText("\t.section .mdebug." + Twine(getCurrentABIString())); + + // TODO: handle O64 ABI + if (Subtarget->isABI_EABI()) { + if (Subtarget->isGP32bit()) + OutStreamer.EmitRawText(StringRef("\t.section .gcc_compiled_long32")); + else + OutStreamer.EmitRawText(StringRef("\t.section .gcc_compiled_long64")); + } + + // return to previous section + OutStreamer.EmitRawText(StringRef("\t.previous")); +} + +// Force static initialization. +extern "C" void LLVMInitializeMipsAsmPrinter() { + RegisterAsmPrinter<MipsAsmPrinter> X(TheMipsTarget); + RegisterAsmPrinter<MipsAsmPrinter> Y(TheMipselTarget); +} diff --git a/contrib/llvm/lib/Target/Mips/CMakeLists.txt b/contrib/llvm/lib/Target/Mips/CMakeLists.txt new file mode 100644 index 0000000..a77802a --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/CMakeLists.txt @@ -0,0 +1,26 @@ +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 + MipsMCAsmInfo.cpp + MipsRegisterInfo.cpp + MipsSubtarget.cpp + MipsTargetMachine.cpp + MipsTargetObjectFile.cpp + MipsSelectionDAGInfo.cpp + ) + +target_link_libraries (LLVMMipsCodeGen LLVMSelectionDAG) diff --git a/contrib/llvm/lib/Target/Mips/Makefile b/contrib/llvm/lib/Target/Mips/Makefile new file mode 100644 index 0000000..2ed8d77 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Makefile @@ -0,0 +1,24 @@ +##===- 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 TargetInfo + +include $(LEVEL)/Makefile.common + diff --git a/contrib/llvm/lib/Target/Mips/Mips.h b/contrib/llvm/lib/Target/Mips/Mips.h new file mode 100644 index 0000000..a9ab050 --- /dev/null +++ b/contrib/llvm/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 formatted_raw_ostream; + + FunctionPass *createMipsISelDag(MipsTargetMachine &TM); + FunctionPass *createMipsDelaySlotFillerPass(MipsTargetMachine &TM); + + extern Target TheMipsTarget; + extern Target TheMipselTarget; + +} // 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/contrib/llvm/lib/Target/Mips/Mips.td b/contrib/llvm/lib/Target/Mips/Mips.td new file mode 100644 index 0000000..aa036ae --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips.td @@ -0,0 +1,85 @@ +//===- 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; + +//===----------------------------------------------------------------------===// +// 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/contrib/llvm/lib/Target/Mips/MipsCallingConv.td b/contrib/llvm/lib/Target/Mips/MipsCallingConv.td new file mode 100644 index 0000000..c2bfb8f --- /dev/null +++ b/contrib/llvm/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, F2 + CCIfType<[f32], CCAssignToReg<[F0, F2]>>, + + // f64 are returned in register D0, D1 + CCIfType<[f64], CCIfSubtarget<"isNotSingleFloat()", CCAssignToReg<[D0, D1]>>> +]>; + +//===----------------------------------------------------------------------===// +// 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/contrib/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp b/contrib/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp new file mode 100644 index 0000000..a2b615d --- /dev/null +++ b/contrib/llvm/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/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp b/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp new file mode 100644 index 0000000..3888bbf --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp @@ -0,0 +1,535 @@ +//===-- 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 "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/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Instruction Selector Implementation +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// MipsDAGToDAGISel - MIPS specific code to select MIPS machine +// instructions for SelectionDAG operations. +//===----------------------------------------------------------------------===// +namespace { + +class 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>()) {} + + // 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" + + /// getTargetMachine - Return a reference to the TargetMachine, casted + /// to the target-specific type. + const MipsTargetMachine &getTargetMachine() { + return static_cast<const MipsTargetMachine &>(TM); + } + + /// getInstrInfo - Return a reference to the TargetInstrInfo, casted + /// to the target-specific type. + const MipsInstrInfo *getInstrInfo() { + return getTargetMachine().getInstrInfo(); + } + + SDNode *getGlobalBaseReg(); + SDNode *Select(SDNode *N); + + // Complex Pattern. + bool SelectAddr(SDNode *Op, SDValue N, + SDValue &Base, SDValue &Offset); + + SDNode *SelectLoadFp64(SDNode *N); + SDNode *SelectStoreFp64(SDNode *N); + + // getI32Imm - Return a target constant with the specified + // value, of type i32. + inline SDValue getI32Imm(unsigned Imm) { + return CurDAG->getTargetConstant(Imm, MVT::i32); + } +}; + +} + + +/// getGlobalBaseReg - Output the instructions required to put the +/// GOT address into a register. +SDNode *MipsDAGToDAGISel::getGlobalBaseReg() { + unsigned GlobalBaseReg = getInstrInfo()->getGlobalBaseReg(MF); + return CurDAG->getRegister(GlobalBaseReg, TLI.getPointerTy()).getNode(); +} + +/// ComplexPattern used on MipsInstrInfo +/// Used on Mips Load/Store instructions +bool MipsDAGToDAGISel:: +SelectAddr(SDNode *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::TargetConstantPool) || + (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; + } + } + + // When loading from constant pools, load the lower address part in + // the instruction itself. Example, instead of: + // lui $2, %hi($CPI1_0) + // addiu $2, $2, %lo($CPI1_0) + // lwc1 $f0, 0($2) + // Generate: + // lui $2, %hi($CPI1_0) + // lwc1 $f0, %lo($CPI1_0)($2) + if ((Addr.getOperand(0).getOpcode() == MipsISD::Hi || + Addr.getOperand(0).getOpcode() == ISD::LOAD) && + Addr.getOperand(1).getOpcode() == MipsISD::Lo) { + SDValue LoVal = Addr.getOperand(1); + if (dyn_cast<ConstantPoolSDNode>(LoVal.getOperand(0))) { + Base = Addr.getOperand(0); + Offset = LoVal.getOperand(0); + return true; + } + } + } + + Base = Addr; + Offset = CurDAG->getTargetConstant(0, MVT::i32); + return true; +} + +SDNode *MipsDAGToDAGISel::SelectLoadFp64(SDNode *N) { + MVT::SimpleValueType NVT = + N->getValueType(0).getSimpleVT().SimpleTy; + + if (!Subtarget.isMips1() || NVT != MVT::f64) + return NULL; + + if (!Predicate_unindexedload(N) || + !Predicate_load(N)) + return NULL; + + SDValue Chain = N->getOperand(0); + SDValue N1 = N->getOperand(1); + SDValue Offset0, Offset1, Base; + + if (!SelectAddr(N, N1, Offset0, Base) || + N1.getValueType() != MVT::i32) + return NULL; + + MachineSDNode::mmo_iterator MemRefs0 = MF->allocateMemRefsArray(1); + MemRefs0[0] = cast<MemSDNode>(N)->getMemOperand(); + DebugLoc dl = N->getDebugLoc(); + + // The second load should start after for 4 bytes. + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Offset0)) + Offset1 = CurDAG->getTargetConstant(C->getSExtValue()+4, MVT::i32); + else if (ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(Offset0)) + Offset1 = CurDAG->getTargetConstantPool(CP->getConstVal(), + MVT::i32, + CP->getAlignment(), + CP->getOffset()+4, + CP->getTargetFlags()); + else + return NULL; + + // Choose the offsets depending on the endianess + if (TM.getTargetData()->isBigEndian()) + std::swap(Offset0, Offset1); + + // Instead of: + // ldc $f0, X($3) + // Generate: + // lwc $f0, X($3) + // lwc $f1, X+4($3) + SDNode *LD0 = CurDAG->getMachineNode(Mips::LWC1, dl, MVT::f32, + MVT::Other, Offset0, Base, Chain); + SDValue Undef = SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, + dl, NVT), 0); + SDValue I0 = CurDAG->getTargetInsertSubreg(Mips::sub_fpeven, dl, + MVT::f64, Undef, SDValue(LD0, 0)); + + SDNode *LD1 = CurDAG->getMachineNode(Mips::LWC1, dl, MVT::f32, + MVT::Other, Offset1, Base, SDValue(LD0, 1)); + SDValue I1 = CurDAG->getTargetInsertSubreg(Mips::sub_fpodd, dl, + MVT::f64, I0, SDValue(LD1, 0)); + + ReplaceUses(SDValue(N, 0), I1); + ReplaceUses(SDValue(N, 1), Chain); + cast<MachineSDNode>(LD0)->setMemRefs(MemRefs0, MemRefs0 + 1); + cast<MachineSDNode>(LD1)->setMemRefs(MemRefs0, MemRefs0 + 1); + return I1.getNode(); +} + +SDNode *MipsDAGToDAGISel::SelectStoreFp64(SDNode *N) { + + if (!Subtarget.isMips1() || + N->getOperand(1).getValueType() != MVT::f64) + return NULL; + + SDValue Chain = N->getOperand(0); + + if (!Predicate_unindexedstore(N) || + !Predicate_store(N)) + return NULL; + + SDValue N1 = N->getOperand(1); + SDValue N2 = N->getOperand(2); + SDValue Offset0, Offset1, Base; + + if (!SelectAddr(N, N2, Offset0, Base) || + N1.getValueType() != MVT::f64 || + N2.getValueType() != MVT::i32) + return NULL; + + MachineSDNode::mmo_iterator MemRefs0 = MF->allocateMemRefsArray(1); + MemRefs0[0] = cast<MemSDNode>(N)->getMemOperand(); + DebugLoc dl = N->getDebugLoc(); + + // Get the even and odd part from the f64 register + SDValue FPOdd = CurDAG->getTargetExtractSubreg(Mips::sub_fpodd, + dl, MVT::f32, N1); + SDValue FPEven = CurDAG->getTargetExtractSubreg(Mips::sub_fpeven, + dl, MVT::f32, N1); + + // The second store should start after for 4 bytes. + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Offset0)) + Offset1 = CurDAG->getTargetConstant(C->getSExtValue()+4, MVT::i32); + else + return NULL; + + // Choose the offsets depending on the endianess + if (TM.getTargetData()->isBigEndian()) + std::swap(Offset0, Offset1); + + // Instead of: + // sdc $f0, X($3) + // Generate: + // swc $f0, X($3) + // swc $f1, X+4($3) + SDValue Ops0[] = { FPEven, Offset0, Base, Chain }; + Chain = SDValue(CurDAG->getMachineNode(Mips::SWC1, dl, + MVT::Other, Ops0, 4), 0); + cast<MachineSDNode>(Chain.getNode())->setMemRefs(MemRefs0, MemRefs0 + 1); + + SDValue Ops1[] = { FPOdd, Offset1, Base, Chain }; + Chain = SDValue(CurDAG->getMachineNode(Mips::SWC1, dl, + MVT::Other, Ops1, 4), 0); + cast<MachineSDNode>(Chain.getNode())->setMemRefs(MemRefs0, MemRefs0 + 1); + + ReplaceUses(SDValue(N, 0), Chain); + return Chain.getNode(); +} + +/// Select instructions not customized! Used for +/// expanded, promoted and normal instructions +SDNode* MipsDAGToDAGISel::Select(SDNode *Node) { + unsigned Opcode = Node->getOpcode(); + DebugLoc dl = Node->getDebugLoc(); + + // Dump information about the Node being selected + DEBUG(errs() << "Selecting: "; Node->dump(CurDAG); errs() << "\n"); + + // If we have a custom node, we already have selected! + if (Node->isMachineOpcode()) { + DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n"); + 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); + + EVT VT = LHS.getValueType(); + SDNode *Carry = CurDAG->getMachineNode(Mips::SLTu, dl, VT, Ops, 2); + SDNode *AddCarry = CurDAG->getMachineNode(Mips::ADDu, dl, VT, + SDValue(Carry,0), RHS); + + return CurDAG->SelectNodeTo(Node, 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 *MulDiv = CurDAG->getMachineNode(Op, dl, MVT::Flag, Op1, Op2); + + SDValue InFlag = SDValue(MulDiv, 0); + SDNode *Lo = CurDAG->getMachineNode(Mips::MFLO, dl, MVT::i32, + MVT::Flag, InFlag); + InFlag = SDValue(Lo,1); + SDNode *Hi = CurDAG->getMachineNode(Mips::MFHI, dl, MVT::i32, InFlag); + + if (!SDValue(Node, 0).use_empty()) + ReplaceUses(SDValue(Node, 0), SDValue(Lo,0)); + + if (!SDValue(Node, 1).use_empty()) + ReplaceUses(SDValue(Node, 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->getMachineNode(MulOp, dl, + MVT::Flag, MulOp1, MulOp2); + + SDValue InFlag = SDValue(MulNode, 0); + + if (Opcode == ISD::MUL) + return CurDAG->getMachineNode(Mips::MFLO, dl, MVT::i32, InFlag); + else + return CurDAG->getMachineNode(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->getMachineNode(Op, dl, MVT::Flag, Op1, Op2); + + SDValue InFlag = SDValue(Node, 0); + return CurDAG->getMachineNode(MOp, dl, MVT::i32, InFlag); + } + + // Get target GOT address. + case ISD::GLOBAL_OFFSET_TABLE: + return getGlobalBaseReg(); + + case ISD::ConstantFP: { + ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(Node); + if (Node->getValueType(0) == MVT::f64 && CN->isExactlyValue(+0.0)) { + SDValue Zero = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl, + Mips::ZERO, MVT::i32); + SDValue Undef = SDValue( + CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, MVT::f64), 0); + SDNode *MTC = CurDAG->getMachineNode(Mips::MTC1, dl, MVT::f32, Zero); + SDValue I0 = CurDAG->getTargetInsertSubreg(Mips::sub_fpeven, dl, + MVT::f64, Undef, SDValue(MTC, 0)); + SDValue I1 = CurDAG->getTargetInsertSubreg(Mips::sub_fpodd, dl, + MVT::f64, I0, SDValue(MTC, 0)); + ReplaceUses(SDValue(Node, 0), I1); + return I1.getNode(); + } + break; + } + + case ISD::LOAD: + if (SDNode *ResNode = SelectLoadFp64(Node)) + return ResNode; + // Other cases are autogenerated. + break; + + case ISD::STORE: + if (SDNode *ResNode = SelectStoreFp64(Node)) + return ResNode; + // Other cases are autogenerated. + break; + + /// 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_) { + unsigned LastOpNum = Node->getNumOperands()-1; + + SDValue Chain = Node->getOperand(0); + SDValue Callee = Node->getOperand(1); + SDValue InFlag; + + // Skip the incomming flag if present + if (Node->getOperand(LastOpNum).getValueType() == MVT::Flag) + LastOpNum--; + + 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->getMachineNode(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, Mips::T9, Load, InFlag); + } else + /// Indirect call + Chain = CurDAG->getCopyToReg(Chain, dl, Mips::T9, Callee, InFlag); + + // Map the JmpLink operands to JALR + SDVTList NodeTys = CurDAG->getVTList(MVT::Other, MVT::Flag); + SmallVector<SDValue, 8> Ops; + Ops.push_back(CurDAG->getRegister(Mips::T9, MVT::i32)); + + for (unsigned i = 2, e = LastOpNum+1; i != e; ++i) + Ops.push_back(Node->getOperand(i)); + Ops.push_back(Chain); + Ops.push_back(Chain.getValue(1)); + + // Emit Jump and Link Register + SDNode *ResNode = CurDAG->getMachineNode(Mips::JALR, dl, NodeTys, + &Ops[0], Ops.size()); + + // Replace Chain and InFlag + ReplaceUses(SDValue(Node, 0), SDValue(ResNode, 0)); + ReplaceUses(SDValue(Node, 1), SDValue(ResNode, 1)); + return ResNode; + } + } + } + + // Select the default instruction + SDNode *ResNode = SelectCode(Node); + + DEBUG(errs() << "=> "); + if (ResNode == NULL || ResNode == Node) + DEBUG(Node->dump(CurDAG)); + else + DEBUG(ResNode->dump(CurDAG)); + DEBUG(errs() << "\n"); + 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/contrib/llvm/lib/Target/Mips/MipsISelLowering.cpp b/contrib/llvm/lib/Target/Mips/MipsISelLowering.cpp new file mode 100644 index 0000000..e979c3f --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsISelLowering.cpp @@ -0,0 +1,1339 @@ +//===-- 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 "MipsTargetObjectFile.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" +#include "llvm/Support/ErrorHandling.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, new MipsTargetObjectFile()) { + Subtarget = &TM.getSubtarget<MipsSubtarget>(); + + // Mips does not have i1 type, so use i32 for + // setcc operations results (slt, sgt, ...). + setBooleanContents(ZeroOrOneBooleanContent); + + // 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); + + // 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); + + // MIPS doesn't have extending float->double load/store + setLoadExtAction(ISD::EXTLOAD, MVT::f32, Expand); + setTruncStoreAction(MVT::f64, MVT::f32, Expand); + + // 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::JumpTable, MVT::i32, Custom); + setOperationAction(ISD::ConstantPool, MVT::i32, Custom); + setOperationAction(ISD::SELECT, MVT::f32, Custom); + setOperationAction(ISD::SELECT, MVT::f64, 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); + setOperationAction(ISD::VASTART, MVT::Other, 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::ROTR, 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); + setOperationAction(ISD::FCOPYSIGN, MVT::f64, Expand); + setOperationAction(ISD::FSIN, MVT::f32, Expand); + setOperationAction(ISD::FCOS, MVT::f32, Expand); + setOperationAction(ISD::FPOWI, MVT::f32, Expand); + setOperationAction(ISD::FPOW, MVT::f32, Expand); + setOperationAction(ISD::FLOG, MVT::f32, Expand); + setOperationAction(ISD::FLOG2, MVT::f32, Expand); + setOperationAction(ISD::FLOG10, MVT::f32, Expand); + setOperationAction(ISD::FEXP, MVT::f32, 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::SimpleValueType MipsTargetLowering::getSetCCResultType(EVT VT) const { + return MVT::i32; +} + +/// getFunctionAlignment - Return the Log2 alignment of this function. +unsigned MipsTargetLowering::getFunctionAlignment(const Function *) const { + return 2; +} + +SDValue MipsTargetLowering:: +LowerOperation(SDValue Op, SelectionDAG &DAG) const +{ + switch (Op.getOpcode()) + { + case ISD::AND: return LowerANDOR(Op, DAG); + case ISD::BRCOND: return LowerBRCOND(Op, DAG); + case ISD::ConstantPool: return LowerConstantPool(Op, DAG); + case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(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::SELECT: return LowerSELECT(Op, DAG); + case ISD::SETCC: return LowerSETCC(Op, DAG); + case ISD::VASTART: return LowerVASTART(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; +} + +// 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: + llvm_unreachable("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: llvm_unreachable("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) const +{ + 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) const +{ + 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) const +{ + 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) const +{ + // 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) const +{ + // 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) const +{ + 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) const { + // FIXME there isn't actually debug info here + DebugLoc dl = Op.getDebugLoc(); + const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal(); + + if (getTargetMachine().getRelocationModel() != Reloc::PIC_) { + SDVTList VTs = DAG.getVTList(MVT::i32); + + MipsTargetObjectFile &TLOF = (MipsTargetObjectFile&)getObjFileLowering(); + + // %gp_rel relocation + if (TLOF.IsGlobalInSmallSection(GV, getTargetMachine())) { + SDValue GA = DAG.getTargetGlobalAddress(GV, MVT::i32, 0, + MipsII::MO_GPREL); + SDValue GPRelNode = DAG.getNode(MipsISD::GPRel, dl, VTs, &GA, 1); + SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(MVT::i32); + return DAG.getNode(ISD::ADD, dl, MVT::i32, GOT, GPRelNode); + } + // %hi/%lo relocation + SDValue GA = DAG.getTargetGlobalAddress(GV, MVT::i32, 0, + MipsII::MO_ABS_HILO); + SDValue HiPart = DAG.getNode(MipsISD::Hi, dl, VTs, &GA, 1); + SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, GA); + return DAG.getNode(ISD::ADD, dl, MVT::i32, HiPart, Lo); + + } else { + SDValue GA = DAG.getTargetGlobalAddress(GV, MVT::i32, 0, + MipsII::MO_GOT); + SDValue ResNode = DAG.getLoad(MVT::i32, dl, + DAG.getEntryNode(), GA, NULL, 0, + false, false, 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); + } + + llvm_unreachable("Dont know how to handle GlobalAddress"); + return SDValue(0,0); +} + +SDValue MipsTargetLowering:: +LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const +{ + llvm_unreachable("TLS not implemented for MIPS."); + return SDValue(); // Not reached +} + +SDValue MipsTargetLowering:: +LowerJumpTable(SDValue Op, SelectionDAG &DAG) const +{ + SDValue ResNode; + SDValue HiPart; + // FIXME there isn't actually debug info here + DebugLoc dl = Op.getDebugLoc(); + bool IsPIC = getTargetMachine().getRelocationModel() == Reloc::PIC_; + unsigned char OpFlag = IsPIC ? MipsII::MO_GOT : MipsII::MO_ABS_HILO; + + EVT PtrVT = Op.getValueType(); + JumpTableSDNode *JT = cast<JumpTableSDNode>(Op); + + SDValue JTI = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, OpFlag); + + if (IsPIC) { + SDValue Ops[] = { JTI }; + HiPart = DAG.getNode(MipsISD::Hi, dl, DAG.getVTList(MVT::i32), Ops, 1); + } else // Emit Load from Global Pointer + HiPart = DAG.getLoad(MVT::i32, dl, DAG.getEntryNode(), JTI, NULL, 0, + false, false, 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) const +{ + SDValue ResNode; + ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op); + const Constant *C = N->getConstVal(); + // 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 (IsInSmallSection(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); + + if (getTargetMachine().getRelocationModel() != Reloc::PIC_) { + SDValue CP = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment(), + N->getOffset(), MipsII::MO_ABS_HILO); + 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); + } else { + SDValue CP = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment(), + N->getOffset(), MipsII::MO_GOT); + SDValue Load = DAG.getLoad(MVT::i32, dl, DAG.getEntryNode(), + CP, NULL, 0, false, false, 0); + SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, CP); + ResNode = DAG.getNode(ISD::ADD, dl, MVT::i32, Load, Lo); + } + + return ResNode; +} + +SDValue MipsTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const { + MachineFunction &MF = DAG.getMachineFunction(); + MipsFunctionInfo *FuncInfo = MF.getInfo<MipsFunctionInfo>(); + + DebugLoc dl = Op.getDebugLoc(); + SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), + getPointerTy()); + + // vastart just stores the address of the VarArgsFrameIndex slot into the + // memory location argument. + const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); + return DAG.getStore(Op.getOperand(0), dl, FI, Op.getOperand(1), SV, 0, + false, false, 0); +} + +//===----------------------------------------------------------------------===// +// Calling Convention Implementation +//===----------------------------------------------------------------------===// + +#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, EVT ValVT, + EVT 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 +} + +static bool CC_MipsO32_VarArgs(unsigned ValNo, EVT ValVT, + EVT LocVT, CCValAssign::LocInfo LocInfo, + ISD::ArgFlagsTy ArgFlags, CCState &State) { + + static const unsigned IntRegsSize=4; + + static const unsigned IntRegs[] = { + Mips::A0, Mips::A1, Mips::A2, Mips::A3 + }; + + // 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) { + if (unsigned Reg = State.AllocateReg(IntRegs, IntRegsSize)) { + State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, MVT::i32, LocInfo)); + return false; + } + unsigned Off = State.AllocateStack(4, 4); + State.addLoc(CCValAssign::getMem(ValNo, ValVT, Off, LocVT, LocInfo)); + return false; + } + + unsigned UnallocIntReg = State.getFirstUnallocated(IntRegs, IntRegsSize); + if (ValVT == MVT::f64) { + if (IntRegs[UnallocIntReg] == (unsigned (Mips::A1))) { + // A1 can't be used anymore, because 64 bit arguments + // must be aligned when copied back to the caller stack + State.AllocateReg(IntRegs, IntRegsSize); + UnallocIntReg++; + } + + if (IntRegs[UnallocIntReg] == (unsigned (Mips::A0)) || + IntRegs[UnallocIntReg] == (unsigned (Mips::A2))) { + unsigned Reg = State.AllocateReg(IntRegs, IntRegsSize); + State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, MVT::i32, LocInfo)); + // Shadow the next register so it can be used + // later to get the other 32bit part. + State.AllocateReg(IntRegs, IntRegsSize); + return false; + } + + // Register is shadowed to preserve alignment, and the + // argument goes to a stack location. + if (UnallocIntReg != IntRegsSize) + State.AllocateReg(IntRegs, IntRegsSize); + + unsigned Off = State.AllocateStack(8, 8); + State.addLoc(CCValAssign::getMem(ValNo, ValVT, Off, LocVT, LocInfo)); + return false; + } + + return true; // CC didn't 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: isTailCall. +SDValue +MipsTargetLowering::LowerCall(SDValue Chain, SDValue Callee, + CallingConv::ID CallConv, bool isVarArg, + bool &isTailCall, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const { + // MIPs target does not yet support tail call optimization. + isTailCall = false; + + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + bool IsPIC = getTargetMachine().getRelocationModel() == Reloc::PIC_; + + // Analyze operands of the call, assigning locations to each operand. + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CallConv, isVarArg, getTargetMachine(), ArgLocs, + *DAG.getContext()); + + // 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 = EVT(MVT::i32).getSizeInBits()/8; + MFI->CreateFixedObject(VTsize, (VTsize*3), true, false); + CCInfo.AnalyzeCallOperands(Outs, + isVarArg ? CC_MipsO32_VarArgs : CC_MipsO32); + } else + CCInfo.AnalyzeCallOperands(Outs, 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 = Outs[i].Val; + CCValAssign &VA = ArgLocs[i]; + + // Promote the value if needed. + switch (VA.getLocInfo()) { + default: llvm_unreachable("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, true, false); + + 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, + false, false, 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. + unsigned char OpFlag = IsPIC ? MipsII::MO_GOT_CALL : MipsII::MO_NO_FLAG; + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), + getPointerTy(), 0, OpFlag); + else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) + Callee = DAG.getTargetExternalSymbol(S->getSymbol(), + getPointerTy(), OpFlag); + + // 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 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 (IsPIC) { + // 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, true, false); + 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, + false, false, 0); + Chain = GPLoad.getValue(1); + Chain = DAG.getCopyToReg(Chain, dl, DAG.getRegister(Mips::GP, MVT::i32), + GPLoad, SDValue(0,0)); + 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); + + // Handle result values, copying them out of physregs into vregs that we + // return. + return LowerCallResult(Chain, InFlag, CallConv, isVarArg, + Ins, dl, DAG, InVals); +} + +/// LowerCallResult - Lower the result values of a call into the +/// appropriate copies out of appropriate physical registers. +SDValue +MipsTargetLowering::LowerCallResult(SDValue Chain, SDValue InFlag, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const { + + // Assign locations to each value returned by this call. + SmallVector<CCValAssign, 16> RVLocs; + CCState CCInfo(CallConv, isVarArg, getTargetMachine(), + RVLocs, *DAG.getContext()); + + CCInfo.AnalyzeCallResult(Ins, RetCC_Mips); + + // 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); + InVals.push_back(Chain.getValue(0)); + } + + return Chain; +} + +//===----------------------------------------------------------------------===// +// Formal Arguments Calling Convention Implementation +//===----------------------------------------------------------------------===// + +/// LowerFormalArguments - transform physical registers into virtual registers +/// and generate load operations for arguments places on the stack. +SDValue +MipsTargetLowering::LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> + &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) + const { + + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + unsigned StackReg = MF.getTarget().getRegisterInfo()->getFrameRegister(MF); + MipsFI->setVarArgsFrameIndex(0); + + // Used with vargs to acumulate store chains. + std::vector<SDValue> OutChains; + + // Keep track of the last register used for arguments + unsigned ArgRegEnd = 0; + + // Assign locations to all of the incoming arguments. + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CallConv, isVarArg, getTargetMachine(), + ArgLocs, *DAG.getContext()); + + if (Subtarget->isABI_O32()) + CCInfo.AnalyzeFormalArguments(Ins, + isVarArg ? CC_MipsO32_VarArgs : CC_MipsO32); + else + CCInfo.AnalyzeFormalArguments(Ins, CC_Mips); + + 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()) { + EVT RegVT = VA.getLocVT(); + ArgRegEnd = VA.getLocReg(); + 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 + llvm_unreachable("RegVT not supported by FormalArguments Lowering"); + + // Transform the arguments stored on + // physical registers into virtual ones + unsigned Reg = AddLiveIn(DAG.getMachineFunction(), ArgRegEnd, RC); + SDValue ArgValue = DAG.getCopyFromReg(Chain, 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(Chain, 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); + } + } + + InVals.push_back(ArgValue); + } else { // VA.isRegLoc() + + // sanity check + assert(VA.isMemLoc()); + + // The last argument is not a register anymore + ArgRegEnd = 0; + + // 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, true, false); + MipsFI->recordLoadArgsFI(FI, -(ArgSize+ + (FirstStackArgLoc + VA.getLocMemOffset()))); + + // Create load nodes to retrieve arguments from the stack + SDValue FIN = DAG.getFrameIndex(FI, getPointerTy()); + InVals.push_back(DAG.getLoad(VA.getValVT(), dl, Chain, FIN, NULL, 0, + false, false, 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, InVals[0]); + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Copy, Chain); + } + + // To meet ABI, when VARARGS are passed on registers, the registers + // must have their values written to the caller stack frame. If the last + // argument was placed in the stack, there's no need to save any register. + if ((isVarArg) && (Subtarget->isABI_O32() && ArgRegEnd)) { + if (StackPtr.getNode() == 0) + StackPtr = DAG.getRegister(StackReg, getPointerTy()); + + // The last register argument that must be saved is Mips::A3 + TargetRegisterClass *RC = Mips::CPURegsRegisterClass; + unsigned StackLoc = ArgLocs.size()-1; + + for (++ArgRegEnd; ArgRegEnd <= Mips::A3; ++ArgRegEnd, ++StackLoc) { + unsigned Reg = AddLiveIn(DAG.getMachineFunction(), ArgRegEnd, RC); + SDValue ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, MVT::i32); + + int FI = MFI->CreateFixedObject(4, 0, true, false); + MipsFI->recordStoreVarArgsFI(FI, -(4+(StackLoc*4))); + SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy()); + OutChains.push_back(DAG.getStore(Chain, dl, ArgValue, PtrOff, NULL, 0, + false, false, 0)); + + // Record the frame index of the first variable argument + // which is a value necessary to VASTART. + if (!MipsFI->getVarArgsFrameIndex()) + MipsFI->setVarArgsFrameIndex(FI); + } + } + + // All stores are grouped in one node to allow the matching between + // the size of Ins and InVals. This only happens when on varg functions + if (!OutChains.empty()) { + OutChains.push_back(Chain); + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + &OutChains[0], OutChains.size()); + } + + return Chain; +} + +//===----------------------------------------------------------------------===// +// Return Value Calling Convention Implementation +//===----------------------------------------------------------------------===// + +SDValue +MipsTargetLowering::LowerReturn(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + DebugLoc dl, SelectionDAG &DAG) const { + + // CCValAssign - represent the assignment of + // the return value to a location + SmallVector<CCValAssign, 16> RVLocs; + + // CCState - Info about the registers and stack slot. + CCState CCInfo(CallConv, isVarArg, getTargetMachine(), + RVLocs, *DAG.getContext()); + + // Analize return values. + CCInfo.AnalyzeReturn(Outs, 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()); + } + + 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!"); + + Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), + Outs[i].Val, 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) + llvm_unreachable("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, EVT 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, + EVT 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; +} + +bool MipsTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const { + if (VT != MVT::f32 && VT != MVT::f64) + return false; + return Imm.isZero(); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsISelLowering.h b/contrib/llvm/lib/Target/Mips/MipsISelLowering.h new file mode 100644 index 0000000..f2de489 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsISelLowering.h @@ -0,0 +1,157 @@ +//===-- 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 { + public: + explicit MipsTargetLowering(MipsTargetMachine &TM); + + /// LowerOperation - Provide custom lowering hooks for some operations. + virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const; + + /// 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::SimpleValueType getSetCCResultType(EVT VT) const; + + /// getFunctionAlignment - Return the Log2 alignment of this function. + virtual unsigned getFunctionAlignment(const Function *F) const; + private: + // Subtarget Info + const MipsSubtarget *Subtarget; + + + // Lower Operand helpers + SDValue LowerCallResult(SDValue Chain, SDValue InFlag, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const; + + // Lower Operand specifics + SDValue LowerANDOR(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerBRCOND(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSELECT(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const; + + virtual SDValue + LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const; + + virtual SDValue + LowerCall(SDValue Chain, SDValue Callee, + CallingConv::ID CallConv, bool isVarArg, + bool &isTailCall, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const; + + virtual SDValue + LowerReturn(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + DebugLoc dl, SelectionDAG &DAG) const; + + 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, + EVT VT) const; + + std::vector<unsigned> + getRegClassForInlineAsmConstraint(const std::string &Constraint, + EVT VT) const; + + virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const; + + /// isFPImmLegal - Returns true if the target can instruction select the + /// specified FP immediate natively. If false, the legalizer will + /// materialize the FP immediate as a load from a constant pool. + virtual bool isFPImmLegal(const APFloat &Imm, EVT VT) const; + }; +} + +#endif // MipsISELLOWERING_H diff --git a/contrib/llvm/lib/Target/Mips/MipsInstrFPU.td b/contrib/llvm/lib/Target/Mips/MipsInstrFPU.td new file mode 100644 index 0000000..e948917 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsInstrFPU.td @@ -0,0 +1,316 @@ +//===- 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<1, 3, [SDTCisVT<0, i32>, + SDTCisSameAs<1, 2>, SDTCisFP<1>, + SDTCisInt<3>]>; +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()">; +def IsNotMipsI : Predicate<"!Subtarget.isMips1()">; + +//===----------------------------------------------------------------------===// +// 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 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", []>; +} + +def FMOV_S32 : FFR<0x11, 0b000110, 0x0, (outs FGR32:$fd), (ins FGR32:$fs), + "mov.s $fd, $fs", []>; +def FMOV_D32 : FFR<0x11, 0b000110, 0x1, (outs AFGR64:$fd), (ins AFGR64:$fs), + "mov.d $fd, $fs", []>; + +/// Floating Point Memory Instructions +let Predicates = [IsNotSingleFloat, IsNotMipsI] 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", + [(set FCR31, (MipsFPCmp FGR32:$fs, FGR32:$ft, imm:$cc))]>; + + def FCMP_D32 : FCC<0x1, (outs), (ins AFGR64:$fs, AFGR64:$ft, condcode:$cc), + "c.$cc.d $fs, $ft", + [(set FCR31, (MipsFPCmp AFGR64:$fs, AFGR64:$ft, imm:$cc))]>, + 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 usesCustomInserter = 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 fpimm0neg : PatLeaf<(fpimm), [{ + return N->isExactlyValue(-0.0); +}]>; + +def : Pat<(f32 fpimm0), (MTC1 ZERO)>; +def : Pat<(f32 fpimm0neg), (FNEG_S32 (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/contrib/llvm/lib/Target/Mips/MipsInstrFormats.td b/contrib/llvm/lib/Target/Mips/MipsInstrFormats.td new file mode 100644 index 0000000..0853272 --- /dev/null +++ b/contrib/llvm/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/contrib/llvm/lib/Target/Mips/MipsInstrInfo.cpp b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.cpp new file mode 100644 index 0000000..4005e35 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.cpp @@ -0,0 +1,634 @@ +//===- 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 "MipsMachineFunction.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/ErrorHandling.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; + 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, + DebugLoc DL) const { + + 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); + } else + // Can't copy this register + 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 TargetRegisterInfo *TRI) const { + DebugLoc DL; + if (I != MBB.end()) DL = I->getDebugLoc(); + + if (RC == Mips::CPURegsRegisterClass) + BuildMI(MBB, I, DL, get(Mips::SW)).addReg(SrcReg, getKillRegState(isKill)) + .addImm(0).addFrameIndex(FI); + else if (RC == Mips::FGR32RegisterClass) + BuildMI(MBB, I, DL, get(Mips::SWC1)).addReg(SrcReg, getKillRegState(isKill)) + .addImm(0).addFrameIndex(FI); + else if (RC == Mips::AFGR64RegisterClass) { + if (!TM.getSubtarget<MipsSubtarget>().isMips1()) { + BuildMI(MBB, I, DL, get(Mips::SDC1)) + .addReg(SrcReg, getKillRegState(isKill)) + .addImm(0).addFrameIndex(FI); + } else { + const TargetRegisterInfo *TRI = + MBB.getParent()->getTarget().getRegisterInfo(); + const unsigned *SubSet = TRI->getSubRegisters(SrcReg); + BuildMI(MBB, I, DL, get(Mips::SWC1)) + .addReg(SubSet[0], getKillRegState(isKill)) + .addImm(0).addFrameIndex(FI); + BuildMI(MBB, I, DL, get(Mips::SWC1)) + .addReg(SubSet[1], getKillRegState(isKill)) + .addImm(4).addFrameIndex(FI); + } + } else + llvm_unreachable("Register class not handled!"); +} + +void MipsInstrInfo:: +loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned DestReg, int FI, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const +{ + DebugLoc DL; + if (I != MBB.end()) DL = I->getDebugLoc(); + + if (RC == Mips::CPURegsRegisterClass) + BuildMI(MBB, I, DL, get(Mips::LW), DestReg).addImm(0).addFrameIndex(FI); + else if (RC == Mips::FGR32RegisterClass) + BuildMI(MBB, I, DL, get(Mips::LWC1), DestReg).addImm(0).addFrameIndex(FI); + else if (RC == Mips::AFGR64RegisterClass) { + if (!TM.getSubtarget<MipsSubtarget>().isMips1()) { + BuildMI(MBB, I, DL, get(Mips::LDC1), DestReg).addImm(0).addFrameIndex(FI); + } else { + const TargetRegisterInfo *TRI = + MBB.getParent()->getTarget().getRegisterInfo(); + const unsigned *SubSet = TRI->getSubRegisters(DestReg); + BuildMI(MBB, I, DL, get(Mips::LWC1), SubSet[0]) + .addImm(0).addFrameIndex(FI); + BuildMI(MBB, I, DL, get(Mips::LWC1), SubSet[1]) + .addImm(4).addFrameIndex(FI); + } + } else + llvm_unreachable("Register class not handled!"); +} + +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(); + bool isUndef = MI->getOperand(2).isUndef(); + NewMI = BuildMI(MF, MI->getDebugLoc(), get(Mips::SW)) + .addReg(SrcReg, getKillRegState(isKill) | getUndefRegState(isUndef)) + .addImm(0).addFrameIndex(FI); + } else { // COPY -> LOAD + unsigned DstReg = MI->getOperand(0).getReg(); + bool isDead = MI->getOperand(0).isDead(); + bool isUndef = MI->getOperand(0).isUndef(); + NewMI = BuildMI(MF, MI->getDebugLoc(), get(Mips::LW)) + .addReg(DstReg, RegState::Define | getDeadRegState(isDead) | + getUndefRegState(isUndef)) + .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; + bool IsMips1 = TM.getSubtarget<MipsSubtarget>().isMips1(); + + if (RC == Mips::FGR32RegisterClass) { + LoadOpc = Mips::LWC1; StoreOpc = Mips::SWC1; + } else { + assert(RC == Mips::AFGR64RegisterClass); + // Mips1 doesn't have ldc/sdc instructions. + if (IsMips1) break; + LoadOpc = Mips::LDC1; StoreOpc = Mips::SDC1; + } + + if (Ops[0] == 0) { // COPY -> STORE + unsigned SrcReg = MI->getOperand(1).getReg(); + bool isKill = MI->getOperand(1).isKill(); + bool isUndef = MI->getOperand(2).isUndef(); + NewMI = BuildMI(MF, MI->getDebugLoc(), get(StoreOpc)) + .addReg(SrcReg, getKillRegState(isKill) | getUndefRegState(isUndef)) + .addImm(0).addFrameIndex(FI) ; + } else { // COPY -> LOAD + unsigned DstReg = MI->getOperand(0).getReg(); + bool isDead = MI->getOperand(0).isDead(); + bool isUndef = MI->getOperand(0).isUndef(); + NewMI = BuildMI(MF, MI->getDebugLoc(), get(LoadOpc)) + .addReg(DstReg, RegState::Define | getDeadRegState(isDead) | + getUndefRegState(isUndef)) + .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: llvm_unreachable("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: llvm_unreachable("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()) + return false; + --I; + while (I->isDebugValue()) { + if (I == MBB.begin()) + return false; + --I; + } + if (!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; + // 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; + while (I->isDebugValue()) { + 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; +} + +/// 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; +} + +/// getGlobalBaseReg - Return a virtual register initialized with the +/// the global base register value. Output instructions required to +/// initialize the register in the function entry block, if necessary. +/// +unsigned MipsInstrInfo::getGlobalBaseReg(MachineFunction *MF) const { + MipsFunctionInfo *MipsFI = MF->getInfo<MipsFunctionInfo>(); + unsigned GlobalBaseReg = MipsFI->getGlobalBaseReg(); + if (GlobalBaseReg != 0) + return GlobalBaseReg; + + // Insert the set of GlobalBaseReg into the first MBB of the function + MachineBasicBlock &FirstMBB = MF->front(); + MachineBasicBlock::iterator MBBI = FirstMBB.begin(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + const TargetInstrInfo *TII = MF->getTarget().getInstrInfo(); + + GlobalBaseReg = RegInfo.createVirtualRegister(Mips::CPURegsRegisterClass); + bool Ok = TII->copyRegToReg(FirstMBB, MBBI, GlobalBaseReg, Mips::GP, + Mips::CPURegsRegisterClass, + Mips::CPURegsRegisterClass, + DebugLoc()); + assert(Ok && "Couldn't assign to global base register!"); + Ok = Ok; // Silence warning when assertions are turned off. + RegInfo.addLiveIn(Mips::GP); + + MipsFI->setGlobalBaseReg(GlobalBaseReg); + return GlobalBaseReg; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsInstrInfo.h b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.h new file mode 100644 index 0000000..7919d9a --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.h @@ -0,0 +1,254 @@ +//===- 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/Support/ErrorHandling.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: llvm_unreachable("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"; + } + } +} + +/// MipsII - This namespace holds all of the target specific flags that +/// instruction info tracks. +/// +namespace MipsII { + /// Target Operand Flag enum. + enum TOF { + //===------------------------------------------------------------------===// + // Mips Specific MachineOperand flags. + + MO_NO_FLAG, + + /// MO_GOT - Represents the offset into the global offset table at which + /// the address the relocation entry symbol resides during execution. + MO_GOT, + + /// MO_GOT_CALL - Represents the offset into the global offset table at + /// which the address of a call site relocation entry symbol resides + /// during execution. This is different from the above since this flag + /// can only be present in call instructions. + MO_GOT_CALL, + + /// MO_GPREL - Represents the offset from the current gp value to be used + /// for the relocatable object file being produced. + MO_GPREL, + + /// MO_ABS_HILO - Represents the hi or low part of an absolute symbol + /// address. + MO_ABS_HILO + + }; +} + +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, + DebugLoc DL) const; + virtual void storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned SrcReg, bool isKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const; + + virtual void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) 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 ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const; + + /// Insert nop instruction when hazard condition is found + virtual void insertNoop(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const; + + /// getGlobalBaseReg - Return a virtual register initialized with the + /// the global base register value. Output instructions required to + /// initialize the register in the function entry block, if necessary. + /// + unsigned getGlobalBaseReg(MachineFunction *MF) const; +}; + +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsInstrInfo.td b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.td new file mode 100644 index 0000000..2b9e941 --- /dev/null +++ b/contrib/llvm/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, SDNPOptInFlag, + SDNPVariadic]>; + +// 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<iPTR, 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, D0, D1, D2, D3, D4, D5, D6, D7, D8, D9], Uses = [GP] in { + class JumpLink<bits<6> op, string instr_asm>: + FJ< op, + (outs), + (ins calltarget:$target, variable_ops), + !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, variable_ops), + !strconcat(instr_asm, "\t$rs"), + [(MipsJmpLink CPURegs:$rs)], IIBranch>; + + class BranchLink<string instr_asm>: + FI< 0x1, + (outs), + (ins CPURegs:$rs, brtarget:$target, variable_ops), + !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 usesCustomInserter = 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/contrib/llvm/lib/Target/Mips/MipsMCAsmInfo.cpp b/contrib/llvm/lib/Target/Mips/MipsMCAsmInfo.cpp new file mode 100644 index 0000000..89e3e11 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsMCAsmInfo.cpp @@ -0,0 +1,27 @@ +//===-- MipsMCAsmInfo.cpp - Mips asm properties ---------------------------===// +// +// 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 MipsMCAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "MipsMCAsmInfo.h" +using namespace llvm; + +MipsMCAsmInfo::MipsMCAsmInfo(const Target &T, const StringRef &TT) { + AlignmentIsInBytes = false; + Data16bitsDirective = "\t.half\t"; + Data32bitsDirective = "\t.word\t"; + Data64bitsDirective = 0; + PrivateGlobalPrefix = "$"; + CommentString = "#"; + ZeroDirective = "\t.space\t"; + GPRel32Directive = "\t.gpword\t"; + HasSetDirective = false; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsMCAsmInfo.h b/contrib/llvm/lib/Target/Mips/MipsMCAsmInfo.h new file mode 100644 index 0000000..33a4b5e --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsMCAsmInfo.h @@ -0,0 +1,30 @@ +//=====-- MipsMCAsmInfo.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 MipsMCAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSTARGETASMINFO_H +#define MIPSTARGETASMINFO_H + +#include "llvm/MC/MCAsmInfo.h" + +namespace llvm { + class Target; + class StringRef; + + class MipsMCAsmInfo : public MCAsmInfo { + public: + explicit MipsMCAsmInfo(const Target &T, const StringRef &TT); + }; + +} // namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsMachineFunction.h b/contrib/llvm/lib/Target/Mips/MipsMachineFunction.h new file mode 100644 index 0000000..5723f9e --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsMachineFunction.h @@ -0,0 +1,147 @@ +//===-- 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 LowerFormalArguments 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 + // LowerFormalArguments, 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; + + /// GlobalBaseReg - keeps track of the virtual register initialized for + /// use as the global base register. This is used for PIC in some PIC + /// relocation models. + unsigned GlobalBaseReg; + + /// VarArgsFrameIndex - FrameIndex for start of varargs area. + int VarArgsFrameIndex; + +public: + MipsFunctionInfo(MachineFunction& MF) + : FPStackOffset(0), RAStackOffset(0), CPUTopSavedRegOff(0), + FPUTopSavedRegOff(0), GPHolder(-1,-1), HasLoadArgs(false), + HasStoreVarArgs(false), SRetReturnReg(0), GlobalBaseReg(0), + VarArgsFrameIndex(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 needGPSaveRestore() const { return GPHolder.SPOffset != -1; } + + 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; } + + unsigned getGlobalBaseReg() const { return GlobalBaseReg; } + void setGlobalBaseReg(unsigned Reg) { GlobalBaseReg = Reg; } + + int getVarArgsFrameIndex() const { return VarArgsFrameIndex; } + void setVarArgsFrameIndex(int Index) { VarArgsFrameIndex = Index; } +}; + +} // end of namespace llvm + +#endif // MIPS_MACHINE_FUNCTION_INFO_H diff --git a/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.cpp b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.cpp new file mode 100644 index 0000000..5e719af --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.cpp @@ -0,0 +1,531 @@ +//===- 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/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.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: llvm_unreachable("Unknown register number!"); + } + return 0; // Not reached +} + +unsigned MipsRegisterInfo::getPICCallReg() { 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, 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, 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 references 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 LowerFormalArguments, 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(); + unsigned RegSize = Subtarget.isGP32bit() ? 4 : 8; + bool HasGP = MipsFI->needGPSaveRestore(); + + // 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 + // LowerFormalArguments. 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()); + + unsigned StackOffset = HasGP ? (MipsFI->getGPStackOffset()+RegSize) + : (Subtarget.isABI_O32() ? 16 : 0); + + // 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 = + StackOffset + 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. This whole area must be aligned to the + // default Stack Alignment requirements. + 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()); + } + + // Stack locations for FP and RA. If only one of them is used, + // the space must be allocated for both, otherwise no space at all. + if (hasFP(MF) || MFI->adjustsStack()) { + // FP stack location + MFI->setObjectOffset(MFI->CreateStackObject(RegSize, RegSize, true), + StackOffset); + MipsFI->setFPStackOffset(StackOffset); + TopCPUSavedRegOff = StackOffset; + StackOffset += RegSize; + + // SP stack location + MFI->setObjectOffset(MFI->CreateStackObject(RegSize, RegSize, true), + StackOffset); + MipsFI->setRAStackOffset(StackOffset); + StackOffset += RegSize; + + if (MFI->adjustsStack()) + TopCPUSavedRegOff += 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 DisableFramePointerElim(MF) || 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. +unsigned MipsRegisterInfo:: +eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, + FrameIndexValue *Value, 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!"); + } + + DEBUG(errs() << "\nFunction : " << MF.getFunction()->getName() << "\n"; + errs() << "<--------->\n" << MI); + + int FrameIndex = MI.getOperand(i).getIndex(); + int stackSize = MF.getFrameInfo()->getStackSize(); + int spOffset = MF.getFrameInfo()->getObjectOffset(FrameIndex); + + DEBUG(errs() << "FrameIndex : " << FrameIndex << "\n" + << "spOffset : " << spOffset << "\n" + << "stackSize : " << stackSize << "\n"); + + // as explained on LowerFormalArguments, 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(); + + DEBUG(errs() << "Offset : " << Offset << "\n" << "<--------->\n"); + + MI.getOperand(i-1).ChangeToImmediate(Offset); + MI.getOperand(i).ChangeToRegister(getFrameRegister(MF), false); + return 0; +} + +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(); + 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->adjustsStack()) 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->adjustsStack()) { + 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); + } + + // Restore GP from the saved stack location + if (MipsFI->needGPSaveRestore()) + 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->adjustsStack()) { + 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 stack offset where GP must be saved/loaded from. + MachineFrameInfo *MFI = MF.getFrameInfo(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + if (MipsFI->needGPSaveRestore()) + MFI->setObjectOffset(MipsFI->getGPFI(), MipsFI->getGPStackOffset()); +} + +unsigned MipsRegisterInfo:: +getRARegister() const { + return Mips::RA; +} + +unsigned MipsRegisterInfo:: +getFrameRegister(const MachineFunction &MF) const { + return hasFP(MF) ? Mips::FP : Mips::SP; +} + +unsigned MipsRegisterInfo:: +getEHExceptionRegister() const { + llvm_unreachable("What is the exception register"); + return 0; +} + +unsigned MipsRegisterInfo:: +getEHHandlerRegister() const { + llvm_unreachable("What is the exception handler register"); + return 0; +} + +int MipsRegisterInfo:: +getDwarfRegNum(unsigned RegNum, bool isEH) const { + llvm_unreachable("What is the dwarf register number"); + return -1; +} + +#include "MipsGenRegisterInfo.inc" + diff --git a/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.h b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.h new file mode 100644 index 0000000..bc857b8 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.h @@ -0,0 +1,79 @@ +//===- 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(); + + /// 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 + unsigned eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, FrameIndexValue *Value = NULL, + 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(const 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/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.td b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.td new file mode 100644 index 0000000..be78a22 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.td @@ -0,0 +1,264 @@ +//===- 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"; +} + +class MipsRegWithSubRegs<string n, list<Register> subregs> + : RegisterWithSubRegs<n, subregs> { + 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 +let Namespace = "Mips" in { +def sub_fpeven : SubRegIndex; +def sub_fpodd : SubRegIndex; +} +class AFPR<bits<5> num, string n, list<Register> subregs> + : MipsRegWithSubRegs<n, subregs> { + let Num = num; + let SubRegIndices = [sub_fpeven, sub_fpodd]; +} + +//===----------------------------------------------------------------------===// +// 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 SubRegClasses = [(FGR32 sub_fpeven, sub_fpodd)]; + 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/contrib/llvm/lib/Target/Mips/MipsSchedule.td b/contrib/llvm/lib/Target/Mips/MipsSchedule.td new file mode 100644 index 0000000..616a79b --- /dev/null +++ b/contrib/llvm/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<[ALU, IMULDIV], [ + 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/contrib/llvm/lib/Target/Mips/MipsSelectionDAGInfo.cpp b/contrib/llvm/lib/Target/Mips/MipsSelectionDAGInfo.cpp new file mode 100644 index 0000000..e4d70fc --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSelectionDAGInfo.cpp @@ -0,0 +1,23 @@ +//===-- MipsSelectionDAGInfo.cpp - Mips SelectionDAG Info -----------------===// +// +// 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 MipsSelectionDAGInfo class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mips-selectiondag-info" +#include "MipsTargetMachine.h" +using namespace llvm; + +MipsSelectionDAGInfo::MipsSelectionDAGInfo(const MipsTargetMachine &TM) + : TargetSelectionDAGInfo(TM) { +} + +MipsSelectionDAGInfo::~MipsSelectionDAGInfo() { +} diff --git a/contrib/llvm/lib/Target/Mips/MipsSelectionDAGInfo.h b/contrib/llvm/lib/Target/Mips/MipsSelectionDAGInfo.h new file mode 100644 index 0000000..6cafb55 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSelectionDAGInfo.h @@ -0,0 +1,31 @@ +//===-- MipsSelectionDAGInfo.h - Mips SelectionDAG Info ---------*- 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 Mips subclass for TargetSelectionDAGInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSSELECTIONDAGINFO_H +#define MIPSSELECTIONDAGINFO_H + +#include "llvm/Target/TargetSelectionDAGInfo.h" + +namespace llvm { + +class MipsTargetMachine; + +class MipsSelectionDAGInfo : public TargetSelectionDAGInfo { +public: + explicit MipsSelectionDAGInfo(const MipsTargetMachine &TM); + ~MipsSelectionDAGInfo(); +}; + +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsSubtarget.cpp b/contrib/llvm/lib/Target/Mips/MipsSubtarget.cpp new file mode 100644 index 0000000..db114da --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSubtarget.cpp @@ -0,0 +1,51 @@ +//===- 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" +using namespace llvm; + +MipsSubtarget::MipsSubtarget(const std::string &TT, const std::string &FS, + bool little) : + MipsArchVersion(Mips1), MipsABI(O32), IsLittle(little), IsSingleFloat(false), + IsFP64bit(false), IsGP64bit(false), HasVFPU(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); + + // 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; + } +} diff --git a/contrib/llvm/lib/Target/Mips/MipsSubtarget.h b/contrib/llvm/lib/Target/Mips/MipsSubtarget.h new file mode 100644 index 0000000..2d5fd22 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSubtarget.h @@ -0,0 +1,123 @@ +//=====-- 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 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; + + // isLinux - Target system is Linux. Is false we consider ELFOS for now. + bool IsLinux; + + /// 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 triple. + MipsSubtarget(const std::string &TT, 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 isLinux() const { return IsLinux; } + + /// 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/contrib/llvm/lib/Target/Mips/MipsTargetMachine.cpp b/contrib/llvm/lib/Target/Mips/MipsTargetMachine.cpp new file mode 100644 index 0000000..ad3eb9e --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsTargetMachine.cpp @@ -0,0 +1,77 @@ +//===-- 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 "MipsMCAsmInfo.h" +#include "MipsTargetMachine.h" +#include "llvm/PassManager.h" +#include "llvm/Target/TargetRegistry.h" +using namespace llvm; + +extern "C" void LLVMInitializeMipsTarget() { + // Register the target. + RegisterTargetMachine<MipsTargetMachine> X(TheMipsTarget); + RegisterTargetMachine<MipselTargetMachine> Y(TheMipselTarget); + RegisterAsmInfo<MipsMCAsmInfo> A(TheMipsTarget); + RegisterAsmInfo<MipsMCAsmInfo> B(TheMipselTarget); +} + +// 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 Target &T, const std::string &TT, const std::string &FS, + bool isLittle=false): + LLVMTargetMachine(T, TT), + Subtarget(TT, FS, isLittle), + DataLayout(isLittle ? std::string("e-p:32:32:32-i8:8:32-i16:16:32-n32") : + std::string("E-p:32:32:32-i8:8:32-i16:16:32-n32")), + InstrInfo(*this), + FrameInfo(TargetFrameInfo::StackGrowsUp, 8, 0), + TLInfo(*this), TSInfo(*this) { + // Abicall enables PIC by default + if (getRelocationModel() == Reloc::Default) { + if (Subtarget.isABI_O32()) + setRelocationModel(Reloc::PIC_); + else + setRelocationModel(Reloc::Static); + } +} + +MipselTargetMachine:: +MipselTargetMachine(const Target &T, const std::string &TT, + const std::string &FS) : + MipsTargetMachine(T, TT, FS, true) {} + +// 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; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsTargetMachine.h b/contrib/llvm/lib/Target/Mips/MipsTargetMachine.h new file mode 100644 index 0000000..d63976f --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsTargetMachine.h @@ -0,0 +1,77 @@ +//===-- 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 "MipsSelectionDAGInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetFrameInfo.h" + +namespace llvm { + class formatted_raw_ostream; + + class MipsTargetMachine : public LLVMTargetMachine { + MipsSubtarget Subtarget; + const TargetData DataLayout; // Calculates type size & alignment + MipsInstrInfo InstrInfo; + TargetFrameInfo FrameInfo; + MipsTargetLowering TLInfo; + MipsSelectionDAGInfo TSInfo; + public: + MipsTargetMachine(const Target &T, const std::string &TT, + 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 const MipsTargetLowering *getTargetLowering() const { + return &TLInfo; + } + + virtual const MipsSelectionDAGInfo* getSelectionDAGInfo() const { + return &TSInfo; + } + + // Pass Pipeline Configuration + virtual bool addInstSelector(PassManagerBase &PM, + CodeGenOpt::Level OptLevel); + virtual bool addPreEmitPass(PassManagerBase &PM, + CodeGenOpt::Level OptLevel); + }; + +/// MipselTargetMachine - Mipsel target machine. +/// +class MipselTargetMachine : public MipsTargetMachine { +public: + MipselTargetMachine(const Target &T, const std::string &TT, + const std::string &FS); +}; + +} // End llvm namespace + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.cpp b/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.cpp new file mode 100644 index 0000000..405f419 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.cpp @@ -0,0 +1,101 @@ +//===-- MipsTargetObjectFile.cpp - Mips object files ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsTargetObjectFile.h" +#include "MipsSubtarget.h" +#include "llvm/DerivedTypes.h" +#include "llvm/GlobalVariable.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Support/CommandLine.h" +using namespace llvm; + +static cl::opt<unsigned> +SSThreshold("mips-ssection-threshold", cl::Hidden, + cl::desc("Small data and bss section threshold size (default=8)"), + cl::init(8)); + +void MipsTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM){ + TargetLoweringObjectFileELF::Initialize(Ctx, TM); + + SmallDataSection = + getContext().getELFSection(".sdata", MCSectionELF::SHT_PROGBITS, + MCSectionELF::SHF_WRITE |MCSectionELF::SHF_ALLOC, + SectionKind::getDataRel()); + + SmallBSSSection = + getContext().getELFSection(".sbss", MCSectionELF::SHT_NOBITS, + MCSectionELF::SHF_WRITE |MCSectionELF::SHF_ALLOC, + SectionKind::getBSS()); + +} + +// 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. +static bool IsInSmallSection(uint64_t Size) { + return Size > 0 && Size <= SSThreshold; +} + +bool MipsTargetObjectFile::IsGlobalInSmallSection(const GlobalValue *GV, + const TargetMachine &TM) const { + if (GV->isDeclaration() || GV->hasAvailableExternallyLinkage()) + return false; + + return IsGlobalInSmallSection(GV, TM, getKindForGlobal(GV, TM)); +} + +/// IsGlobalInSmallSection - Return true if this global address should be +/// placed into small data/bss section. +bool MipsTargetObjectFile:: +IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM, + SectionKind Kind) const { + + // Only use small section for non linux targets. + const MipsSubtarget &Subtarget = TM.getSubtarget<MipsSubtarget>(); + if (Subtarget.isLinux()) + return false; + + // Only global variables, not functions. + const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GV); + if (!GVA) + return false; + + // We can only do this for datarel or BSS objects for now. + if (!Kind.isBSS() && !Kind.isDataRel()) + return false; + + // If this is a internal constant string, there is a special + // section for it, but not in small data/bss. + if (Kind.isMergeable1ByteCString()) + return false; + + const Type *Ty = GV->getType()->getElementType(); + return IsInSmallSection(TM.getTargetData()->getTypeAllocSize(Ty)); +} + + + +const MCSection *MipsTargetObjectFile:: +SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, + Mangler *Mang, const TargetMachine &TM) const { + // TODO: Could also support "weak" symbols as well with ".gnu.linkonce.s.*" + // sections? + + // Handle Small Section classification here. + if (Kind.isBSS() && IsGlobalInSmallSection(GV, TM, Kind)) + return SmallBSSSection; + if (Kind.isDataNoRel() && IsGlobalInSmallSection(GV, TM, Kind)) + return SmallDataSection; + + // Otherwise, we work the same as ELF. + return TargetLoweringObjectFileELF::SelectSectionForGlobal(GV, Kind, Mang,TM); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.h b/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.h new file mode 100644 index 0000000..237b160 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.h @@ -0,0 +1,41 @@ +//===-- llvm/Target/MipsTargetObjectFile.h - Mips Object Info ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_MIPS_TARGETOBJECTFILE_H +#define LLVM_TARGET_MIPS_TARGETOBJECTFILE_H + +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" + +namespace llvm { + + class MipsTargetObjectFile : public TargetLoweringObjectFileELF { + const MCSection *SmallDataSection; + const MCSection *SmallBSSSection; + public: + + void Initialize(MCContext &Ctx, const TargetMachine &TM); + + + /// IsGlobalInSmallSection - Return true if this global address should be + /// placed into small data/bss section. + bool IsGlobalInSmallSection(const GlobalValue *GV, + const TargetMachine &TM, SectionKind Kind)const; + bool IsGlobalInSmallSection(const GlobalValue *GV, + const TargetMachine &TM) const; + + const MCSection *SelectSectionForGlobal(const GlobalValue *GV, + SectionKind Kind, + Mangler *Mang, + const TargetMachine &TM) const; + + // TODO: Classify globals as mips wishes. + }; +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/Mips/TargetInfo/CMakeLists.txt b/contrib/llvm/lib/Target/Mips/TargetInfo/CMakeLists.txt new file mode 100644 index 0000000..6e5d56b --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/TargetInfo/CMakeLists.txt @@ -0,0 +1,7 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +add_llvm_library(LLVMMipsInfo + MipsTargetInfo.cpp + ) + +add_dependencies(LLVMMipsInfo MipsCodeGenTable_gen) diff --git a/contrib/llvm/lib/Target/Mips/TargetInfo/Makefile b/contrib/llvm/lib/Target/Mips/TargetInfo/Makefile new file mode 100644 index 0000000..32f4e16 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/TargetInfo/Makefile @@ -0,0 +1,15 @@ +##===- lib/Target/Mips/TargetInfo/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 = LLVMMipsInfo + +# Hack: we need to include 'main' target directory to grab private headers +CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/contrib/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp b/contrib/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp new file mode 100644 index 0000000..cc3d61e --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp @@ -0,0 +1,21 @@ +//===-- MipsTargetInfo.cpp - Mips Target Implementation -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Mips.h" +#include "llvm/Module.h" +#include "llvm/Target/TargetRegistry.h" +using namespace llvm; + +Target llvm::TheMipsTarget, llvm::TheMipselTarget; + +extern "C" void LLVMInitializeMipsTargetInfo() { + RegisterTarget<Triple::mips> X(TheMipsTarget, "mips", "Mips"); + + RegisterTarget<Triple::mipsel> Y(TheMipselTarget, "mipsel", "Mipsel"); +} |