diff options
Diffstat (limited to 'lib/Target/Mips')
66 files changed, 4908 insertions, 2142 deletions
diff --git a/lib/Target/Mips/AsmParser/CMakeLists.txt b/lib/Target/Mips/AsmParser/CMakeLists.txt new file mode 100644 index 000000000000..ac21c259fb44 --- /dev/null +++ b/lib/Target/Mips/AsmParser/CMakeLists.txt @@ -0,0 +1,6 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +add_llvm_library(LLVMMipsAsmParser + MipsAsmParser.cpp + ) + diff --git a/lib/Target/Mips/AsmParser/LLVMBuild.txt b/lib/Target/Mips/AsmParser/LLVMBuild.txt new file mode 100644 index 000000000000..e7ca243d0e7f --- /dev/null +++ b/lib/Target/Mips/AsmParser/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/Mips/AsmParser/LLVMBuild.txt ----------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = MipsAsmParser +parent = Mips +required_libraries = MC MCParser Support MipsDesc MipsInfo +add_to_library_groups = Mips diff --git a/lib/Target/Mips/AsmParser/Makefile b/lib/Target/Mips/AsmParser/Makefile new file mode 100644 index 000000000000..679acee9fe72 --- /dev/null +++ b/lib/Target/Mips/AsmParser/Makefile @@ -0,0 +1,15 @@ +##===- lib/Target/Mips/AsmParser/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 = LLVMMipsAsmParser + +# 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/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp new file mode 100644 index 000000000000..58b559025757 --- /dev/null +++ b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -0,0 +1,66 @@ +//===-- MipsAsmParser.cpp - Parse Mips assembly to MCInst instructions ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/MipsMCTargetDesc.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +namespace { +class MipsAsmParser : public MCTargetAsmParser { + bool MatchAndEmitInstruction(SMLoc IDLoc, + SmallVectorImpl<MCParsedAsmOperand*> &Operands, + MCStreamer &Out); + + bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc); + + bool ParseInstruction(StringRef Name, SMLoc NameLoc, + SmallVectorImpl<MCParsedAsmOperand*> &Operands); + + bool ParseDirective(AsmToken DirectiveID); + +public: + MipsAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser) + : MCTargetAsmParser() { + } + +}; +} + +bool MipsAsmParser:: +MatchAndEmitInstruction(SMLoc IDLoc, + SmallVectorImpl<MCParsedAsmOperand*> &Operands, + MCStreamer &Out) { + return true; +} + +bool MipsAsmParser:: +ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { + return true; +} + +bool MipsAsmParser:: +ParseInstruction(StringRef Name, SMLoc NameLoc, + SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + return true; +} + +bool MipsAsmParser:: +ParseDirective(AsmToken DirectiveID) { + return true; +} + +extern "C" void LLVMInitializeMipsAsmParser() { + RegisterMCAsmParser<MipsAsmParser> X(TheMipsTarget); + RegisterMCAsmParser<MipsAsmParser> Y(TheMipselTarget); + RegisterMCAsmParser<MipsAsmParser> A(TheMips64Target); + RegisterMCAsmParser<MipsAsmParser> B(TheMips64elTarget); +} diff --git a/lib/Target/Mips/CMakeLists.txt b/lib/Target/Mips/CMakeLists.txt index 71391f322725..13d17e4e5293 100644 --- a/lib/Target/Mips/CMakeLists.txt +++ b/lib/Target/Mips/CMakeLists.txt @@ -1,15 +1,17 @@ set(LLVM_TARGET_DEFINITIONS Mips.td) -llvm_tablegen(MipsGenRegisterInfo.inc -gen-register-info) -llvm_tablegen(MipsGenInstrInfo.inc -gen-instr-info) -llvm_tablegen(MipsGenCodeEmitter.inc -gen-emitter) -llvm_tablegen(MipsGenAsmWriter.inc -gen-asm-writer) -llvm_tablegen(MipsGenDAGISel.inc -gen-dag-isel) -llvm_tablegen(MipsGenCallingConv.inc -gen-callingconv) -llvm_tablegen(MipsGenSubtargetInfo.inc -gen-subtarget) +tablegen(LLVM MipsGenRegisterInfo.inc -gen-register-info) +tablegen(LLVM MipsGenInstrInfo.inc -gen-instr-info) +tablegen(LLVM MipsGenCodeEmitter.inc -gen-emitter) +tablegen(LLVM MipsGenMCCodeEmitter.inc -gen-emitter -mc-emitter) +tablegen(LLVM MipsGenAsmWriter.inc -gen-asm-writer) +tablegen(LLVM MipsGenDAGISel.inc -gen-dag-isel) +tablegen(LLVM MipsGenCallingConv.inc -gen-callingconv) +tablegen(LLVM MipsGenSubtargetInfo.inc -gen-subtarget) add_public_tablegen_target(MipsCommonTableGen) add_llvm_target(MipsCodeGen + MipsAnalyzeImmediate.cpp MipsAsmPrinter.cpp MipsCodeEmitter.cpp MipsDelaySlotFiller.cpp @@ -21,7 +23,7 @@ add_llvm_target(MipsCodeGen MipsISelLowering.cpp MipsFrameLowering.cpp MipsMCInstLower.cpp - MipsMCSymbolRefExpr.cpp + MipsMachineFunction.cpp MipsRegisterInfo.cpp MipsSubtarget.cpp MipsTargetMachine.cpp @@ -29,19 +31,7 @@ add_llvm_target(MipsCodeGen MipsSelectionDAGInfo.cpp ) -add_llvm_library_dependencies(LLVMMipsCodeGen - LLVMAsmPrinter - LLVMCodeGen - LLVMCore - LLVMMC - LLVMMipsAsmPrinter - LLVMMipsDesc - LLVMMipsInfo - LLVMSelectionDAG - LLVMSupport - LLVMTarget - ) - add_subdirectory(InstPrinter) add_subdirectory(TargetInfo) add_subdirectory(MCTargetDesc) +add_subdirectory(AsmParser) diff --git a/lib/Target/Mips/InstPrinter/CMakeLists.txt b/lib/Target/Mips/InstPrinter/CMakeLists.txt index c45b35df8c11..3e9fbf1c5566 100644 --- a/lib/Target/Mips/InstPrinter/CMakeLists.txt +++ b/lib/Target/Mips/InstPrinter/CMakeLists.txt @@ -4,9 +4,4 @@ add_llvm_library(LLVMMipsAsmPrinter MipsInstPrinter.cpp ) -add_llvm_library_dependencies(LLVMMipsAsmPrinter - LLVMMC - LLVMSupport - ) - add_dependencies(LLVMMipsAsmPrinter MipsCommonTableGen) diff --git a/lib/Target/Mips/InstPrinter/LLVMBuild.txt b/lib/Target/Mips/InstPrinter/LLVMBuild.txt new file mode 100644 index 000000000000..317057b913b1 --- /dev/null +++ b/lib/Target/Mips/InstPrinter/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/Mips/InstPrinter/LLVMBuild.txt --------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = MipsAsmPrinter +parent = Mips +required_libraries = MC Support +add_to_library_groups = Mips diff --git a/lib/Target/Mips/InstPrinter/Makefile b/lib/Target/Mips/InstPrinter/Makefile index 74872a48b974..f07f3ed381ee 100644 --- a/lib/Target/Mips/InstPrinter/Makefile +++ b/lib/Target/Mips/InstPrinter/Makefile @@ -1,4 +1,4 @@ -##===- lib/Target/Mips/AsmPrinter/Makefile --------------*- Makefile -*-===## +##===- lib/Target/Mips/AsmPrinter/Makefile -----------------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # diff --git a/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp b/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp index 3dafc6134488..6886b1745240 100644 --- a/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp +++ b/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp @@ -13,14 +13,15 @@ #define DEBUG_TYPE "asm-printer" #include "MipsInstPrinter.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCSymbol.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/ADT/StringExtras.h" using namespace llvm; -#define GET_INSTRUCTION_NAME #include "MipsGenAsmWriter.inc" const char* Mips::MipsFCCToString(Mips::CondCode CC) { @@ -61,12 +62,8 @@ const char* Mips::MipsFCCToString(Mips::CondCode CC) { llvm_unreachable("Impossible condition code!"); } -StringRef MipsInstPrinter::getOpcodeName(unsigned Opcode) const { - return getInstructionName(Opcode); -} - void MipsInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const { - OS << '$' << LowercaseString(getRegisterName(RegNo)); + OS << '$' << StringRef(getRegisterName(RegNo)).lower(); } void MipsInstPrinter::printInst(const MCInst *MI, raw_ostream &O, @@ -75,6 +72,59 @@ void MipsInstPrinter::printInst(const MCInst *MI, raw_ostream &O, printAnnotation(O, Annot); } +static void printExpr(const MCExpr *Expr, raw_ostream &OS) { + int Offset = 0; + const MCSymbolRefExpr *SRE; + + if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr)) { + SRE = dyn_cast<MCSymbolRefExpr>(BE->getLHS()); + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(BE->getRHS()); + assert(SRE && CE && "Binary expression must be sym+const."); + Offset = CE->getValue(); + } + else if (!(SRE = dyn_cast<MCSymbolRefExpr>(Expr))) + assert(false && "Unexpected MCExpr type."); + + MCSymbolRefExpr::VariantKind Kind = SRE->getKind(); + + switch (Kind) { + default: llvm_unreachable("Invalid kind!"); + case MCSymbolRefExpr::VK_None: break; + case MCSymbolRefExpr::VK_Mips_GPREL: OS << "%gp_rel("; break; + case MCSymbolRefExpr::VK_Mips_GOT_CALL: OS << "%call16("; break; + case MCSymbolRefExpr::VK_Mips_GOT16: OS << "%got("; break; + case MCSymbolRefExpr::VK_Mips_GOT: OS << "%got("; break; + case MCSymbolRefExpr::VK_Mips_ABS_HI: OS << "%hi("; break; + case MCSymbolRefExpr::VK_Mips_ABS_LO: OS << "%lo("; break; + case MCSymbolRefExpr::VK_Mips_TLSGD: OS << "%tlsgd("; break; + case MCSymbolRefExpr::VK_Mips_TLSLDM: OS << "%tlsldm("; break; + case MCSymbolRefExpr::VK_Mips_DTPREL_HI: OS << "%dtprel_hi("; break; + case MCSymbolRefExpr::VK_Mips_DTPREL_LO: OS << "%dtprel_lo("; break; + case MCSymbolRefExpr::VK_Mips_GOTTPREL: OS << "%gottprel("; break; + case MCSymbolRefExpr::VK_Mips_TPREL_HI: OS << "%tprel_hi("; break; + case MCSymbolRefExpr::VK_Mips_TPREL_LO: OS << "%tprel_lo("; break; + case MCSymbolRefExpr::VK_Mips_GPOFF_HI: OS << "%hi(%neg(%gp_rel("; break; + case MCSymbolRefExpr::VK_Mips_GPOFF_LO: OS << "%lo(%neg(%gp_rel("; break; + case MCSymbolRefExpr::VK_Mips_GOT_DISP: OS << "%got_disp("; break; + case MCSymbolRefExpr::VK_Mips_GOT_PAGE: OS << "%got_page("; break; + case MCSymbolRefExpr::VK_Mips_GOT_OFST: OS << "%got_ofst("; break; + } + + OS << SRE->getSymbol(); + + if (Offset) { + if (Offset > 0) + OS << '+'; + OS << Offset; + } + + if ((Kind == MCSymbolRefExpr::VK_Mips_GPOFF_HI) || + (Kind == MCSymbolRefExpr::VK_Mips_GPOFF_LO)) + OS << ")))"; + else if (Kind != MCSymbolRefExpr::VK_None) + OS << ')'; +} + void MipsInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) { const MCOperand &Op = MI->getOperand(OpNo); @@ -82,14 +132,14 @@ void MipsInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, printRegName(O, Op.getReg()); return; } - + if (Op.isImm()) { O << Op.getImm(); return; } - + assert(Op.isExpr() && "unknown operand kind in printOperand"); - O << *Op.getExpr(); + printExpr(Op.getExpr(), O); } void MipsInstPrinter::printUnsignedImm(const MCInst *MI, int opNum, diff --git a/lib/Target/Mips/InstPrinter/MipsInstPrinter.h b/lib/Target/Mips/InstPrinter/MipsInstPrinter.h index 5c1116538c61..76b839b2127f 100644 --- a/lib/Target/Mips/InstPrinter/MipsInstPrinter.h +++ b/lib/Target/Mips/InstPrinter/MipsInstPrinter.h @@ -1,4 +1,4 @@ -//===-- MipsInstPrinter.h - Convert Mips MCInst to assembly syntax --------===// +//=== MipsInstPrinter.h - Convert Mips MCInst to assembly syntax -*- C++ -*-==// // // The LLVM Compiler Infrastructure // @@ -18,7 +18,7 @@ namespace llvm { // These enumeration declarations were orignally in MipsInstrInfo.h but // had to be moved here to avoid circular dependencies between -// LLVMMipsCodeGen and LLVMMipsAsmPrinter. +// LLVMMipsCodeGen and LLVMMipsAsmPrinter. namespace Mips { // Mips Branch Codes enum FPBranchCode { @@ -77,17 +77,17 @@ class TargetMachine; class MipsInstPrinter : public MCInstPrinter { public: - MipsInstPrinter(const MCAsmInfo &MAI) : MCInstPrinter(MAI) {} - + MipsInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, + const MCRegisterInfo &MRI) + : MCInstPrinter(MAI, MII, MRI) {} + // Autogenerated by tblgen. void printInstruction(const MCInst *MI, raw_ostream &O); - static const char *getInstructionName(unsigned Opcode); static const char *getRegisterName(unsigned RegNo); - - virtual StringRef getOpcodeName(unsigned Opcode) const; + virtual void printRegName(raw_ostream &OS, unsigned RegNo) const; virtual void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot); - + private: void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); void printUnsignedImm(const MCInst *MI, int opNum, raw_ostream &O); diff --git a/lib/Target/Mips/LLVMBuild.txt b/lib/Target/Mips/LLVMBuild.txt new file mode 100644 index 000000000000..abbed8c90fc8 --- /dev/null +++ b/lib/Target/Mips/LLVMBuild.txt @@ -0,0 +1,34 @@ +;===- ./lib/Target/Mips/LLVMBuild.txt --------------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[common] +subdirectories = AsmParser InstPrinter MCTargetDesc TargetInfo + +[component_0] +type = TargetGroup +name = Mips +parent = Target +has_asmparser = 1 +has_asmprinter = 1 +has_jit = 1 + +[component_1] +type = Library +name = MipsCodeGen +parent = Mips +required_libraries = AsmPrinter CodeGen Core MC MipsAsmPrinter MipsDesc MipsInfo SelectionDAG Support Target +add_to_library_groups = Mips diff --git a/lib/Target/Mips/MCTargetDesc/CMakeLists.txt b/lib/Target/Mips/MCTargetDesc/CMakeLists.txt index 2ceb5c95746b..fa231507a2ef 100644 --- a/lib/Target/Mips/MCTargetDesc/CMakeLists.txt +++ b/lib/Target/Mips/MCTargetDesc/CMakeLists.txt @@ -3,13 +3,7 @@ add_llvm_library(LLVMMipsDesc MipsMCAsmInfo.cpp MipsMCCodeEmitter.cpp MipsMCTargetDesc.cpp - ) - -add_llvm_library_dependencies(LLVMMipsDesc - LLVMMC - LLVMMipsAsmPrinter - LLVMMipsInfo - LLVMSupport + MipsELFObjectWriter.cpp ) add_dependencies(LLVMMipsDesc MipsCommonTableGen) diff --git a/lib/Target/Mips/MCTargetDesc/LLVMBuild.txt b/lib/Target/Mips/MCTargetDesc/LLVMBuild.txt new file mode 100644 index 000000000000..29f5da691180 --- /dev/null +++ b/lib/Target/Mips/MCTargetDesc/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/Mips/MCTargetDesc/LLVMBuild.txt -------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = MipsDesc +parent = Mips +required_libraries = MC MipsAsmPrinter MipsInfo Support +add_to_library_groups = Mips diff --git a/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp b/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp index f190ec42c776..e79be3363623 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp @@ -1,44 +1,172 @@ +//===-- MipsASMBackend.cpp - Mips Asm Backend ----------------------------===// +// +// 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 MipsAsmBackend and MipsELFObjectWriter classes. +// +//===----------------------------------------------------------------------===// +// + +#include "MipsBaseInfo.h" +#include "MipsFixupKinds.h" #include "MCTargetDesc/MipsMCTargetDesc.h" -#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCELFObjectWriter.h" -#include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCMachObjectWriter.h" +#include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCObjectWriter.h" -#include "llvm/MC/MCSectionELF.h" -#include "llvm/MC/MCSectionMachO.h" -#include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCSubtargetInfo.h" -#include "llvm/Object/MachOFormat.h" -#include "llvm/Support/ELF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" + using namespace llvm; -namespace { -class MipsELFObjectWriter : public MCELFObjectTargetWriter { -public: - MipsELFObjectWriter(bool is64Bit, Triple::OSType OSType, uint16_t EMachine, - bool HasRelocationAddend) - : MCELFObjectTargetWriter(is64Bit, OSType, EMachine, - HasRelocationAddend) {} -}; +// Prepare value for the target space for it +static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { + + // Add/subtract and shift + switch (Kind) { + default: + return 0; + case FK_GPRel_4: + case FK_Data_4: + case Mips::fixup_Mips_LO16: + break; + case Mips::fixup_Mips_PC16: + // So far we are only using this type for branches. + // For branches we start 1 instruction after the branch + // so the displacement will be one instruction size less. + Value -= 4; + // The displacement is then divided by 4 to give us an 18 bit + // address range. + Value >>= 2; + break; + case Mips::fixup_Mips_26: + // So far we are only using this type for jumps. + // The displacement is then divided by 4 to give us an 28 bit + // address range. + Value >>= 2; + break; + case Mips::fixup_Mips_HI16: + case Mips::fixup_Mips_GOT_Local: + // Get the higher 16-bits. Also add 1 if bit 15 is 1. + Value = ((Value + 0x8000) >> 16) & 0xffff; + break; + } + + return Value; +} +namespace { class MipsAsmBackend : public MCAsmBackend { + Triple::OSType OSType; + bool IsLittle; // Big or little endian + bool Is64Bit; // 32 or 64 bit words + public: - MipsAsmBackend(const Target &T) - : MCAsmBackend() {} + MipsAsmBackend(const Target &T, Triple::OSType _OSType, + bool _isLittle, bool _is64Bit) + :MCAsmBackend(), OSType(_OSType), IsLittle(_isLittle), Is64Bit(_is64Bit) {} - unsigned getNumFixupKinds() const { - return 1; //tbd + MCObjectWriter *createObjectWriter(raw_ostream &OS) const { + return createMipsELFObjectWriter(OS, OSType, IsLittle, Is64Bit); } /// ApplyFixup - Apply the \arg Value for given \arg Fixup into the provided /// data fragment, at the offset specified by the fixup and following the /// fixup kind as appropriate. - void ApplyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, + void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, uint64_t Value) const { + MCFixupKind Kind = Fixup.getKind(); + Value = adjustFixupValue((unsigned)Kind, Value); + int64_t SymOffset = MipsGetSymAndOffset(Fixup).second; + + if (!Value && !SymOffset) + return; // Doesn't change encoding. + + // Where do we start in the object + unsigned Offset = Fixup.getOffset(); + // Number of bytes we need to fixup + unsigned NumBytes = (getFixupKindInfo(Kind).TargetSize + 7) / 8; + // Used to point to big endian bytes + unsigned FullSize; + + switch ((unsigned)Kind) { + case Mips::fixup_Mips_16: + FullSize = 2; + break; + case Mips::fixup_Mips_64: + FullSize = 8; + break; + default: + FullSize = 4; + break; + } + + // Grab current value, if any, from bits. + uint64_t CurVal = 0; + + for (unsigned i = 0; i != NumBytes; ++i) { + unsigned Idx = IsLittle ? i : (FullSize - 1 - i); + CurVal |= (uint64_t)((uint8_t)Data[Offset + Idx]) << (i*8); + } + + uint64_t Mask = ((uint64_t)(-1) >> (64 - getFixupKindInfo(Kind).TargetSize)); + CurVal |= (Value + SymOffset) & Mask; + + // Write out the fixed up bytes back to the code/data bits. + for (unsigned i = 0; i != NumBytes; ++i) { + unsigned Idx = IsLittle ? i : (FullSize - 1 - i); + Data[Offset + Idx] = (uint8_t)((CurVal >> (i*8)) & 0xff); + } + } + + unsigned getNumFixupKinds() const { return Mips::NumTargetFixupKinds; } + + const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const { + const static MCFixupKindInfo Infos[Mips::NumTargetFixupKinds] = { + // This table *must* be in same the order of fixup_* kinds in + // MipsFixupKinds.h. + // + // name offset bits flags + { "fixup_Mips_16", 0, 16, 0 }, + { "fixup_Mips_32", 0, 32, 0 }, + { "fixup_Mips_REL32", 0, 32, 0 }, + { "fixup_Mips_26", 0, 26, 0 }, + { "fixup_Mips_HI16", 0, 16, 0 }, + { "fixup_Mips_LO16", 0, 16, 0 }, + { "fixup_Mips_GPREL16", 0, 16, 0 }, + { "fixup_Mips_LITERAL", 0, 16, 0 }, + { "fixup_Mips_GOT_Global", 0, 16, 0 }, + { "fixup_Mips_GOT_Local", 0, 16, 0 }, + { "fixup_Mips_PC16", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_Mips_CALL16", 0, 16, 0 }, + { "fixup_Mips_GPREL32", 0, 32, 0 }, + { "fixup_Mips_SHIFT5", 6, 5, 0 }, + { "fixup_Mips_SHIFT6", 6, 5, 0 }, + { "fixup_Mips_64", 0, 64, 0 }, + { "fixup_Mips_TLSGD", 0, 16, 0 }, + { "fixup_Mips_GOTTPREL", 0, 16, 0 }, + { "fixup_Mips_TPREL_HI", 0, 16, 0 }, + { "fixup_Mips_TPREL_LO", 0, 16, 0 }, + { "fixup_Mips_TLSLDM", 0, 16, 0 }, + { "fixup_Mips_DTPREL_HI", 0, 16, 0 }, + { "fixup_Mips_DTPREL_LO", 0, 16, 0 }, + { "fixup_Mips_Branch_PCRel", 0, 16, MCFixupKindInfo::FKF_IsPCRel } + }; + + if (Kind < FirstTargetFixupKind) + return MCAsmBackend::getFixupKindInfo(Kind); + + assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && + "Invalid kind!"); + return Infos[Kind - FirstTargetFixupKind]; } /// @name Target Relaxation Interfaces @@ -48,70 +176,62 @@ public: /// relaxation. /// /// \param Inst - The instruction to test. - bool MayNeedRelaxation(const MCInst &Inst) const { + bool mayNeedRelaxation(const MCInst &Inst) const { return false; } - /// RelaxInstruction - Relax the instruction in the given fragment to the next - /// wider instruction. + /// fixupNeedsRelaxation - Target specific predicate for whether a given + /// fixup requires the associated instruction to be relaxed. + bool fixupNeedsRelaxation(const MCFixup &Fixup, + uint64_t Value, + const MCInstFragment *DF, + const MCAsmLayout &Layout) const { + // FIXME. + assert(0 && "RelaxInstruction() unimplemented"); + return false; + } + + /// RelaxInstruction - Relax the instruction in the given fragment + /// to the next wider instruction. /// - /// \param Inst - The instruction to relax, which may be the same as the - /// output. + /// \param Inst - The instruction to relax, which may be the same + /// as the output. /// \parm Res [output] - On return, the relaxed instruction. - void RelaxInstruction(const MCInst &Inst, MCInst &Res) const { + void relaxInstruction(const MCInst &Inst, MCInst &Res) const { } - + /// @} - /// WriteNopData - Write an (optimal) nop sequence of Count bytes to the given - /// output. If the target cannot generate such a sequence, it should return an - /// error. + /// WriteNopData - Write an (optimal) nop sequence of Count bytes + /// to the given output. If the target cannot generate such a sequence, + /// it should return an error. /// /// \return - True on success. - bool WriteNopData(uint64_t Count, MCObjectWriter *OW) const { - return false; + bool writeNopData(uint64_t Count, MCObjectWriter *OW) const { + return true; } -}; +}; // class MipsAsmBackend -class MipsEB_AsmBackend : public MipsAsmBackend { -public: - Triple::OSType OSType; - - MipsEB_AsmBackend(const Target &T, Triple::OSType _OSType) - : MipsAsmBackend(T), OSType(_OSType) {} - - MCObjectWriter *createObjectWriter(raw_ostream &OS) const { - return createELFObjectWriter(createELFObjectTargetWriter(), - OS, /*IsLittleEndian*/ false); - } - - MCELFObjectTargetWriter *createELFObjectTargetWriter() const { - return new MipsELFObjectWriter(false, OSType, ELF::EM_MIPS, false); - } -}; - -class MipsEL_AsmBackend : public MipsAsmBackend { -public: - Triple::OSType OSType; - - MipsEL_AsmBackend(const Target &T, Triple::OSType _OSType) - : MipsAsmBackend(T), OSType(_OSType) {} +} // namespace - MCObjectWriter *createObjectWriter(raw_ostream &OS) const { - return createELFObjectWriter(createELFObjectTargetWriter(), - OS, /*IsLittleEndian*/ true); - } +// MCAsmBackend +MCAsmBackend *llvm::createMipsAsmBackendEL32(const Target &T, StringRef TT) { + return new MipsAsmBackend(T, Triple(TT).getOS(), + /*IsLittle*/true, /*Is64Bit*/false); +} - MCELFObjectTargetWriter *createELFObjectTargetWriter() const { - return new MipsELFObjectWriter(false, OSType, ELF::EM_MIPS, false); - } -}; +MCAsmBackend *llvm::createMipsAsmBackendEB32(const Target &T, StringRef TT) { + return new MipsAsmBackend(T, Triple(TT).getOS(), + /*IsLittle*/false, /*Is64Bit*/false); } -MCAsmBackend *llvm::createMipsAsmBackend(const Target &T, StringRef TT) { - Triple TheTriple(TT); +MCAsmBackend *llvm::createMipsAsmBackendEL64(const Target &T, StringRef TT) { + return new MipsAsmBackend(T, Triple(TT).getOS(), + /*IsLittle*/true, /*Is64Bit*/true); +} - // just return little endian for now - // - return new MipsEL_AsmBackend(T, Triple(TT).getOS()); +MCAsmBackend *llvm::createMipsAsmBackendEB64(const Target &T, StringRef TT) { + return new MipsAsmBackend(T, Triple(TT).getOS(), + /*IsLittle*/false, /*Is64Bit*/true); } + diff --git a/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h b/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h index f7a6fa949091..fb1c5ce6b6c6 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h +++ b/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h @@ -1,4 +1,4 @@ -//===-- MipsBaseInfo.h - Top level definitions for ARM ------- --*- C++ -*-===// +//===-- MipsBaseInfo.h - Top level definitions for MIPS MC ------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,11 +14,103 @@ #ifndef MIPSBASEINFO_H #define MIPSBASEINFO_H +#include "MipsFixupKinds.h" #include "MipsMCTargetDesc.h" +#include "llvm/MC/MCExpr.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/ErrorHandling.h" namespace llvm { + +/// 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_GOT16 - Represents the offset into the global offset table at which + /// the address the relocation entry symbol resides during execution. + MO_GOT16, + 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_HI/LO - Represents the hi or low part of an absolute symbol + /// address. + MO_ABS_HI, + MO_ABS_LO, + + /// MO_TLSGD - Represents the offset into the global offset table at which + // the module ID and TSL block offset reside during execution (General + // Dynamic TLS). + MO_TLSGD, + + /// MO_TLSLDM - Represents the offset into the global offset table at which + // the module ID and TSL block offset reside during execution (Local + // Dynamic TLS). + MO_TLSLDM, + MO_DTPREL_HI, + MO_DTPREL_LO, + + /// MO_GOTTPREL - Represents the offset from the thread pointer (Initial + // Exec TLS). + MO_GOTTPREL, + + /// MO_TPREL_HI/LO - Represents the hi and low part of the offset from + // the thread pointer (Local Exec TLS). + MO_TPREL_HI, + MO_TPREL_LO, + + // N32/64 Flags. + MO_GPOFF_HI, + MO_GPOFF_LO, + MO_GOT_DISP, + MO_GOT_PAGE, + MO_GOT_OFST + }; + + enum { + //===------------------------------------------------------------------===// + // Instruction encodings. These are the standard/most common forms for + // Mips instructions. + // + + // Pseudo - This represents an instruction that is a pseudo instruction + // or one that has not been implemented yet. It is illegal to code generate + // it, but tolerated for intermediate implementation stages. + Pseudo = 0, + + /// FrmR - This form is for instructions of the format R. + FrmR = 1, + /// FrmI - This form is for instructions of the format I. + FrmI = 2, + /// FrmJ - This form is for instructions of the format J. + FrmJ = 3, + /// FrmFR - This form is for instructions of the format FR. + FrmFR = 4, + /// FrmFI - This form is for instructions of the format FI. + FrmFI = 5, + /// FrmOther - This form is for instructions that have no specific format. + FrmOther = 6, + + FormMask = 15 + }; +} + + /// getMipsRegisterNumbering - Given the enum value for some register, /// return the number that it corresponds to. inline static unsigned getMipsRegisterNumbering(unsigned RegEnum) @@ -98,15 +190,43 @@ inline static unsigned getMipsRegisterNumbering(unsigned RegEnum) case Mips::D14: return 28; case Mips::SP: case Mips::SP_64: case Mips::F29: case Mips::D29_64: + case Mips::HWR29: return 29; case Mips::FP: case Mips::FP_64: case Mips::F30: case Mips::D30_64: - case Mips::D15: + case Mips::D15: return 30; case Mips::RA: case Mips::RA_64: case Mips::F31: case Mips::D31_64: return 31; default: llvm_unreachable("Unknown register number!"); } - return 0; // Not reached +} + +inline static std::pair<const MCSymbolRefExpr*, int64_t> +MipsGetSymAndOffset(const MCFixup &Fixup) { + MCFixupKind FixupKind = Fixup.getKind(); + + if ((FixupKind < FirstTargetFixupKind) || + (FixupKind >= MCFixupKind(Mips::LastTargetFixupKind))) + return std::make_pair((const MCSymbolRefExpr*)0, (int64_t)0); + + const MCExpr *Expr = Fixup.getValue(); + MCExpr::ExprKind Kind = Expr->getKind(); + + if (Kind == MCExpr::Binary) { + const MCBinaryExpr *BE = static_cast<const MCBinaryExpr*>(Expr); + const MCExpr *LHS = BE->getLHS(); + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(BE->getRHS()); + + if ((LHS->getKind() != MCExpr::SymbolRef) || !CE) + return std::make_pair((const MCSymbolRefExpr*)0, (int64_t)0); + + return std::make_pair(cast<MCSymbolRefExpr>(LHS), CE->getValue()); + } + + if (Kind != MCExpr::SymbolRef) + return std::make_pair((const MCSymbolRefExpr*)0, (int64_t)0); + + return std::make_pair(cast<MCSymbolRefExpr>(Expr), 0); } } diff --git a/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp b/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp new file mode 100644 index 000000000000..2091bec50082 --- /dev/null +++ b/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp @@ -0,0 +1,249 @@ +//===-- MipsELFObjectWriter.cpp - Mips ELF Writer -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MCTargetDesc/MipsFixupKinds.h" +#include "MCTargetDesc/MipsMCTargetDesc.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/ErrorHandling.h" +#include <list> + +using namespace llvm; + +namespace { + struct RelEntry { + RelEntry(const ELFRelocationEntry &R, const MCSymbol *S, int64_t O) : + Reloc(R), Sym(S), Offset(O) {} + ELFRelocationEntry Reloc; + const MCSymbol *Sym; + int64_t Offset; + }; + + typedef std::list<RelEntry> RelLs; + typedef RelLs::iterator RelLsIter; + + class MipsELFObjectWriter : public MCELFObjectTargetWriter { + public: + MipsELFObjectWriter(bool _is64Bit, uint8_t OSABI); + + virtual ~MipsELFObjectWriter(); + + virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, + bool IsPCRel, bool IsRelocWithSymbol, + int64_t Addend) const; + virtual unsigned getEFlags() const; + virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + const MCFixup &Fixup, + bool IsPCRel) const; + virtual void sortRelocs(const MCAssembler &Asm, + std::vector<ELFRelocationEntry> &Relocs); + }; +} + +MipsELFObjectWriter::MipsELFObjectWriter(bool _is64Bit, uint8_t OSABI) + : MCELFObjectTargetWriter(_is64Bit, OSABI, ELF::EM_MIPS, + /*HasRelocationAddend*/ false) {} + +MipsELFObjectWriter::~MipsELFObjectWriter() {} + +// FIXME: get the real EABI Version from the Subtarget class. +unsigned MipsELFObjectWriter::getEFlags() const { + + // FIXME: We can't tell if we are PIC (dynamic) or CPIC (static) + unsigned Flag = ELF::EF_MIPS_NOREORDER; + + if (is64Bit()) + Flag |= ELF::EF_MIPS_ARCH_64R2; + else + Flag |= ELF::EF_MIPS_ARCH_32R2; + return Flag; +} + +const MCSymbol *MipsELFObjectWriter::ExplicitRelSym(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + const MCFixup &Fixup, + bool IsPCRel) const { + assert(Target.getSymA() && "SymA cannot be 0."); + const MCSymbol &Sym = Target.getSymA()->getSymbol().AliasedSymbol(); + + if (Sym.getSection().getKind().isMergeableCString() || + Sym.getSection().getKind().isMergeableConst()) + return &Sym; + + return NULL; +} + +unsigned MipsELFObjectWriter::GetRelocType(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel, + bool IsRelocWithSymbol, + int64_t Addend) const { + // determine the type of the relocation + unsigned Type = (unsigned)ELF::R_MIPS_NONE; + unsigned Kind = (unsigned)Fixup.getKind(); + + switch (Kind) { + default: + llvm_unreachable("invalid fixup kind!"); + case FK_Data_4: + Type = ELF::R_MIPS_32; + break; + case FK_GPRel_4: + Type = ELF::R_MIPS_GPREL32; + break; + case Mips::fixup_Mips_GPREL16: + Type = ELF::R_MIPS_GPREL16; + break; + case Mips::fixup_Mips_26: + Type = ELF::R_MIPS_26; + break; + case Mips::fixup_Mips_CALL16: + Type = ELF::R_MIPS_CALL16; + break; + case Mips::fixup_Mips_GOT_Global: + case Mips::fixup_Mips_GOT_Local: + Type = ELF::R_MIPS_GOT16; + break; + case Mips::fixup_Mips_HI16: + Type = ELF::R_MIPS_HI16; + break; + case Mips::fixup_Mips_LO16: + Type = ELF::R_MIPS_LO16; + break; + case Mips::fixup_Mips_TLSGD: + Type = ELF::R_MIPS_TLS_GD; + break; + case Mips::fixup_Mips_GOTTPREL: + Type = ELF::R_MIPS_TLS_GOTTPREL; + break; + case Mips::fixup_Mips_TPREL_HI: + Type = ELF::R_MIPS_TLS_TPREL_HI16; + break; + case Mips::fixup_Mips_TPREL_LO: + Type = ELF::R_MIPS_TLS_TPREL_LO16; + break; + case Mips::fixup_Mips_TLSLDM: + Type = ELF::R_MIPS_TLS_LDM; + break; + case Mips::fixup_Mips_DTPREL_HI: + Type = ELF::R_MIPS_TLS_DTPREL_HI16; + break; + case Mips::fixup_Mips_DTPREL_LO: + Type = ELF::R_MIPS_TLS_DTPREL_LO16; + break; + case Mips::fixup_Mips_Branch_PCRel: + case Mips::fixup_Mips_PC16: + Type = ELF::R_MIPS_PC16; + break; + } + + return Type; +} + +// Return true if R is either a GOT16 against a local symbol or HI16. +static bool NeedsMatchingLo(const MCAssembler &Asm, const RelEntry &R) { + if (!R.Sym) + return false; + + MCSymbolData &SD = Asm.getSymbolData(R.Sym->AliasedSymbol()); + + return ((R.Reloc.Type == ELF::R_MIPS_GOT16) && !SD.isExternal()) || + (R.Reloc.Type == ELF::R_MIPS_HI16); +} + +static bool HasMatchingLo(const MCAssembler &Asm, RelLsIter I, RelLsIter Last) { + if (I == Last) + return false; + + RelLsIter Hi = I++; + + return (I->Reloc.Type == ELF::R_MIPS_LO16) && (Hi->Sym == I->Sym) && + (Hi->Offset == I->Offset); +} + +static bool HasSameSymbol(const RelEntry &R0, const RelEntry &R1) { + return R0.Sym == R1.Sym; +} + +static int CompareOffset(const RelEntry &R0, const RelEntry &R1) { + return (R0.Offset > R1.Offset) ? 1 : ((R0.Offset == R1.Offset) ? 0 : -1); +} + +void MipsELFObjectWriter::sortRelocs(const MCAssembler &Asm, + std::vector<ELFRelocationEntry> &Relocs) { + // Call the defualt function first. Relocations are sorted in descending + // order of r_offset. + MCELFObjectTargetWriter::sortRelocs(Asm, Relocs); + + RelLs RelocLs; + std::vector<RelLsIter> Unmatched; + + // Fill RelocLs. Traverse Relocs backwards so that relocations in RelocLs + // are in ascending order of r_offset. + for (std::vector<ELFRelocationEntry>::reverse_iterator R = Relocs.rbegin(); + R != Relocs.rend(); ++R) { + std::pair<const MCSymbolRefExpr*, int64_t> P = + MipsGetSymAndOffset(*R->Fixup); + RelocLs.push_back(RelEntry(*R, P.first ? &P.first->getSymbol() : 0, + P.second)); + } + + // Get list of unmatched HI16 and GOT16. + for (RelLsIter R = RelocLs.begin(); R != RelocLs.end(); ++R) + if (NeedsMatchingLo(Asm, *R) && !HasMatchingLo(Asm, R, --RelocLs.end())) + Unmatched.push_back(R); + + // Insert unmatched HI16 and GOT16 immediately before their matching LO16. + for (std::vector<RelLsIter>::iterator U = Unmatched.begin(); + U != Unmatched.end(); ++U) { + RelLsIter LoPos = RelocLs.end(), HiPos = *U; + bool MatchedLo = false; + + for (RelLsIter R = RelocLs.begin(); R != RelocLs.end(); ++R) { + if ((R->Reloc.Type == ELF::R_MIPS_LO16) && HasSameSymbol(*HiPos, *R) && + (CompareOffset(*R, *HiPos) >= 0) && + ((LoPos == RelocLs.end()) || ((CompareOffset(*R, *LoPos) < 0)) || + (!MatchedLo && !CompareOffset(*R, *LoPos)))) + LoPos = R; + + MatchedLo = NeedsMatchingLo(Asm, *R) && + HasMatchingLo(Asm, R, --RelocLs.end()); + } + + // If a matching LoPos was found, move HiPos and insert it before LoPos. + // Make the offsets of HiPos and LoPos match. + if (LoPos != RelocLs.end()) { + HiPos->Offset = LoPos->Offset; + RelocLs.insert(LoPos, *HiPos); + RelocLs.erase(HiPos); + } + } + + // Put the sorted list back in reverse order. + assert(Relocs.size() == RelocLs.size()); + unsigned I = RelocLs.size(); + + for (RelLsIter R = RelocLs.begin(); R != RelocLs.end(); ++R) + Relocs[--I] = R->Reloc; +} + +MCObjectWriter *llvm::createMipsELFObjectWriter(raw_ostream &OS, + uint8_t OSABI, + bool IsLittleEndian, + bool Is64Bit) { + MCELFObjectTargetWriter *MOTW = new MipsELFObjectWriter(Is64Bit, OSABI); + return createELFObjectWriter(MOTW, OS, IsLittleEndian); +} diff --git a/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h b/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h index 8b099eab91fd..9b76eda861dc 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h +++ b/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h @@ -1,7 +1,4 @@ -#ifndef LLVM_Mips_MipsFIXUPKINDS_H -#define LLVM_Mips_MipsFIXUPKINDS_H - -//===-- Mips/MipsFixupKinds.h - Mips Specific Fixup Entries --------*- C++ -*-===// +//===-- MipsFixupKinds.h - Mips Specific Fixup Entries ----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,81 +7,100 @@ // //===----------------------------------------------------------------------===// +#ifndef LLVM_MIPS_MIPSFIXUPKINDS_H +#define LLVM_MIPS_MIPSFIXUPKINDS_H #include "llvm/MC/MCFixup.h" namespace llvm { namespace Mips { - enum Fixups { - // fixup_Mips_xxx - R_MIPS_NONE - fixup_Mips_NONE = FirstTargetFixupKind, + // Although most of the current fixup types reflect a unique relocation + // one can have multiple fixup types for a given relocation and thus need + // to be uniquely named. + // + // This table *must* be in the save order of + // MCFixupKindInfo Infos[Mips::NumTargetFixupKinds] + // in MipsAsmBackend.cpp. + // + enum Fixups { + // Branch fixups resulting in R_MIPS_16. + fixup_Mips_16 = FirstTargetFixupKind, - // fixup_Mips_xxx - R_MIPS_16. - fixup_Mips_16, + // Pure 32 bit data fixup resulting in - R_MIPS_32. + fixup_Mips_32, - // fixup_Mips_xxx - R_MIPS_32. - fixup_Mips_32, + // Full 32 bit data relative data fixup resulting in - R_MIPS_REL32. + fixup_Mips_REL32, - // fixup_Mips_xxx - R_MIPS_REL32. - fixup_Mips_REL32, + // Jump 26 bit fixup resulting in - R_MIPS_26. + fixup_Mips_26, - // fixup_Mips_xxx - R_MIPS_26. - fixup_Mips_26, + // Pure upper 16 bit fixup resulting in - R_MIPS_HI16. + fixup_Mips_HI16, - // fixup_Mips_xxx - R_MIPS_HI16. - fixup_Mips_HI16, + // Pure lower 16 bit fixup resulting in - R_MIPS_LO16. + fixup_Mips_LO16, - // fixup_Mips_xxx - R_MIPS_LO16. - fixup_Mips_LO16, + // 16 bit fixup for GP offest resulting in - R_MIPS_GPREL16. + fixup_Mips_GPREL16, - // fixup_Mips_xxx - R_MIPS_GPREL16. - fixup_Mips_GPREL16, + // 16 bit literal fixup resulting in - R_MIPS_LITERAL. + fixup_Mips_LITERAL, - // fixup_Mips_xxx - R_MIPS_LITERAL. - fixup_Mips_LITERAL, + // Global symbol fixup resulting in - R_MIPS_GOT16. + fixup_Mips_GOT_Global, - // fixup_Mips_xxx - R_MIPS_GOT16. - fixup_Mips_GOT16, + // Local symbol fixup resulting in - R_MIPS_GOT16. + fixup_Mips_GOT_Local, - // fixup_Mips_xxx - R_MIPS_PC16. - fixup_Mips_PC16, + // PC relative branch fixup resulting in - R_MIPS_PC16. + fixup_Mips_PC16, - // fixup_Mips_xxx - R_MIPS_CALL16. - fixup_Mips_CALL16, + // resulting in - R_MIPS_CALL16. + fixup_Mips_CALL16, - // fixup_Mips_xxx - R_MIPS_GPREL32. - fixup_Mips_GPREL32, + // resulting in - R_MIPS_GPREL32. + fixup_Mips_GPREL32, - // fixup_Mips_xxx - R_MIPS_SHIFT5. - fixup_Mips_SHIFT5, + // resulting in - R_MIPS_SHIFT5. + fixup_Mips_SHIFT5, - // fixup_Mips_xxx - R_MIPS_SHIFT6. - fixup_Mips_SHIFT6, + // resulting in - R_MIPS_SHIFT6. + fixup_Mips_SHIFT6, - // fixup_Mips_xxx - R_MIPS_64. - fixup_Mips_64, + // Pure 64 bit data fixup resulting in - R_MIPS_64. + fixup_Mips_64, - // fixup_Mips_xxx - R_MIPS_TLS_GD. - fixup_Mips_TLSGD, + // resulting in - R_MIPS_TLS_GD. + fixup_Mips_TLSGD, - // fixup_Mips_xxx - R_MIPS_TLS_GOTTPREL. - fixup_Mips_GOTTPREL, + // resulting in - R_MIPS_TLS_GOTTPREL. + fixup_Mips_GOTTPREL, - // fixup_Mips_xxx - R_MIPS_TLS_TPREL_HI16. - fixup_Mips_TPREL_HI, + // resulting in - R_MIPS_TLS_TPREL_HI16. + fixup_Mips_TPREL_HI, - // fixup_Mips_xxx - R_MIPS_TLS_TPREL_LO16. - fixup_Mips_TPREL_LO, + // resulting in - R_MIPS_TLS_TPREL_LO16. + fixup_Mips_TPREL_LO, - // fixup_Mips_xxx - yyy. // This should become R_MIPS_PC16 - fixup_Mips_Branch_PCRel, + // resulting in - R_MIPS_TLS_LDM. + fixup_Mips_TLSLDM, - // Marker - LastTargetFixupKind, - NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind - }; -} // namespace llvm + // resulting in - R_MIPS_TLS_DTPREL_HI16. + fixup_Mips_DTPREL_HI, + + // resulting in - R_MIPS_TLS_DTPREL_LO16. + fixup_Mips_DTPREL_LO, + + // PC relative branch fixup resulting in - R_MIPS_PC16 + fixup_Mips_Branch_PCRel, + + // Marker + LastTargetFixupKind, + NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind + }; } // namespace Mips +} // namespace llvm -#endif /* LLVM_Mips_MipsFIXUPKINDS_H */ +#endif // LLVM_MIPS_MIPSFIXUPKINDS_H diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp b/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp index 71ae80498995..9d67aa1856e3 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp @@ -1,4 +1,4 @@ -//===-- MipsMCAsmInfo.cpp - Mips asm properties ---------------------------===// +//===-- MipsMCAsmInfo.cpp - Mips Asm Properties ---------------------------===// // // The LLVM Compiler Infrastructure // @@ -16,6 +16,8 @@ using namespace llvm; +void MipsMCAsmInfo::anchor() { } + MipsMCAsmInfo::MipsMCAsmInfo(const Target &T, StringRef TT) { Triple TheTriple(TT); if ((TheTriple.getArch() == Triple::mips) || @@ -25,11 +27,12 @@ MipsMCAsmInfo::MipsMCAsmInfo(const Target &T, StringRef TT) { AlignmentIsInBytes = false; Data16bitsDirective = "\t.2byte\t"; Data32bitsDirective = "\t.4byte\t"; - Data64bitsDirective = 0; + Data64bitsDirective = "\t.8byte\t"; PrivateGlobalPrefix = "$"; CommentString = "#"; ZeroDirective = "\t.space\t"; GPRel32Directive = "\t.gpword\t"; + GPRel64Directive = "\t.gpdword\t"; WeakRefDirective = "\t.weak\t"; SupportsDebugInformation = true; diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h b/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h index 41b719207b7b..e1d878936f31 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h +++ b/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h @@ -1,4 +1,4 @@ -//=====-- MipsMCAsmInfo.h - Mips asm properties ---------------*- C++ -*--====// +//===-- MipsMCAsmInfo.h - Mips Asm Info ------------------------*- C++ -*--===// // // The LLVM Compiler Infrastructure // @@ -14,13 +14,14 @@ #ifndef MIPSTARGETASMINFO_H #define MIPSTARGETASMINFO_H -#include "llvm/ADT/StringRef.h" #include "llvm/MC/MCAsmInfo.h" namespace llvm { + class StringRef; class Target; class MipsMCAsmInfo : public MCAsmInfo { + virtual void anchor(); public: explicit MipsMCAsmInfo(const Target &T, StringRef TT); }; diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp b/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp index d66de23ba115..27954b174ed9 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp @@ -1,4 +1,4 @@ -//===-- MipsMCCodeEmitter.cpp - Convert Mips code to machine code ---------===// +//===-- MipsMCCodeEmitter.cpp - Convert Mips Code to Machine Code ---------===// // // The LLVM Compiler Infrastructure // @@ -12,16 +12,18 @@ //===----------------------------------------------------------------------===// // #define DEBUG_TYPE "mccodeemitter" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MCTargetDesc/MipsFixupKinds.h" +#include "MCTargetDesc/MipsMCTargetDesc.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/Statistic.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" -#include "llvm/ADT/APFloat.h" -#include "llvm/ADT/Statistic.h" #include "llvm/Support/raw_ostream.h" -#include "MCTargetDesc/MipsMCTargetDesc.h" using namespace llvm; @@ -31,22 +33,252 @@ class MipsMCCodeEmitter : public MCCodeEmitter { void operator=(const MipsMCCodeEmitter &); // DO NOT IMPLEMENT const MCInstrInfo &MCII; const MCSubtargetInfo &STI; + MCContext &Ctx; + bool IsLittleEndian; public: MipsMCCodeEmitter(const MCInstrInfo &mcii, const MCSubtargetInfo &sti, - MCContext &ctx) - : MCII(mcii), STI(sti) {} + MCContext &ctx, bool IsLittle) : + MCII(mcii), STI(sti) , Ctx(ctx), IsLittleEndian(IsLittle) {} ~MipsMCCodeEmitter() {} - void EncodeInstruction(const MCInst &MI, raw_ostream &OS, - SmallVectorImpl<MCFixup> &Fixups) const { + void EmitByte(unsigned char C, raw_ostream &OS) const { + OS << (char)C; } + + void EmitInstruction(uint64_t Val, unsigned Size, raw_ostream &OS) const { + // Output the instruction encoding in little endian byte order. + for (unsigned i = 0; i < Size; ++i) { + unsigned Shift = IsLittleEndian ? i * 8 : (Size - 1 - i) * 8; + EmitByte((Val >> Shift) & 0xff, OS); + } + } + + void EncodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl<MCFixup> &Fixups) const; + + // getBinaryCodeForInstr - TableGen'erated function for getting the + // binary encoding for an instruction. + uint64_t getBinaryCodeForInstr(const MCInst &MI, + SmallVectorImpl<MCFixup> &Fixups) const; + + // getBranchJumpOpValue - Return binary encoding of the jump + // target operand. If the machine operand requires relocation, + // record the relocation and return zero. + unsigned getJumpTargetOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const; + + // getBranchTargetOpValue - Return binary encoding of the branch + // target operand. If the machine operand requires relocation, + // record the relocation and return zero. + unsigned getBranchTargetOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const; + + // getMachineOpValue - Return binary encoding of operand. If the machin + // operand requires relocation, record the relocation and return zero. + unsigned getMachineOpValue(const MCInst &MI,const MCOperand &MO, + SmallVectorImpl<MCFixup> &Fixups) const; + + unsigned getMemEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const; + unsigned getSizeExtEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const; + unsigned getSizeInsEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const; + }; // class MipsMCCodeEmitter } // namespace -MCCodeEmitter *llvm::createMipsMCCodeEmitter(const MCInstrInfo &MCII, - const MCSubtargetInfo &STI, - MCContext &Ctx) { - return new MipsMCCodeEmitter(MCII, STI, Ctx); +MCCodeEmitter *llvm::createMipsMCCodeEmitterEB(const MCInstrInfo &MCII, + const MCSubtargetInfo &STI, + MCContext &Ctx) +{ + return new MipsMCCodeEmitter(MCII, STI, Ctx, false); +} + +MCCodeEmitter *llvm::createMipsMCCodeEmitterEL(const MCInstrInfo &MCII, + const MCSubtargetInfo &STI, + MCContext &Ctx) +{ + return new MipsMCCodeEmitter(MCII, STI, Ctx, true); +} + +/// EncodeInstruction - Emit the instruction. +/// Size the instruction (currently only 4 bytes +void MipsMCCodeEmitter:: +EncodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl<MCFixup> &Fixups) const +{ + uint32_t Binary = getBinaryCodeForInstr(MI, Fixups); + + // Check for unimplemented opcodes. + // Unfortunately in MIPS both NOT and SLL will come in with Binary == 0 + // so we have to special check for them. + unsigned Opcode = MI.getOpcode(); + if ((Opcode != Mips::NOP) && (Opcode != Mips::SLL) && !Binary) + llvm_unreachable("unimplemented opcode in EncodeInstruction()"); + + const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); + uint64_t TSFlags = Desc.TSFlags; + + // Pseudo instructions don't get encoded and shouldn't be here + // in the first place! + if ((TSFlags & MipsII::FormMask) == MipsII::Pseudo) + llvm_unreachable("Pseudo opcode found in EncodeInstruction()"); + + // For now all instructions are 4 bytes + int Size = 4; // FIXME: Have Desc.getSize() return the correct value! + + EmitInstruction(Binary, Size, OS); } + +/// getBranchTargetOpValue - Return binary encoding of the branch +/// target operand. If the machine operand requires relocation, +/// record the relocation and return zero. +unsigned MipsMCCodeEmitter:: +getBranchTargetOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const { + + const MCOperand &MO = MI.getOperand(OpNo); + assert(MO.isExpr() && "getBranchTargetOpValue expects only expressions"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::Create(0, Expr, + MCFixupKind(Mips::fixup_Mips_PC16))); + return 0; +} + +/// getJumpTargetOpValue - Return binary encoding of the jump +/// target operand. If the machine operand requires relocation, +/// record the relocation and return zero. +unsigned MipsMCCodeEmitter:: +getJumpTargetOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const { + + const MCOperand &MO = MI.getOperand(OpNo); + assert(MO.isExpr() && "getJumpTargetOpValue expects only expressions"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::Create(0, Expr, + MCFixupKind(Mips::fixup_Mips_26))); + return 0; +} + +/// getMachineOpValue - Return binary encoding of operand. If the machine +/// operand requires relocation, record the relocation and return zero. +unsigned MipsMCCodeEmitter:: +getMachineOpValue(const MCInst &MI, const MCOperand &MO, + SmallVectorImpl<MCFixup> &Fixups) const { + if (MO.isReg()) { + unsigned Reg = MO.getReg(); + unsigned RegNo = getMipsRegisterNumbering(Reg); + return RegNo; + } else if (MO.isImm()) { + return static_cast<unsigned>(MO.getImm()); + } else if (MO.isFPImm()) { + return static_cast<unsigned>(APFloat(MO.getFPImm()) + .bitcastToAPInt().getHiBits(32).getLimitedValue()); + } + + // MO must be an Expr. + assert(MO.isExpr()); + + const MCExpr *Expr = MO.getExpr(); + MCExpr::ExprKind Kind = Expr->getKind(); + + if (Kind == MCExpr::Binary) { + Expr = static_cast<const MCBinaryExpr*>(Expr)->getLHS(); + Kind = Expr->getKind(); + } + + assert (Kind == MCExpr::SymbolRef); + + Mips::Fixups FixupKind; + + switch(cast<MCSymbolRefExpr>(Expr)->getKind()) { + case MCSymbolRefExpr::VK_Mips_GPREL: + FixupKind = Mips::fixup_Mips_GPREL16; + break; + case MCSymbolRefExpr::VK_Mips_GOT_CALL: + FixupKind = Mips::fixup_Mips_CALL16; + break; + case MCSymbolRefExpr::VK_Mips_GOT16: + FixupKind = Mips::fixup_Mips_GOT_Global; + break; + case MCSymbolRefExpr::VK_Mips_GOT: + FixupKind = Mips::fixup_Mips_GOT_Local; + break; + case MCSymbolRefExpr::VK_Mips_ABS_HI: + FixupKind = Mips::fixup_Mips_HI16; + break; + case MCSymbolRefExpr::VK_Mips_ABS_LO: + FixupKind = Mips::fixup_Mips_LO16; + break; + case MCSymbolRefExpr::VK_Mips_TLSGD: + FixupKind = Mips::fixup_Mips_TLSGD; + break; + case MCSymbolRefExpr::VK_Mips_TLSLDM: + FixupKind = Mips::fixup_Mips_TLSLDM; + break; + case MCSymbolRefExpr::VK_Mips_DTPREL_HI: + FixupKind = Mips::fixup_Mips_DTPREL_HI; + break; + case MCSymbolRefExpr::VK_Mips_DTPREL_LO: + FixupKind = Mips::fixup_Mips_DTPREL_LO; + break; + case MCSymbolRefExpr::VK_Mips_GOTTPREL: + FixupKind = Mips::fixup_Mips_GOTTPREL; + break; + case MCSymbolRefExpr::VK_Mips_TPREL_HI: + FixupKind = Mips::fixup_Mips_TPREL_HI; + break; + case MCSymbolRefExpr::VK_Mips_TPREL_LO: + FixupKind = Mips::fixup_Mips_TPREL_LO; + break; + default: + break; + } // switch + + Fixups.push_back(MCFixup::Create(0, MO.getExpr(), MCFixupKind(FixupKind))); + + // All of the information is in the fixup. + return 0; +} + +/// getMemEncoding - Return binary encoding of memory related operand. +/// If the offset operand requires relocation, record the relocation. +unsigned +MipsMCCodeEmitter::getMemEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const { + // Base register is encoded in bits 20-16, offset is encoded in bits 15-0. + assert(MI.getOperand(OpNo).isReg()); + unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo),Fixups) << 16; + unsigned OffBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups); + + return (OffBits & 0xFFFF) | RegBits; +} + +unsigned +MipsMCCodeEmitter::getSizeExtEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const { + assert(MI.getOperand(OpNo).isImm()); + unsigned SizeEncoding = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups); + return SizeEncoding - 1; +} + +// FIXME: should be called getMSBEncoding +// +unsigned +MipsMCCodeEmitter::getSizeInsEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const { + assert(MI.getOperand(OpNo-1).isImm()); + assert(MI.getOperand(OpNo).isImm()); + unsigned Position = getMachineOpValue(MI, MI.getOperand(OpNo-1), Fixups); + unsigned Size = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups); + + return Position + Size - 1; +} + +#include "MipsGenMCCodeEmitter.inc" + diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp b/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp index 1f9e3ddf13c8..3c544f6aec90 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp @@ -1,4 +1,4 @@ -//===-- MipsMCTargetDesc.cpp - Mips Target Descriptions ---------*- C++ -*-===// +//===-- MipsMCTargetDesc.cpp - Mips Target Descriptions -------------------===// // // The LLVM Compiler Infrastructure // @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#include "MipsMCTargetDesc.h" #include "MipsMCAsmInfo.h" +#include "MipsMCTargetDesc.h" #include "InstPrinter/MipsInstPrinter.h" #include "llvm/MC/MachineLocation.h" #include "llvm/MC/MCCodeGenInfo.h" @@ -20,6 +20,7 @@ #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TargetRegistry.h" #define GET_INSTRINFO_MC_DESC @@ -63,19 +64,24 @@ static MCAsmInfo *createMipsMCAsmInfo(const Target &T, StringRef TT) { } static MCCodeGenInfo *createMipsMCCodeGenInfo(StringRef TT, Reloc::Model RM, - CodeModel::Model CM) { + CodeModel::Model CM, + CodeGenOpt::Level OL) { MCCodeGenInfo *X = new MCCodeGenInfo(); - if (RM == Reloc::Default) + if (CM == CodeModel::JITDefault) + RM = Reloc::Static; + else if (RM == Reloc::Default) RM = Reloc::PIC_; - X->InitMCCodeGenInfo(RM, CM); + X->InitMCCodeGenInfo(RM, CM, OL); return X; } static MCInstPrinter *createMipsMCInstPrinter(const Target &T, unsigned SyntaxVariant, const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI, const MCSubtargetInfo &STI) { - return new MipsInstPrinter(MAI); + return new MipsInstPrinter(MAI, MII, MRI); } static MCStreamer *createMCStreamer(const Target &T, StringRef TT, @@ -110,7 +116,8 @@ extern "C" void LLVMInitializeMipsTargetMC() { TargetRegistry::RegisterMCInstrInfo(TheMipsTarget, createMipsMCInstrInfo); TargetRegistry::RegisterMCInstrInfo(TheMipselTarget, createMipsMCInstrInfo); TargetRegistry::RegisterMCInstrInfo(TheMips64Target, createMipsMCInstrInfo); - TargetRegistry::RegisterMCInstrInfo(TheMips64elTarget, createMipsMCInstrInfo); + TargetRegistry::RegisterMCInstrInfo(TheMips64elTarget, + createMipsMCInstrInfo); // Register the MC register info. TargetRegistry::RegisterMCRegInfo(TheMipsTarget, createMipsMCRegisterInfo); @@ -120,25 +127,31 @@ extern "C" void LLVMInitializeMipsTargetMC() { createMipsMCRegisterInfo); // Register the MC Code Emitter - TargetRegistry::RegisterMCCodeEmitter(TheMipsTarget, createMipsMCCodeEmitter); + TargetRegistry::RegisterMCCodeEmitter(TheMipsTarget, + createMipsMCCodeEmitterEB); TargetRegistry::RegisterMCCodeEmitter(TheMipselTarget, - createMipsMCCodeEmitter); + createMipsMCCodeEmitterEL); TargetRegistry::RegisterMCCodeEmitter(TheMips64Target, - createMipsMCCodeEmitter); + createMipsMCCodeEmitterEB); TargetRegistry::RegisterMCCodeEmitter(TheMips64elTarget, - createMipsMCCodeEmitter); + createMipsMCCodeEmitterEL); // Register the object streamer. TargetRegistry::RegisterMCObjectStreamer(TheMipsTarget, createMCStreamer); TargetRegistry::RegisterMCObjectStreamer(TheMipselTarget, createMCStreamer); TargetRegistry::RegisterMCObjectStreamer(TheMips64Target, createMCStreamer); - TargetRegistry::RegisterMCObjectStreamer(TheMips64elTarget, createMCStreamer); + TargetRegistry::RegisterMCObjectStreamer(TheMips64elTarget, + createMCStreamer); // Register the asm backend. - TargetRegistry::RegisterMCAsmBackend(TheMipsTarget, createMipsAsmBackend); - TargetRegistry::RegisterMCAsmBackend(TheMipselTarget, createMipsAsmBackend); - TargetRegistry::RegisterMCAsmBackend(TheMips64Target, createMipsAsmBackend); - TargetRegistry::RegisterMCAsmBackend(TheMips64elTarget, createMipsAsmBackend); + TargetRegistry::RegisterMCAsmBackend(TheMipsTarget, + createMipsAsmBackendEB32); + TargetRegistry::RegisterMCAsmBackend(TheMipselTarget, + createMipsAsmBackendEL32); + TargetRegistry::RegisterMCAsmBackend(TheMips64Target, + createMipsAsmBackendEB64); + TargetRegistry::RegisterMCAsmBackend(TheMips64elTarget, + createMipsAsmBackendEL64); // Register the MC subtarget info. TargetRegistry::RegisterMCSubtargetInfo(TheMipsTarget, diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h b/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h index 7a0042ad889e..547ccddd78ea 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h +++ b/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h @@ -14,25 +14,40 @@ #ifndef MIPSMCTARGETDESC_H #define MIPSMCTARGETDESC_H +#include "llvm/Support/DataTypes.h" + namespace llvm { class MCAsmBackend; -class MCInstrInfo; class MCCodeEmitter; class MCContext; +class MCInstrInfo; +class MCObjectWriter; class MCSubtargetInfo; class StringRef; class Target; +class raw_ostream; extern Target TheMipsTarget; extern Target TheMipselTarget; extern Target TheMips64Target; extern Target TheMips64elTarget; -MCCodeEmitter *createMipsMCCodeEmitter(const MCInstrInfo &MCII, - const MCSubtargetInfo &STI, - MCContext &Ctx); +MCCodeEmitter *createMipsMCCodeEmitterEB(const MCInstrInfo &MCII, + const MCSubtargetInfo &STI, + MCContext &Ctx); +MCCodeEmitter *createMipsMCCodeEmitterEL(const MCInstrInfo &MCII, + const MCSubtargetInfo &STI, + MCContext &Ctx); + +MCAsmBackend *createMipsAsmBackendEB32(const Target &T, StringRef TT); +MCAsmBackend *createMipsAsmBackendEL32(const Target &T, StringRef TT); +MCAsmBackend *createMipsAsmBackendEB64(const Target &T, StringRef TT); +MCAsmBackend *createMipsAsmBackendEL64(const Target &T, StringRef TT); -MCAsmBackend *createMipsAsmBackend(const Target &T, StringRef TT); +MCObjectWriter *createMipsELFObjectWriter(raw_ostream &OS, + uint8_t OSABI, + bool IsLittleEndian, + bool Is64Bit); } // End llvm namespace // Defines symbolic names for Mips registers. This defines a mapping from diff --git a/lib/Target/Mips/Makefile b/lib/Target/Mips/Makefile index d72693c0940d..168635c96beb 100644 --- a/lib/Target/Mips/Makefile +++ b/lib/Target/Mips/Makefile @@ -15,9 +15,9 @@ TARGET = Mips BUILT_SOURCES = MipsGenRegisterInfo.inc MipsGenInstrInfo.inc \ MipsGenAsmWriter.inc MipsGenCodeEmitter.inc \ MipsGenDAGISel.inc MipsGenCallingConv.inc \ - MipsGenSubtargetInfo.inc + MipsGenSubtargetInfo.inc MipsGenMCCodeEmitter.inc -DIRS = InstPrinter TargetInfo MCTargetDesc +DIRS = InstPrinter AsmParser TargetInfo MCTargetDesc include $(LEVEL)/Makefile.common diff --git a/lib/Target/Mips/Mips.h b/lib/Target/Mips/Mips.h index bacecf20b920..bafadc8f25f6 100644 --- a/lib/Target/Mips/Mips.h +++ b/lib/Target/Mips/Mips.h @@ -21,8 +21,6 @@ namespace llvm { class MipsTargetMachine; class FunctionPass; - class MachineCodeEmitter; - class formatted_raw_ostream; FunctionPass *createMipsISelDag(MipsTargetMachine &TM); FunctionPass *createMipsDelaySlotFillerPass(MipsTargetMachine &TM); diff --git a/lib/Target/Mips/Mips.td b/lib/Target/Mips/Mips.td index 39c2c164f664..cbebe84a1805 100644 --- a/lib/Target/Mips/Mips.td +++ b/lib/Target/Mips/Mips.td @@ -1,4 +1,4 @@ -//===- Mips.td - Describe the Mips Target Machine ----------*- tablegen -*-===// +//===-- Mips.td - Describe the Mips Target Machine ---------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // @@ -63,7 +63,7 @@ def FeatureMips32 : SubtargetFeature<"mips32", "MipsArchVersion", "Mips32", [FeatureCondMov, FeatureBitCount]>; def FeatureMips32r2 : SubtargetFeature<"mips32r2", "MipsArchVersion", "Mips32r2", "Mips32r2 ISA Support", - [FeatureMips32, FeatureSEInReg]>; + [FeatureMips32, FeatureSEInReg, FeatureSwap]>; def FeatureMips64 : SubtargetFeature<"mips64", "MipsArchVersion", "Mips64", "Mips64 ISA Support", [FeatureGP64Bit, FeatureFP64Bit, @@ -79,9 +79,9 @@ def FeatureMips64r2 : SubtargetFeature<"mips64r2", "MipsArchVersion", class Proc<string Name, list<SubtargetFeature> Features> : Processor<Name, MipsGenericItineraries, Features>; -def : Proc<"mips32r1", [FeatureMips32]>; -def : Proc<"4ke", [FeatureMips32r2]>; -def : Proc<"mips64r1", [FeatureMips64]>; +def : Proc<"mips32", [FeatureMips32]>; +def : Proc<"mips32r2", [FeatureMips32r2]>; +def : Proc<"mips64", [FeatureMips64]>; def : Proc<"mips64r2", [FeatureMips64r2]>; def MipsAsmWriter : AsmWriter { diff --git a/lib/Target/Mips/Mips64InstrInfo.td b/lib/Target/Mips/Mips64InstrInfo.td index 9758f4bb8907..427e8d97ad9c 100644 --- a/lib/Target/Mips/Mips64InstrInfo.td +++ b/lib/Target/Mips/Mips64InstrInfo.td @@ -25,68 +25,48 @@ def uimm16_64 : Operand<i64> { // Transformation Function - get Imm - 32. def Subtract32 : SDNodeXForm<imm, [{ - return getI32Imm((unsigned)N->getZExtValue() - 32); + return getImm(N, (unsigned)N->getZExtValue() - 32); }]>; -// imm32_63 predicate - True if imm is in range [32, 63]. -def imm32_63 : ImmLeaf<i64, - [{return (int32_t)Imm >= 32 && (int32_t)Imm < 64;}], - Subtract32>; +// shamt must fit in 6 bits. +def immZExt6 : ImmLeaf<i32, [{return Imm == (Imm & 0x3f);}]>; //===----------------------------------------------------------------------===// // Instructions specific format //===----------------------------------------------------------------------===// // Shifts -class LogicR_shift_rotate_imm64<bits<6> func, bits<5> _rs, string instr_asm, - SDNode OpNode, PatFrag PF>: - FR<0x00, func, (outs CPU64Regs:$rd), (ins CPU64Regs:$rt, shamt_64:$shamt), - !strconcat(instr_asm, "\t$rd, $rt, $shamt"), - [(set CPU64Regs:$rd, (OpNode CPU64Regs:$rt, (i64 PF:$shamt)))], - IIAlu> { - let rs = _rs; -} - -class LogicR_shift_rotate_reg64<bits<6> func, bits<5> _shamt, string instr_asm, - SDNode OpNode>: - FR<0x00, func, (outs CPU64Regs:$rd), (ins CPU64Regs:$rs, CPU64Regs:$rt), - !strconcat(instr_asm, "\t$rd, $rt, $rs"), - [(set CPU64Regs:$rd, (OpNode CPU64Regs:$rt, CPU64Regs:$rs))], IIAlu> { - let shamt = _shamt; -} +// 64-bit shift instructions. +class shift_rotate_imm64<bits<6> func, bits<5> isRotate, string instr_asm, + SDNode OpNode>: + shift_rotate_imm<func, isRotate, instr_asm, OpNode, immZExt6, shamt, + CPU64Regs>; // Mul, Div -let rd = 0, shamt = 0, Defs = [HI64, LO64] in { - let isCommutable = 1 in - class Mul64<bits<6> func, string instr_asm, InstrItinClass itin>: - FR<0x00, func, (outs), (ins CPU64Regs:$rs, CPU64Regs:$rt), - !strconcat(instr_asm, "\t$rs, $rt"), [], itin>; - - class Div64<SDNode op, bits<6> func, string instr_asm, InstrItinClass itin>: - FR<0x00, func, (outs), (ins CPU64Regs:$rs, CPU64Regs:$rt), - !strconcat(instr_asm, "\t$$zero, $rs, $rt"), - [(op CPU64Regs:$rs, CPU64Regs:$rt)], itin>; +class Mult64<bits<6> func, string instr_asm, InstrItinClass itin>: + Mult<func, instr_asm, itin, CPU64Regs, [HI64, LO64]>; +class Div64<SDNode op, bits<6> func, string instr_asm, InstrItinClass itin>: + Div<op, func, instr_asm, itin, CPU64Regs, [HI64, LO64]>; + +multiclass Atomic2Ops64<PatFrag Op, string Opstr> { + def #NAME# : Atomic2Ops<Op, Opstr, CPU64Regs, CPURegs>, Requires<[NotN64]>; + def _P8 : Atomic2Ops<Op, Opstr, CPU64Regs, CPU64Regs>, Requires<[IsN64]>; } -// Move from Hi/Lo -let shamt = 0 in { -let rs = 0, rt = 0 in -class MoveFromLOHI64<bits<6> func, string instr_asm>: - FR<0x00, func, (outs CPU64Regs:$rd), (ins), - !strconcat(instr_asm, "\t$rd"), [], IIHiLo>; - -let rt = 0, rd = 0 in -class MoveToLOHI64<bits<6> func, string instr_asm>: - FR<0x00, func, (outs), (ins CPU64Regs:$rs), - !strconcat(instr_asm, "\t$rs"), [], IIHiLo>; +multiclass AtomicCmpSwap64<PatFrag Op, string Width> { + def #NAME# : AtomicCmpSwap<Op, Width, CPU64Regs, CPURegs>, Requires<[NotN64]>; + def _P8 : AtomicCmpSwap<Op, Width, CPU64Regs, CPU64Regs>, + Requires<[IsN64]>; } -// Count Leading Ones/Zeros in Word -class CountLeading64<bits<6> func, string instr_asm, list<dag> pattern>: - FR<0x1c, func, (outs CPU64Regs:$rd), (ins CPU64Regs:$rs), - !strconcat(instr_asm, "\t$rd, $rs"), pattern, IIAlu>, - Requires<[HasBitCount]> { - let shamt = 0; - let rt = rd; +let usesCustomInserter = 1, Predicates = [HasMips64] in { + defm ATOMIC_LOAD_ADD_I64 : Atomic2Ops64<atomic_load_add_64, "load_add_64">; + defm ATOMIC_LOAD_SUB_I64 : Atomic2Ops64<atomic_load_sub_64, "load_sub_64">; + defm ATOMIC_LOAD_AND_I64 : Atomic2Ops64<atomic_load_and_64, "load_and_64">; + defm ATOMIC_LOAD_OR_I64 : Atomic2Ops64<atomic_load_or_64, "load_or_64">; + defm ATOMIC_LOAD_XOR_I64 : Atomic2Ops64<atomic_load_xor_64, "load_xor_64">; + defm ATOMIC_LOAD_NAND_I64 : Atomic2Ops64<atomic_load_nand_64, "load_nand_64">; + defm ATOMIC_SWAP_I64 : Atomic2Ops64<atomic_swap_64, "swap_64">; + defm ATOMIC_CMP_SWAP_I64 : AtomicCmpSwap64<atomic_cmp_swap_64, "64">; } //===----------------------------------------------------------------------===// @@ -101,6 +81,7 @@ def SLTi64 : SetCC_I<0x0a, "slti", setlt, simm16_64, immSExt16, CPU64Regs>; def SLTiu64 : SetCC_I<0x0b, "sltiu", setult, simm16_64, immSExt16, CPU64Regs>; def ORi64 : ArithLogicI<0x0d, "ori", or, uimm16_64, immZExt16, CPU64Regs>; def XORi64 : ArithLogicI<0x0e, "xori", xor, uimm16_64, immZExt16, CPU64Regs>; +def LUi64 : LoadUpper<0x0f, "lui", CPU64Regs, uimm16_64>; /// Arithmetic Instructions (3-Operand, R-Type) def DADDu : ArithLogicR<0x00, 0x2d, "daddu", add, IIAlu, CPU64Regs, 1>; @@ -113,26 +94,21 @@ def XOR64 : ArithLogicR<0x00, 0x26, "xor", xor, IIAlu, CPU64Regs, 1>; def NOR64 : LogicNOR<0x00, 0x27, "nor", CPU64Regs>; /// Shift Instructions -def DSLL : LogicR_shift_rotate_imm64<0x38, 0x00, "dsll", shl, immZExt5>; -def DSRL : LogicR_shift_rotate_imm64<0x3a, 0x00, "dsrl", srl, immZExt5>; -def DSRA : LogicR_shift_rotate_imm64<0x3b, 0x00, "dsra", sra, immZExt5>; -def DSLL32 : LogicR_shift_rotate_imm64<0x3c, 0x00, "dsll32", shl, imm32_63>; -def DSRL32 : LogicR_shift_rotate_imm64<0x3e, 0x00, "dsrl32", srl, imm32_63>; -def DSRA32 : LogicR_shift_rotate_imm64<0x3f, 0x00, "dsra32", sra, imm32_63>; -def DSLLV : LogicR_shift_rotate_reg64<0x24, 0x00, "dsllv", shl>; -def DSRLV : LogicR_shift_rotate_reg64<0x26, 0x00, "dsrlv", srl>; -def DSRAV : LogicR_shift_rotate_reg64<0x27, 0x00, "dsrav", sra>; +def DSLL : shift_rotate_imm64<0x38, 0x00, "dsll", shl>; +def DSRL : shift_rotate_imm64<0x3a, 0x00, "dsrl", srl>; +def DSRA : shift_rotate_imm64<0x3b, 0x00, "dsra", sra>; +def DSLLV : shift_rotate_reg<0x24, 0x00, "dsllv", shl, CPU64Regs>; +def DSRLV : shift_rotate_reg<0x26, 0x00, "dsrlv", srl, CPU64Regs>; +def DSRAV : shift_rotate_reg<0x27, 0x00, "dsrav", sra, CPU64Regs>; // Rotate Instructions let Predicates = [HasMips64r2] in { - def DROTR : LogicR_shift_rotate_imm64<0x3a, 0x01, "drotr", rotr, immZExt5>; - def DROTR32 : LogicR_shift_rotate_imm64<0x3e, 0x01, "drotr32", rotr, - imm32_63>; - def DROTRV : LogicR_shift_rotate_reg64<0x16, 0x01, "drotrv", rotr>; + def DROTR : shift_rotate_imm64<0x3a, 0x01, "drotr", rotr>; + def DROTRV : shift_rotate_reg<0x16, 0x01, "drotrv", rotr, CPU64Regs>; } /// Load and Store Instructions -/// aligned +/// aligned defm LB64 : LoadM64<0x20, "lb", sextloadi8>; defm LBu64 : LoadM64<0x24, "lbu", zextloadi8>; defm LH64 : LoadM64<0x21, "lh", sextloadi16_a>; @@ -154,7 +130,14 @@ defm USW64 : StoreM64<0x2b, "usw", truncstorei32_u, 1>; defm ULD : LoadM64<0x37, "uld", load_u, 1>; defm USD : StoreM64<0x3f, "usd", store_u, 1>; +/// Load-linked, Store-conditional +def LLD : LLBase<0x34, "lld", CPU64Regs, mem>, Requires<[NotN64]>; +def LLD_P8 : LLBase<0x34, "lld", CPU64Regs, mem64>, Requires<[IsN64]>; +def SCD : SCBase<0x3c, "scd", CPU64Regs, mem>, Requires<[NotN64]>; +def SCD_P8 : SCBase<0x3c, "scd", CPU64Regs, mem64>, Requires<[IsN64]>; + /// Jump and Branch Instructions +def JR64 : JumpFR<0x00, 0x08, "jr", CPU64Regs>; def BEQ64 : CBranch<0x04, "beq", seteq, CPU64Regs>; def BNE64 : CBranch<0x05, "bne", setne, CPU64Regs>; def BGEZ64 : CBranchZero<0x01, 1, "bgez", setge, CPU64Regs>; @@ -162,46 +145,104 @@ def BGTZ64 : CBranchZero<0x07, 0, "bgtz", setgt, CPU64Regs>; def BLEZ64 : CBranchZero<0x07, 0, "blez", setle, CPU64Regs>; def BLTZ64 : CBranchZero<0x01, 0, "bltz", setlt, CPU64Regs>; +def JALR64 : JumpLinkReg<0x00, 0x09, "jalr", CPU64Regs>; + /// Multiply and Divide Instructions. -def DMULT : Mul64<0x1c, "dmult", IIImul>; -def DMULTu : Mul64<0x1d, "dmultu", IIImul>; +def DMULT : Mult64<0x1c, "dmult", IIImul>; +def DMULTu : Mult64<0x1d, "dmultu", IIImul>; def DSDIV : Div64<MipsDivRem, 0x1e, "ddiv", IIIdiv>; def DUDIV : Div64<MipsDivRemU, 0x1f, "ddivu", IIIdiv>; -let Defs = [HI64] in - def MTHI64 : MoveToLOHI64<0x11, "mthi">; -let Defs = [LO64] in - def MTLO64 : MoveToLOHI64<0x13, "mtlo">; +def MTHI64 : MoveToLOHI<0x11, "mthi", CPU64Regs, [HI64]>; +def MTLO64 : MoveToLOHI<0x13, "mtlo", CPU64Regs, [LO64]>; +def MFHI64 : MoveFromLOHI<0x10, "mfhi", CPU64Regs, [HI64]>; +def MFLO64 : MoveFromLOHI<0x12, "mflo", CPU64Regs, [LO64]>; -let Uses = [HI64] in - def MFHI64 : MoveFromLOHI64<0x10, "mfhi">; -let Uses = [LO64] in - def MFLO64 : MoveFromLOHI64<0x12, "mflo">; +/// Sign Ext In Register Instructions. +def SEB64 : SignExtInReg<0x10, "seb", i8, CPU64Regs>; +def SEH64 : SignExtInReg<0x18, "seh", i16, CPU64Regs>; /// Count Leading -def DCLZ : CountLeading64<0x24, "dclz", - [(set CPU64Regs:$rd, (ctlz CPU64Regs:$rs))]>; -def DCLO : CountLeading64<0x25, "dclo", - [(set CPU64Regs:$rd, (ctlz (not CPU64Regs:$rs)))]>; +def DCLZ : CountLeading0<0x24, "dclz", CPU64Regs>; +def DCLO : CountLeading1<0x25, "dclo", CPU64Regs>; + +/// Double Word Swap Bytes/HalfWords +def DSBH : SubwordSwap<0x24, 0x2, "dsbh", CPU64Regs>; +def DSHD : SubwordSwap<0x24, 0x5, "dshd", CPU64Regs>; + +def LEA_ADDiu64 : EffectiveAddress<"daddiu\t$rt, $addr", CPU64Regs, mem_ea_64>; + +let Uses = [SP_64] in +def DynAlloc64 : EffectiveAddress<"daddiu\t$rt, $addr", CPU64Regs, mem_ea_64>, + Requires<[IsN64]>; + +def RDHWR64 : ReadHardware<CPU64Regs, HWRegs64>; + +def DEXT : ExtBase<3, "dext", CPU64Regs>; +def DINS : InsBase<7, "dins", CPU64Regs>; + +def DSLL64_32 : FR<0x3c, 0x00, (outs CPU64Regs:$rd), (ins CPURegs:$rt), + "dsll\t$rd, $rt, 32", [], IIAlu>; + +def SLL64_32 : FR<0x0, 0x00, (outs CPU64Regs:$rd), (ins CPURegs:$rt), + "sll\t$rd, $rt, 0", [], IIAlu>; +def SLL64_64 : FR<0x0, 0x00, (outs CPU64Regs:$rd), (ins CPU64Regs:$rt), + "sll\t$rd, $rt, 0", [], IIAlu>; //===----------------------------------------------------------------------===// // Arbitrary patterns that map to one or more instructions //===----------------------------------------------------------------------===// -// Small immediates -def : Pat<(i64 immSExt16:$in), - (DADDiu ZERO_64, imm:$in)>; -def : Pat<(i64 immZExt16:$in), - (ORi64 ZERO_64, imm:$in)>; - -// zextloadi32_u -def : Pat<(zextloadi32_u addr:$a), (DSRL (DSLL (ULW64_P8 addr:$a), 32), 32)>, - Requires<[IsN64]>; -def : Pat<(zextloadi32_u addr:$a), (DSRL (DSLL (ULW64 addr:$a), 32), 32)>, - Requires<[NotN64]>; +// extended loads +let Predicates = [NotN64] in { + def : Pat<(i64 (extloadi1 addr:$src)), (LB64 addr:$src)>; + def : Pat<(i64 (extloadi8 addr:$src)), (LB64 addr:$src)>; + def : Pat<(i64 (extloadi16_a addr:$src)), (LH64 addr:$src)>; + def : Pat<(i64 (extloadi16_u addr:$src)), (ULH64 addr:$src)>; + def : Pat<(i64 (extloadi32_a addr:$src)), (LW64 addr:$src)>; + def : Pat<(i64 (extloadi32_u addr:$src)), (ULW64 addr:$src)>; + def : Pat<(zextloadi32_u addr:$a), (DSRL (DSLL (ULW64 addr:$a), 32), 32)>; +} +let Predicates = [IsN64] in { + def : Pat<(i64 (extloadi1 addr:$src)), (LB64_P8 addr:$src)>; + def : Pat<(i64 (extloadi8 addr:$src)), (LB64_P8 addr:$src)>; + def : Pat<(i64 (extloadi16_a addr:$src)), (LH64_P8 addr:$src)>; + def : Pat<(i64 (extloadi16_u addr:$src)), (ULH64_P8 addr:$src)>; + def : Pat<(i64 (extloadi32_a addr:$src)), (LW64_P8 addr:$src)>; + def : Pat<(i64 (extloadi32_u addr:$src)), (ULW64_P8 addr:$src)>; + def : Pat<(zextloadi32_u addr:$a), (DSRL (DSLL (ULW64_P8 addr:$a), 32), 32)>; +} // hi/lo relocs -def : Pat<(i64 (MipsLo tglobaladdr:$in)), (DADDiu ZERO_64, tglobaladdr:$in)>; +def : Pat<(MipsHi tglobaladdr:$in), (LUi64 tglobaladdr:$in)>; +def : Pat<(MipsHi tblockaddress:$in), (LUi64 tblockaddress:$in)>; +def : Pat<(MipsHi tjumptable:$in), (LUi64 tjumptable:$in)>; +def : Pat<(MipsHi tconstpool:$in), (LUi64 tconstpool:$in)>; +def : Pat<(MipsHi tglobaltlsaddr:$in), (LUi64 tglobaltlsaddr:$in)>; + +def : Pat<(MipsLo tglobaladdr:$in), (DADDiu ZERO_64, tglobaladdr:$in)>; +def : Pat<(MipsLo tblockaddress:$in), (DADDiu ZERO_64, tblockaddress:$in)>; +def : Pat<(MipsLo tjumptable:$in), (DADDiu ZERO_64, tjumptable:$in)>; +def : Pat<(MipsLo tconstpool:$in), (DADDiu ZERO_64, tconstpool:$in)>; +def : Pat<(MipsLo tglobaltlsaddr:$in), (DADDiu ZERO_64, tglobaltlsaddr:$in)>; + +def : Pat<(add CPU64Regs:$hi, (MipsLo tglobaladdr:$lo)), + (DADDiu CPU64Regs:$hi, tglobaladdr:$lo)>; +def : Pat<(add CPU64Regs:$hi, (MipsLo tblockaddress:$lo)), + (DADDiu CPU64Regs:$hi, tblockaddress:$lo)>; +def : Pat<(add CPU64Regs:$hi, (MipsLo tjumptable:$lo)), + (DADDiu CPU64Regs:$hi, tjumptable:$lo)>; +def : Pat<(add CPU64Regs:$hi, (MipsLo tconstpool:$lo)), + (DADDiu CPU64Regs:$hi, tconstpool:$lo)>; +def : Pat<(add CPU64Regs:$hi, (MipsLo tglobaltlsaddr:$lo)), + (DADDiu CPU64Regs:$hi, tglobaltlsaddr:$lo)>; + +def : WrapperPat<tglobaladdr, DADDiu, CPU64Regs>; +def : WrapperPat<tconstpool, DADDiu, CPU64Regs>; +def : WrapperPat<texternalsym, DADDiu, CPU64Regs>; +def : WrapperPat<tblockaddress, DADDiu, CPU64Regs>; +def : WrapperPat<tjumptable, DADDiu, CPU64Regs>; +def : WrapperPat<tglobaltlsaddr, DADDiu, CPU64Regs>; defm : BrcondPats<CPU64Regs, BEQ64, BNE64, SLT64, SLTu64, SLTi64, SLTiu64, ZERO_64>; @@ -212,3 +253,21 @@ defm : SetlePats<CPU64Regs, SLT64, SLTu64>; defm : SetgtPats<CPU64Regs, SLT64, SLTu64>; defm : SetgePats<CPU64Regs, SLT64, SLTu64>; defm : SetgeImmPats<CPU64Regs, SLTi64, SLTiu64>; + +// select MipsDynAlloc +def : Pat<(MipsDynAlloc addr:$f), (DynAlloc64 addr:$f)>, Requires<[IsN64]>; + +// truncate +def : Pat<(i32 (trunc CPU64Regs:$src)), + (SLL (EXTRACT_SUBREG CPU64Regs:$src, sub_32), 0)>, Requires<[IsN64]>; + +// 32-to-64-bit extension +def : Pat<(i64 (anyext CPURegs:$src)), (SLL64_32 CPURegs:$src)>; +def : Pat<(i64 (zext CPURegs:$src)), (DSRL (DSLL64_32 CPURegs:$src), 32)>; +def : Pat<(i64 (sext CPURegs:$src)), (SLL64_32 CPURegs:$src)>; + +// Sign extend in register +def : Pat<(i64 (sext_inreg CPU64Regs:$src, i32)), (SLL64_64 CPU64Regs:$src)>; + +// bswap pattern +def : Pat<(bswap CPU64Regs:$rt), (DSHD (DSBH CPU64Regs:$rt))>; diff --git a/lib/Target/Mips/MipsAnalyzeImmediate.cpp b/lib/Target/Mips/MipsAnalyzeImmediate.cpp new file mode 100644 index 000000000000..dc8fbd0d0370 --- /dev/null +++ b/lib/Target/Mips/MipsAnalyzeImmediate.cpp @@ -0,0 +1,153 @@ +//===-- MipsAnalyzeImmediate.cpp - Analyze Immediates ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "MipsAnalyzeImmediate.h" +#include "Mips.h" +#include "llvm/Support/MathExtras.h" + +using namespace llvm; + +MipsAnalyzeImmediate::Inst::Inst(unsigned O, unsigned I) : Opc(O), ImmOpnd(I) {} + +// Add I to the instruction sequences. +void MipsAnalyzeImmediate::AddInstr(InstSeqLs &SeqLs, const Inst &I) { + // Add an instruction seqeunce consisting of just I. + if (SeqLs.empty()) { + SeqLs.push_back(InstSeq(1, I)); + return; + } + + for (InstSeqLs::iterator Iter = SeqLs.begin(); Iter != SeqLs.end(); ++Iter) + Iter->push_back(I); +} + +void MipsAnalyzeImmediate::GetInstSeqLsADDiu(uint64_t Imm, unsigned RemSize, + InstSeqLs &SeqLs) { + GetInstSeqLs((Imm + 0x8000ULL) & 0xffffffffffff0000ULL, RemSize, SeqLs); + AddInstr(SeqLs, Inst(ADDiu, Imm & 0xffffULL)); +} + +void MipsAnalyzeImmediate::GetInstSeqLsORi(uint64_t Imm, unsigned RemSize, + InstSeqLs &SeqLs) { + GetInstSeqLs(Imm & 0xffffffffffff0000ULL, RemSize, SeqLs); + AddInstr(SeqLs, Inst(ORi, Imm & 0xffffULL)); +} + +void MipsAnalyzeImmediate::GetInstSeqLsSLL(uint64_t Imm, unsigned RemSize, + InstSeqLs &SeqLs) { + unsigned Shamt = CountTrailingZeros_64(Imm); + GetInstSeqLs(Imm >> Shamt, RemSize - Shamt, SeqLs); + AddInstr(SeqLs, Inst(SLL, Shamt)); +} + +void MipsAnalyzeImmediate::GetInstSeqLs(uint64_t Imm, unsigned RemSize, + InstSeqLs &SeqLs) { + uint64_t MaskedImm = Imm & (0xffffffffffffffffULL >> (64 - Size)); + + // Do nothing if Imm is 0. + if (!MaskedImm) + return; + + // A single ADDiu will do if RemSize <= 16. + if (RemSize <= 16) { + AddInstr(SeqLs, Inst(ADDiu, MaskedImm)); + return; + } + + // Shift if the lower 16-bit is cleared. + if (!(Imm & 0xffff)) { + GetInstSeqLsSLL(Imm, RemSize, SeqLs); + return; + } + + GetInstSeqLsADDiu(Imm, RemSize, SeqLs); + + // If bit 15 is cleared, it doesn't make a difference whether the last + // instruction is an ADDiu or ORi. In that case, do not call GetInstSeqLsORi. + if (Imm & 0x8000) { + InstSeqLs SeqLsORi; + GetInstSeqLsORi(Imm, RemSize, SeqLsORi); + SeqLs.insert(SeqLs.end(), SeqLsORi.begin(), SeqLsORi.end()); + } +} + +// Replace a ADDiu & SLL pair with a LUi. +// e.g. the following two instructions +// ADDiu 0x0111 +// SLL 18 +// are replaced with +// LUi 0x444 +void MipsAnalyzeImmediate::ReplaceADDiuSLLWithLUi(InstSeq &Seq) { + // Check if the first two instructions are ADDiu and SLL and the shift amount + // is at least 16. + if ((Seq.size() < 2) || (Seq[0].Opc != ADDiu) || + (Seq[1].Opc != SLL) || (Seq[1].ImmOpnd < 16)) + return; + + // Sign-extend and shift operand of ADDiu and see if it still fits in 16-bit. + int64_t Imm = SignExtend64<16>(Seq[0].ImmOpnd); + int64_t ShiftedImm = Imm << (Seq[1].ImmOpnd - 16); + + if (!isInt<16>(ShiftedImm)) + return; + + // Replace the first instruction and erase the second. + Seq[0].Opc = LUi; + Seq[0].ImmOpnd = (unsigned)(ShiftedImm & 0xffff); + Seq.erase(Seq.begin() + 1); +} + +void MipsAnalyzeImmediate::GetShortestSeq(InstSeqLs &SeqLs, InstSeq &Insts) { + InstSeqLs::iterator ShortestSeq = SeqLs.end(); + // The length of an instruction sequence is at most 7. + unsigned ShortestLength = 8; + + for (InstSeqLs::iterator S = SeqLs.begin(); S != SeqLs.end(); ++S) { + ReplaceADDiuSLLWithLUi(*S); + assert(S->size() <= 7); + + if (S->size() < ShortestLength) { + ShortestSeq = S; + ShortestLength = S->size(); + } + } + + Insts.clear(); + Insts.append(ShortestSeq->begin(), ShortestSeq->end()); +} + +const MipsAnalyzeImmediate::InstSeq +&MipsAnalyzeImmediate::Analyze(uint64_t Imm, unsigned Size, + bool LastInstrIsADDiu) { + this->Size = Size; + + if (Size == 32) { + ADDiu = Mips::ADDiu; + ORi = Mips::ORi; + SLL = Mips::SLL; + LUi = Mips::LUi; + } else { + ADDiu = Mips::DADDiu; + ORi = Mips::ORi64; + SLL = Mips::DSLL; + LUi = Mips::LUi64; + } + + InstSeqLs SeqLs; + + // Get the list of instruction sequences. + if (LastInstrIsADDiu | !Imm) + GetInstSeqLsADDiu(Imm, Size, SeqLs); + else + GetInstSeqLs(Imm, Size, SeqLs); + + // Set Insts to the shortest instruction sequence. + GetShortestSeq(SeqLs, Insts); + + return Insts; +} diff --git a/lib/Target/Mips/MipsAnalyzeImmediate.h b/lib/Target/Mips/MipsAnalyzeImmediate.h new file mode 100644 index 000000000000..a094ddae45de --- /dev/null +++ b/lib/Target/Mips/MipsAnalyzeImmediate.h @@ -0,0 +1,63 @@ +//===-- MipsAnalyzeImmediate.h - Analyze Immediates ------------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef MIPS_ANALYZE_IMMEDIATE_H +#define MIPS_ANALYZE_IMMEDIATE_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/DataTypes.h" + +namespace llvm { + + class MipsAnalyzeImmediate { + public: + struct Inst { + unsigned Opc, ImmOpnd; + Inst(unsigned Opc, unsigned ImmOpnd); + }; + typedef SmallVector<Inst, 7 > InstSeq; + + /// Analyze - Get an instrucion sequence to load immediate Imm. The last + /// instruction in the sequence must be an ADDiu if LastInstrIsADDiu is + /// true; + const InstSeq &Analyze(uint64_t Imm, unsigned Size, bool LastInstrIsADDiu); + private: + typedef SmallVector<InstSeq, 5> InstSeqLs; + + /// AddInstr - Add I to all instruction sequences in SeqLs. + void AddInstr(InstSeqLs &SeqLs, const Inst &I); + + /// GetInstSeqLsADDiu - Get instrucion sequences which end with an ADDiu to + /// load immediate Imm + void GetInstSeqLsADDiu(uint64_t Imm, unsigned RemSize, InstSeqLs &SeqLs); + + /// GetInstSeqLsORi - Get instrucion sequences which end with an ORi to + /// load immediate Imm + void GetInstSeqLsORi(uint64_t Imm, unsigned RemSize, InstSeqLs &SeqLs); + + /// GetInstSeqLsSLL - Get instrucion sequences which end with a SLL to + /// load immediate Imm + void GetInstSeqLsSLL(uint64_t Imm, unsigned RemSize, InstSeqLs &SeqLs); + + /// GetInstSeqLs - Get instrucion sequences to load immediate Imm. + void GetInstSeqLs(uint64_t Imm, unsigned RemSize, InstSeqLs &SeqLs); + + /// ReplaceADDiuSLLWithLUi - Replace an ADDiu & SLL pair with a LUi. + void ReplaceADDiuSLLWithLUi(InstSeq &Seq); + + /// GetShortestSeq - Find the shortest instruction sequence in SeqLs and + /// return it in Insts. + void GetShortestSeq(InstSeqLs &SeqLs, InstSeq &Insts); + + unsigned Size; + unsigned ADDiu, ORi, SLL, LUi; + InstSeq Insts; + }; +} + +#endif diff --git a/lib/Target/Mips/MipsAsmPrinter.cpp b/lib/Target/Mips/MipsAsmPrinter.cpp index 0e826812d076..8206cfc15704 100644 --- a/lib/Target/Mips/MipsAsmPrinter.cpp +++ b/lib/Target/Mips/MipsAsmPrinter.cpp @@ -1,4 +1,4 @@ -//===-- MipsAsmPrinter.cpp - Mips LLVM assembly writer --------------------===// +//===-- MipsAsmPrinter.cpp - Mips LLVM Assembly Printer -------------------===// // // The LLVM Compiler Infrastructure // @@ -16,10 +16,12 @@ #include "MipsAsmPrinter.h" #include "Mips.h" #include "MipsInstrInfo.h" -#include "MipsMachineFunction.h" -#include "MipsMCInstLower.h" -#include "MipsMCSymbolRefExpr.h" #include "InstPrinter/MipsInstPrinter.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Analysis/DebugInfo.h" #include "llvm/BasicBlock.h" #include "llvm/Instructions.h" #include "llvm/CodeGen/MachineFunctionPass.h" @@ -27,55 +29,125 @@ #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineMemOperand.h" +#include "llvm/Instructions.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Target/Mangler.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetOptions.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Analysis/DebugInfo.h" using namespace llvm; -static bool isUnalignedLoadStore(unsigned Opc) { - return Opc == Mips::ULW || Opc == Mips::ULH || Opc == Mips::ULHu || - Opc == Mips::USW || Opc == Mips::USH || - Opc == Mips::ULW_P8 || Opc == Mips::ULH_P8 || Opc == Mips::ULHu_P8 || - Opc == Mips::USW_P8 || Opc == Mips::USH_P8; +void MipsAsmPrinter::EmitInstrWithMacroNoAT(const MachineInstr *MI) { + MCInst TmpInst; + + MCInstLowering.Lower(MI, TmpInst); + OutStreamer.EmitRawText(StringRef("\t.set\tmacro")); + if (MipsFI->getEmitNOAT()) + OutStreamer.EmitRawText(StringRef("\t.set\tat")); + OutStreamer.EmitInstruction(TmpInst); + if (MipsFI->getEmitNOAT()) + OutStreamer.EmitRawText(StringRef("\t.set\tnoat")); + OutStreamer.EmitRawText(StringRef("\t.set\tnomacro")); +} + +bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) { + MipsFI = MF.getInfo<MipsFunctionInfo>(); + AsmPrinter::runOnMachineFunction(MF); + return true; } void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { - SmallString<128> Str; - raw_svector_ostream OS(Str); - if (MI->isDebugValue()) { + SmallString<128> Str; + raw_svector_ostream OS(Str); + PrintDebugValueComment(MI, OS); return; } - MipsMCInstLower MCInstLowering(Mang, *MF, *this); unsigned Opc = MI->getOpcode(); MCInst TmpInst0; - MCInstLowering.Lower(MI, TmpInst0); - - // Enclose unaligned load or store with .macro & .nomacro directives. - if (isUnalignedLoadStore(Opc)) { - MCInst Directive; - Directive.setOpcode(Mips::MACRO); - OutStreamer.EmitInstruction(Directive); - OutStreamer.EmitInstruction(TmpInst0); - Directive.setOpcode(Mips::NOMACRO); - OutStreamer.EmitInstruction(Directive); + SmallVector<MCInst, 4> MCInsts; + + switch (Opc) { + case Mips::ULW: + case Mips::ULH: + case Mips::ULHu: + case Mips::USW: + case Mips::USH: + case Mips::ULW_P8: + case Mips::ULH_P8: + case Mips::ULHu_P8: + case Mips::USW_P8: + case Mips::USH_P8: + case Mips::ULD: + case Mips::ULW64: + case Mips::ULH64: + case Mips::ULHu64: + case Mips::USD: + case Mips::USW64: + case Mips::USH64: + case Mips::ULD_P8: + case Mips::ULW64_P8: + case Mips::ULH64_P8: + case Mips::ULHu64_P8: + case Mips::USD_P8: + case Mips::USW64_P8: + case Mips::USH64_P8: { + if (OutStreamer.hasRawTextSupport()) { + EmitInstrWithMacroNoAT(MI); + return; + } + + MCInstLowering.LowerUnalignedLoadStore(MI, MCInsts); + for (SmallVector<MCInst, 4>::iterator I = MCInsts.begin(); I + != MCInsts.end(); ++I) + OutStreamer.EmitInstruction(*I); + return; } + case Mips::CPRESTORE: { + const MachineOperand &MO = MI->getOperand(0); + assert(MO.isImm() && "CPRESTORE's operand must be an immediate."); + int64_t Offset = MO.getImm(); + + if (OutStreamer.hasRawTextSupport()) { + if (!isInt<16>(Offset)) { + EmitInstrWithMacroNoAT(MI); + return; + } + } else { + MCInstLowering.LowerCPRESTORE(Offset, MCInsts); + + for (SmallVector<MCInst, 4>::iterator I = MCInsts.begin(); + I != MCInsts.end(); ++I) + OutStreamer.EmitInstruction(*I); + return; + } + + break; + } + case Mips::SETGP01: { + MCInstLowering.LowerSETGP01(MI, MCInsts); + + for (SmallVector<MCInst, 4>::iterator I = MCInsts.begin(); + I != MCInsts.end(); ++I) + OutStreamer.EmitInstruction(*I); + + return; + } + default: + break; + } + + MCInstLowering.Lower(MI, TmpInst0); OutStreamer.EmitInstruction(TmpInst0); } @@ -138,7 +210,7 @@ void MipsAsmPrinter::printSavedRegsBitmask(raw_ostream &O) { if (Mips::CPURegsRegisterClass->contains(Reg)) break; - unsigned RegNum = MipsRegisterInfo::getRegisterNumbering(Reg); + unsigned RegNum = getMipsRegisterNumbering(Reg); if (Mips::AFGR64RegisterClass->contains(Reg)) { FPUBitmask |= (3 << RegNum); CSFPRegsSize += AFGR64RegSize; @@ -153,7 +225,7 @@ void MipsAsmPrinter::printSavedRegsBitmask(raw_ostream &O) { // Set CPU Bitmask. for (; i != e; ++i) { unsigned Reg = CSI[i].getReg(); - unsigned RegNum = MipsRegisterInfo::getRegisterNumbering(Reg); + unsigned RegNum = getMipsRegisterNumbering(Reg); CPUBitmask |= (1 << RegNum); } @@ -177,7 +249,7 @@ void MipsAsmPrinter::printSavedRegsBitmask(raw_ostream &O) { 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)); + O.write_hex((Value & (0xF << (i*4))) >> (i*4)); } //===----------------------------------------------------------------------===// @@ -192,10 +264,11 @@ void MipsAsmPrinter::emitFrameDirective() { unsigned returnReg = RI.getRARegister(); unsigned stackSize = MF->getFrameInfo()->getStackSize(); - OutStreamer.EmitRawText("\t.frame\t$" + - Twine(LowercaseString(MipsInstPrinter::getRegisterName(stackReg))) + + if (OutStreamer.hasRawTextSupport()) + OutStreamer.EmitRawText("\t.frame\t$" + + StringRef(MipsInstPrinter::getRegisterName(stackReg)).lower() + "," + Twine(stackSize) + ",$" + - Twine(LowercaseString(MipsInstPrinter::getRegisterName(returnReg)))); + StringRef(MipsInstPrinter::getRegisterName(returnReg)).lower()); } /// Emit Set directives. @@ -205,27 +278,49 @@ const char *MipsAsmPrinter::getCurrentABIString() const { case MipsSubtarget::N32: return "abiN32"; case MipsSubtarget::N64: return "abi64"; case MipsSubtarget::EABI: return "eabi32"; // TODO: handle eabi64 - default: break; + default: llvm_unreachable("Unknown Mips ABI");; } - - llvm_unreachable("Unknown Mips ABI"); - return NULL; } void MipsAsmPrinter::EmitFunctionEntryLabel() { - OutStreamer.EmitRawText("\t.ent\t" + Twine(CurrentFnSym->getName())); + if (OutStreamer.hasRawTextSupport()) + 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() { + MCInstLowering.Initialize(Mang, &MF->getContext()); + emitFrameDirective(); - SmallString<128> Str; - raw_svector_ostream OS(Str); - printSavedRegsBitmask(OS); - OutStreamer.EmitRawText(OS.str()); + bool EmitCPLoad = (MF->getTarget().getRelocationModel() == Reloc::PIC_) && + Subtarget->isABI_O32() && MipsFI->globalBaseRegSet() && + MipsFI->globalBaseRegFixed(); + + if (OutStreamer.hasRawTextSupport()) { + SmallString<128> Str; + raw_svector_ostream OS(Str); + printSavedRegsBitmask(OS); + OutStreamer.EmitRawText(OS.str()); + + OutStreamer.EmitRawText(StringRef("\t.set\tnoreorder")); + + // Emit .cpload directive if needed. + if (EmitCPLoad) + OutStreamer.EmitRawText(StringRef("\t.cpload\t$25")); + + OutStreamer.EmitRawText(StringRef("\t.set\tnomacro")); + if (MipsFI->getEmitNOAT()) + OutStreamer.EmitRawText(StringRef("\t.set\tnoat")); + } else if (EmitCPLoad) { + SmallVector<MCInst, 4> MCInsts; + MCInstLowering.LowerCPLOAD(MCInsts); + for (SmallVector<MCInst, 4>::iterator I = MCInsts.begin(); + I != MCInsts.end(); ++I) + OutStreamer.EmitInstruction(*I); + } } /// EmitFunctionBodyEnd - Targets can override this to emit stuff after @@ -234,11 +329,15 @@ 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())); -} + if (OutStreamer.hasRawTextSupport()) { + if (MipsFI->getEmitNOAT()) + OutStreamer.EmitRawText(StringRef("\t.set\tat")); + OutStreamer.EmitRawText(StringRef("\t.set\tmacro")); + OutStreamer.EmitRawText(StringRef("\t.set\treorder")); + OutStreamer.EmitRawText("\t.end\t" + Twine(CurrentFnSym->getName())); + } +} /// isBlockOnlyReachableByFallthough - Return true if the basic block has /// exactly one predecessor and the control transfer mechanism between @@ -262,24 +361,24 @@ bool MipsAsmPrinter::isBlockOnlyReachableByFallthrough(const MachineBasicBlock* // If there isn't exactly one predecessor, it can't be a fall through. MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), PI2 = PI; ++PI2; - + if (PI2 != MBB->pred_end()) - return false; + return false; // The predecessor has to be immediately before this block. if (!Pred->isLayoutSuccessor(MBB)) return false; - + // If the block is completely empty, then it definitely does fall through. if (Pred->empty()) return true; - + // Otherwise, check the last instruction. // Check if the last terminator is an unconditional branch. MachineBasicBlock::const_iterator I = Pred->end(); - while (I != Pred->begin() && !(--I)->getDesc().isTerminator()) ; + while (I != Pred->begin() && !(--I)->isTerminator()) ; - return !I->getDesc().isBarrier(); + return !I->isBarrier(); } // Print out an operand for an inline asm expression. @@ -300,7 +399,7 @@ bool MipsAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, raw_ostream &O) { if (ExtraCode && ExtraCode[0]) return true; // Unknown modifier. - + const MachineOperand &MO = MI->getOperand(OpNum); assert(MO.isReg() && "unexpected inline asm memory operand"); O << "0($" << MipsInstPrinter::getRegisterName(MO.getReg()) << ")"; @@ -335,7 +434,7 @@ void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum, switch (MO.getType()) { case MachineOperand::MO_Register: O << '$' - << LowercaseString(MipsInstPrinter::getRegisterName(MO.getReg())); + << StringRef(MipsInstPrinter::getRegisterName(MO.getReg())).lower(); break; case MachineOperand::MO_Immediate: @@ -420,18 +519,23 @@ void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) { // FIXME: Use SwitchSection. // Tell the assembler which ABI we are using - OutStreamer.EmitRawText("\t.section .mdebug." + Twine(getCurrentABIString())); + if (OutStreamer.hasRawTextSupport()) + 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")); + if (OutStreamer.hasRawTextSupport()) { + 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")); + if (OutStreamer.hasRawTextSupport()) + OutStreamer.EmitRawText(StringRef("\t.previous")); } MachineLocation diff --git a/lib/Target/Mips/MipsAsmPrinter.h b/lib/Target/Mips/MipsAsmPrinter.h index 16461ff1fbb0..562bf9ce0092 100644 --- a/lib/Target/Mips/MipsAsmPrinter.h +++ b/lib/Target/Mips/MipsAsmPrinter.h @@ -1,4 +1,4 @@ -//===-- MipsAsmPrinter.h - Mips LLVM assembly writer ----------------------===// +//===-- MipsAsmPrinter.h - Mips LLVM Assembly Printer ----------*- C++ -*--===// // // The LLVM Compiler Infrastructure // @@ -14,6 +14,8 @@ #ifndef MIPSASMPRINTER_H #define MIPSASMPRINTER_H +#include "MipsMachineFunction.h" +#include "MipsMCInstLower.h" #include "MipsSubtarget.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/Support/Compiler.h" @@ -22,16 +24,22 @@ namespace llvm { class MCStreamer; class MachineInstr; -class raw_ostream; class MachineBasicBlock; class Module; +class raw_ostream; class LLVM_LIBRARY_VISIBILITY MipsAsmPrinter : public AsmPrinter { - const MipsSubtarget *Subtarget; - + + void EmitInstrWithMacroNoAT(const MachineInstr *MI); + public: + + const MipsSubtarget *Subtarget; + const MipsFunctionInfo *MipsFI; + MipsMCInstLower MCInstLowering; + explicit MipsAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) - : AsmPrinter(TM, Streamer) { + : AsmPrinter(TM, Streamer), MCInstLowering(*this) { Subtarget = &TM.getSubtarget<MipsSubtarget>(); } @@ -39,6 +47,8 @@ public: return "Mips Assembly Printer"; } + virtual bool runOnMachineFunction(MachineFunction &MF); + void EmitInstruction(const MachineInstr *MI); void printSavedRegsBitmask(raw_ostream &O); void printHex32(unsigned int Value, raw_ostream &O); diff --git a/lib/Target/Mips/MipsCallingConv.td b/lib/Target/Mips/MipsCallingConv.td index 0ae4ef6fbad4..4b7e1d37662c 100644 --- a/lib/Target/Mips/MipsCallingConv.td +++ b/lib/Target/Mips/MipsCallingConv.td @@ -1,4 +1,4 @@ -//===- MipsCallingConv.td - Calling Conventions for Mips ---*- tablegen -*-===// +//===-- MipsCallingConv.td - Calling Conventions for Mips --*- tablegen -*-===// // // The LLVM Compiler Infrastructure // @@ -35,12 +35,18 @@ def RetCC_MipsO32 : CallingConv<[ //===----------------------------------------------------------------------===// def CC_MipsN : CallingConv<[ - // FIXME: Handle byval, complex and float double parameters. + // Handles byval parameters. + CCIfByVal<CCCustom<"CC_Mips64Byval">>, - // Promote i8/i16/i32 arguments to i64. - CCIfType<[i8, i16, i32], CCPromoteToType<i64>>, + // Promote i8/i16 arguments to i32. + CCIfType<[i8, i16], CCPromoteToType<i32>>, // Integer arguments are passed in integer registers. + CCIfType<[i32], CCAssignToRegWithShadow<[A0, A1, A2, A3, + T0, T1, T2, T3], + [F12, F13, F14, F15, + F16, F17, F18, F19]>>, + CCIfType<[i64], CCAssignToRegWithShadow<[A0_64, A1_64, A2_64, A3_64, T0_64, T1_64, T2_64, T3_64], [D12_64, D13_64, D14_64, D15_64, @@ -59,13 +65,30 @@ def CC_MipsN : CallingConv<[ T0_64, T1_64, T2_64, T3_64]>>, // All stack parameter slots become 64-bit doublewords and are 8-byte aligned. - CCIfType<[i64, f64], CCAssignToStack<8, 8>>, - CCIfType<[f32], CCAssignToStack<4, 8>> + CCIfType<[i32, f32], CCAssignToStack<4, 8>>, + CCIfType<[i64, f64], CCAssignToStack<8, 8>> ]>; -def RetCC_MipsN : CallingConv<[ - // FIXME: Handle complex and float double return values. +// N32/64 variable arguments. +// All arguments are passed in integer registers. +def CC_MipsN_VarArg : CallingConv<[ + // Handles byval parameters. + CCIfByVal<CCCustom<"CC_Mips64Byval">>, + + // Promote i8/i16 arguments to i32. + CCIfType<[i8, i16], CCPromoteToType<i32>>, + + CCIfType<[i32, f32], CCAssignToReg<[A0, A1, A2, A3, T0, T1, T2, T3]>>, + + CCIfType<[i64, f64], CCAssignToReg<[A0_64, A1_64, A2_64, A3_64, + T0_64, T1_64, T2_64, T3_64]>>, + + // All stack parameter slots become 64-bit doublewords and are 8-byte aligned. + CCIfType<[i32, f32], CCAssignToStack<4, 8>>, + CCIfType<[i64, f64], CCAssignToStack<8, 8>> +]>; +def RetCC_MipsN : CallingConv<[ // i32 are returned in registers V0, V1 CCIfType<[i32], CCAssignToReg<[V0, V1]>>, @@ -137,3 +160,20 @@ def RetCC_Mips : CallingConv<[ CCIfSubtarget<"isABI_N64()", CCDelegateTo<RetCC_MipsN>>, CCDelegateTo<RetCC_MipsO32> ]>; + +//===----------------------------------------------------------------------===// +// Callee-saved register lists. +//===----------------------------------------------------------------------===// + +def CSR_SingleFloatOnly : CalleeSavedRegs<(add (sequence "F%u", 31, 20), RA, FP, + (sequence "S%u", 7, 0))>; + +def CSR_O32 : CalleeSavedRegs<(add (sequence "D%u", 15, 10), RA, FP, + (sequence "S%u", 7, 0))>; + +def CSR_N32 : CalleeSavedRegs<(add D31_64, D29_64, D27_64, D25_64, D24_64, + D23_64, D22_64, D21_64, RA_64, FP_64, GP_64, + (sequence "S%u_64", 7, 0))>; + +def CSR_N64 : CalleeSavedRegs<(add (sequence "D%u_64", 31, 24), RA_64, FP_64, + GP_64, (sequence "S%u_64", 7, 0))>; diff --git a/lib/Target/Mips/MipsCodeEmitter.cpp b/lib/Target/Mips/MipsCodeEmitter.cpp index 23fabe315cf5..7d819026da96 100644 --- a/lib/Target/Mips/MipsCodeEmitter.cpp +++ b/lib/Target/Mips/MipsCodeEmitter.cpp @@ -1,4 +1,4 @@ -//===-- Mips/MipsCodeEmitter.cpp - Convert Mips code to machine code -----===// +//===-- Mips/MipsCodeEmitter.cpp - Convert Mips Code to Machine Code ------===// // // The LLVM Compiler Infrastructure // @@ -18,18 +18,20 @@ #include "MipsRelocations.h" #include "MipsSubtarget.h" #include "MipsTargetMachine.h" -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Function.h" -#include "llvm/PassManager.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/JITCodeEmitter.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/Passes.h" -#include "llvm/ADT/Statistic.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Function.h" +#include "llvm/PassManager.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" @@ -37,8 +39,6 @@ #include <iomanip> #endif -#include "llvm/CodeGen/MachineOperand.h" - using namespace llvm; STATISTIC(NumEmitted, "Number of machine instructions emitted"); @@ -66,9 +66,9 @@ class MipsCodeEmitter : public MachineFunctionPass { public: MipsCodeEmitter(TargetMachine &tm, JITCodeEmitter &mce) : MachineFunctionPass(ID), JTI(0), - II((const MipsInstrInfo *) tm.getInstrInfo()), - TD(tm.getTargetData()), TM(tm), MCE(mce), MCPEs(0), MJTEs(0), - IsPIC(TM.getRelocationModel() == Reloc::PIC_) { + II((const MipsInstrInfo *) tm.getInstrInfo()), + TD(tm.getTargetData()), TM(tm), MCE(mce), MCPEs(0), MJTEs(0), + IsPIC(TM.getRelocationModel() == Reloc::PIC_) { } bool runOnMachineFunction(MachineFunction &MF); @@ -80,7 +80,7 @@ class MipsCodeEmitter : public MachineFunctionPass { /// getBinaryCodeForInstr - This function, generated by the /// CodeEmitterGenerator using TableGen, produces the binary encoding for /// machine instructions. - unsigned getBinaryCodeForInstr(const MachineInstr &MI) const; + uint64_t getBinaryCodeForInstr(const MachineInstr &MI) const; void emitInstruction(const MachineInstr &MI); @@ -91,7 +91,7 @@ class MipsCodeEmitter : public MachineFunctionPass { /// Routines that handle operands which add machine relocations which are /// fixed up by the relocation stage. void emitGlobalAddress(const GlobalValue *GV, unsigned Reloc, - bool MayNeedFarStub) const; + bool MayNeedFarStub) const; void emitExternalSymbolAddress(const char *ES, unsigned Reloc) const; void emitConstPoolAddress(unsigned CPI, unsigned Reloc) const; void emitJumpTableAddress(unsigned JTIndex, unsigned Reloc) const; @@ -105,9 +105,22 @@ class MipsCodeEmitter : public MachineFunctionPass { unsigned getRelocation(const MachineInstr &MI, const MachineOperand &MO) const; + unsigned getJumpTargetOpValue(const MachineInstr &MI, unsigned OpNo) const; + + unsigned getBranchTargetOpValue(const MachineInstr &MI, + unsigned OpNo) const; unsigned getMemEncoding(const MachineInstr &MI, unsigned OpNo) const; unsigned getSizeExtEncoding(const MachineInstr &MI, unsigned OpNo) const; unsigned getSizeInsEncoding(const MachineInstr &MI, unsigned OpNo) const; + + int emitULW(const MachineInstr &MI); + int emitUSW(const MachineInstr &MI); + int emitULH(const MachineInstr &MI); + int emitULHu(const MachineInstr &MI); + int emitUSH(const MachineInstr &MI); + + void emitGlobalAddressUnaligned(const GlobalValue *GV, unsigned Reloc, + int Offset) const; }; } @@ -132,7 +145,7 @@ bool MipsCodeEmitter::runOnMachineFunction(MachineFunction &MF) { for (MachineFunction::iterator MBB = MF.begin(), E = MF.end(); MBB != E; ++MBB){ MCE.StartMachineBasicBlock(MBB); - for (MachineBasicBlock::const_iterator I = MBB->begin(), E = MBB->end(); + for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E; ++I) emitInstruction(*I); } @@ -149,30 +162,50 @@ unsigned MipsCodeEmitter::getRelocation(const MachineInstr &MI, if (Form == MipsII::FrmJ) return Mips::reloc_mips_26; if ((Form == MipsII::FrmI || Form == MipsII::FrmFI) - && MI.getDesc().isBranch()) - return Mips::reloc_mips_branch; + && MI.isBranch()) + return Mips::reloc_mips_pc16; if (Form == MipsII::FrmI && MI.getOpcode() == Mips::LUi) return Mips::reloc_mips_hi; return Mips::reloc_mips_lo; } +unsigned MipsCodeEmitter::getJumpTargetOpValue(const MachineInstr &MI, + unsigned OpNo) const { + MachineOperand MO = MI.getOperand(OpNo); + if (MO.isGlobal()) + emitGlobalAddress(MO.getGlobal(), getRelocation(MI, MO), true); + else if (MO.isSymbol()) + emitExternalSymbolAddress(MO.getSymbolName(), getRelocation(MI, MO)); + else if (MO.isMBB()) + emitMachineBasicBlock(MO.getMBB(), getRelocation(MI, MO)); + else + llvm_unreachable("Unexpected jump target operand kind."); + return 0; +} + +unsigned MipsCodeEmitter::getBranchTargetOpValue(const MachineInstr &MI, + unsigned OpNo) const { + MachineOperand MO = MI.getOperand(OpNo); + emitMachineBasicBlock(MO.getMBB(), getRelocation(MI, MO)); + return 0; +} + unsigned MipsCodeEmitter::getMemEncoding(const MachineInstr &MI, - unsigned OpNo) const { + unsigned OpNo) const { // Base register is encoded in bits 20-16, offset is encoded in bits 15-0. assert(MI.getOperand(OpNo).isReg()); unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo)) << 16; - return - (getMachineOpValue(MI, MI.getOperand(OpNo+1)) & 0xFFFF) | RegBits; + return (getMachineOpValue(MI, MI.getOperand(OpNo+1)) & 0xFFFF) | RegBits; } unsigned MipsCodeEmitter::getSizeExtEncoding(const MachineInstr &MI, - unsigned OpNo) const { + unsigned OpNo) const { // size is encoded as size-1. return getMachineOpValue(MI, MI.getOperand(OpNo)) - 1; } unsigned MipsCodeEmitter::getSizeInsEncoding(const MachineInstr &MI, - unsigned OpNo) const { + unsigned OpNo) const { // size is encoded as pos+size-1. return getMachineOpValue(MI, MI.getOperand(OpNo-1)) + getMachineOpValue(MI, MI.getOperand(OpNo)) - 1; @@ -181,14 +214,20 @@ unsigned MipsCodeEmitter::getSizeInsEncoding(const MachineInstr &MI, /// getMachineOpValue - Return binary encoding of operand. If the machine /// operand requires relocation, record the relocation and return zero. unsigned MipsCodeEmitter::getMachineOpValue(const MachineInstr &MI, - const MachineOperand &MO) const { + const MachineOperand &MO) const { if (MO.isReg()) - return MipsRegisterInfo::getRegisterNumbering(MO.getReg()); + return getMipsRegisterNumbering(MO.getReg()); else if (MO.isImm()) return static_cast<unsigned>(MO.getImm()); - else if (MO.isGlobal()) - emitGlobalAddress(MO.getGlobal(), getRelocation(MI, MO), true); - else if (MO.isSymbol()) + else if (MO.isGlobal()) { + if (MI.getOpcode() == Mips::ULW || MI.getOpcode() == Mips::USW || + MI.getOpcode() == Mips::ULH || MI.getOpcode() == Mips::ULHu) + emitGlobalAddressUnaligned(MO.getGlobal(), getRelocation(MI, MO), 4); + else if (MI.getOpcode() == Mips::USH) + emitGlobalAddressUnaligned(MO.getGlobal(), getRelocation(MI, MO), 8); + else + emitGlobalAddress(MO.getGlobal(), getRelocation(MI, MO), true); + } else if (MO.isSymbol()) emitExternalSymbolAddress(MO.getSymbolName(), getRelocation(MI, MO)); else if (MO.isCPI()) emitConstPoolAddress(MO.getIndex(), getRelocation(MI, MO)); @@ -202,9 +241,18 @@ unsigned MipsCodeEmitter::getMachineOpValue(const MachineInstr &MI, } void MipsCodeEmitter::emitGlobalAddress(const GlobalValue *GV, unsigned Reloc, - bool MayNeedFarStub) const { + bool MayNeedFarStub) const { MCE.addRelocation(MachineRelocation::getGV(MCE.getCurrentPCOffset(), Reloc, - const_cast<GlobalValue *>(GV), 0, MayNeedFarStub)); + const_cast<GlobalValue *>(GV), 0, + MayNeedFarStub)); +} + +void MipsCodeEmitter::emitGlobalAddressUnaligned(const GlobalValue *GV, + unsigned Reloc, int Offset) const { + MCE.addRelocation(MachineRelocation::getGV(MCE.getCurrentPCOffset(), Reloc, + const_cast<GlobalValue *>(GV), 0, false)); + MCE.addRelocation(MachineRelocation::getGV(MCE.getCurrentPCOffset() + Offset, + Reloc, const_cast<GlobalValue *>(GV), 0, false)); } void MipsCodeEmitter:: @@ -225,11 +273,108 @@ emitJumpTableAddress(unsigned JTIndex, unsigned Reloc) const { } void MipsCodeEmitter::emitMachineBasicBlock(MachineBasicBlock *BB, - unsigned Reloc) const { + unsigned Reloc) const { MCE.addRelocation(MachineRelocation::getBB(MCE.getCurrentPCOffset(), Reloc, BB)); } +int MipsCodeEmitter::emitUSW(const MachineInstr &MI) { + unsigned src = getMachineOpValue(MI, MI.getOperand(0)); + unsigned base = getMachineOpValue(MI, MI.getOperand(1)); + unsigned offset = getMachineOpValue(MI, MI.getOperand(2)); + // swr src, offset(base) + // swl src, offset+3(base) + MCE.emitWordLE( + (0x2e << 26) | (base << 21) | (src << 16) | (offset & 0xffff)); + MCE.emitWordLE( + (0x2a << 26) | (base << 21) | (src << 16) | ((offset+3) & 0xffff)); + return 2; +} + +int MipsCodeEmitter::emitULW(const MachineInstr &MI) { + unsigned dst = getMachineOpValue(MI, MI.getOperand(0)); + unsigned base = getMachineOpValue(MI, MI.getOperand(1)); + unsigned offset = getMachineOpValue(MI, MI.getOperand(2)); + unsigned at = 1; + if (dst != base) { + // lwr dst, offset(base) + // lwl dst, offset+3(base) + MCE.emitWordLE( + (0x26 << 26) | (base << 21) | (dst << 16) | (offset & 0xffff)); + MCE.emitWordLE( + (0x22 << 26) | (base << 21) | (dst << 16) | ((offset+3) & 0xffff)); + return 2; + } else { + // lwr at, offset(base) + // lwl at, offset+3(base) + // addu dst, at, $zero + MCE.emitWordLE( + (0x26 << 26) | (base << 21) | (at << 16) | (offset & 0xffff)); + MCE.emitWordLE( + (0x22 << 26) | (base << 21) | (at << 16) | ((offset+3) & 0xffff)); + MCE.emitWordLE( + (0x0 << 26) | (at << 21) | (0x0 << 16) | (dst << 11) | (0x0 << 6) | 0x21); + return 3; + } +} + +int MipsCodeEmitter::emitUSH(const MachineInstr &MI) { + unsigned src = getMachineOpValue(MI, MI.getOperand(0)); + unsigned base = getMachineOpValue(MI, MI.getOperand(1)); + unsigned offset = getMachineOpValue(MI, MI.getOperand(2)); + unsigned at = 1; + // sb src, offset(base) + // srl at,src,8 + // sb at, offset+1(base) + MCE.emitWordLE( + (0x28 << 26) | (base << 21) | (src << 16) | (offset & 0xffff)); + MCE.emitWordLE( + (0x0 << 26) | (0x0 << 21) | (src << 16) | (at << 11) | (0x8 << 6) | 0x2); + MCE.emitWordLE( + (0x28 << 26) | (base << 21) | (at << 16) | ((offset+1) & 0xffff)); + return 3; +} + +int MipsCodeEmitter::emitULH(const MachineInstr &MI) { + unsigned dst = getMachineOpValue(MI, MI.getOperand(0)); + unsigned base = getMachineOpValue(MI, MI.getOperand(1)); + unsigned offset = getMachineOpValue(MI, MI.getOperand(2)); + unsigned at = 1; + // lbu at, offset(base) + // lb dst, offset+1(base) + // sll dst,dst,8 + // or dst,dst,at + MCE.emitWordLE( + (0x24 << 26) | (base << 21) | (at << 16) | (offset & 0xffff)); + MCE.emitWordLE( + (0x20 << 26) | (base << 21) | (dst << 16) | ((offset+1) & 0xffff)); + MCE.emitWordLE( + (0x0 << 26) | (0x0 << 21) | (dst << 16) | (dst << 11) | (0x8 << 6) | 0x0); + MCE.emitWordLE( + (0x0 << 26) | (dst << 21) | (at << 16) | (dst << 11) | (0x0 << 6) | 0x25); + return 4; +} + +int MipsCodeEmitter::emitULHu(const MachineInstr &MI) { + unsigned dst = getMachineOpValue(MI, MI.getOperand(0)); + unsigned base = getMachineOpValue(MI, MI.getOperand(1)); + unsigned offset = getMachineOpValue(MI, MI.getOperand(2)); + unsigned at = 1; + // lbu at, offset(base) + // lbu dst, offset+1(base) + // sll dst,dst,8 + // or dst,dst,at + MCE.emitWordLE( + (0x24 << 26) | (base << 21) | (at << 16) | (offset & 0xffff)); + MCE.emitWordLE( + (0x24 << 26) | (base << 21) | (dst << 16) | ((offset+1) & 0xffff)); + MCE.emitWordLE( + (0x0 << 26) | (0x0 << 21) | (dst << 16) | (dst << 11) | (0x8 << 6) | 0x0); + MCE.emitWordLE( + (0x0 << 26) | (dst << 21) | (at << 16) | (dst << 11) | (0x0 << 6) | 0x25); + return 4; +} + void MipsCodeEmitter::emitInstruction(const MachineInstr &MI) { DEBUG(errs() << "JIT: " << (void*)MCE.getCurrentPCValue() << ":\t" << MI); @@ -239,11 +384,27 @@ void MipsCodeEmitter::emitInstruction(const MachineInstr &MI) { if ((MI.getDesc().TSFlags & MipsII::FormMask) == MipsII::Pseudo) return; - ++NumEmitted; // Keep track of the # of mi's emitted switch (MI.getOpcode()) { + case Mips::USW: + NumEmitted += emitUSW(MI); + break; + case Mips::ULW: + NumEmitted += emitULW(MI); + break; + case Mips::ULH: + NumEmitted += emitULH(MI); + break; + case Mips::ULHu: + NumEmitted += emitULHu(MI); + break; + case Mips::USH: + NumEmitted += emitUSH(MI); + break; + default: emitWordLE(getBinaryCodeForInstr(MI)); + ++NumEmitted; // Keep track of the # of mi's emitted break; } @@ -259,7 +420,7 @@ void MipsCodeEmitter::emitWordLE(unsigned Word) { /// createMipsJITCodeEmitterPass - Return a pass that emits the collected Mips /// code to the specified MCE object. FunctionPass *llvm::createMipsJITCodeEmitterPass(MipsTargetMachine &TM, - JITCodeEmitter &JCE) { + JITCodeEmitter &JCE) { return new MipsCodeEmitter(TM, JCE); } diff --git a/lib/Target/Mips/MipsCondMov.td b/lib/Target/Mips/MipsCondMov.td new file mode 100644 index 000000000000..075a3e807b1f --- /dev/null +++ b/lib/Target/Mips/MipsCondMov.td @@ -0,0 +1,194 @@ +//===-- MipsCondMov.td - Describe Mips Conditional Moves --*- tablegen -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is the Conditional Moves implementation. +// +//===----------------------------------------------------------------------===// + +// Conditional moves: +// These instructions are expanded in +// MipsISelLowering::EmitInstrWithCustomInserter if target does not have +// conditional move instructions. +// cond:int, data:int +class CondMovIntInt<RegisterClass CRC, RegisterClass DRC, bits<6> funct, + string instr_asm> : + FR<0, funct, (outs DRC:$rd), (ins DRC:$rs, CRC:$rt, DRC:$F), + !strconcat(instr_asm, "\t$rd, $rs, $rt"), [], NoItinerary> { + let shamt = 0; + let Constraints = "$F = $rd"; +} + +// cond:int, data:float +class CondMovIntFP<RegisterClass CRC, RegisterClass DRC, bits<5> fmt, + bits<6> func, string instr_asm> : + FFR<0x11, func, fmt, (outs DRC:$fd), (ins DRC:$fs, CRC:$rt, DRC:$F), + !strconcat(instr_asm, "\t$fd, $fs, $rt"), []> { + bits<5> rt; + let ft = rt; + let Constraints = "$F = $fd"; +} + +// cond:float, data:int +class CondMovFPInt<RegisterClass RC, SDNode cmov, bits<1> tf, + string instr_asm> : + FCMOV<tf, (outs RC:$rd), (ins RC:$rs, RC:$F), + !strconcat(instr_asm, "\t$rd, $rs, $$fcc0"), + [(set RC:$rd, (cmov RC:$rs, RC:$F))]> { + let cc = 0; + let Uses = [FCR31]; + let Constraints = "$F = $rd"; +} + +// cond:float, data:float +class CondMovFPFP<RegisterClass RC, SDNode cmov, bits<5> fmt, bits<1> tf, + string instr_asm> : + FFCMOV<fmt, tf, (outs RC:$fd), (ins RC:$fs, RC:$F), + !strconcat(instr_asm, "\t$fd, $fs, $$fcc0"), + [(set RC:$fd, (cmov RC:$fs, RC:$F))]> { + let cc = 0; + let Uses = [FCR31]; + let Constraints = "$F = $fd"; +} + +// select patterns +multiclass MovzPats0<RegisterClass CRC, RegisterClass DRC, + Instruction MOVZInst, Instruction SLTOp, + Instruction SLTuOp, Instruction SLTiOp, + Instruction SLTiuOp> { + def : Pat<(select (i32 (setge CRC:$lhs, CRC:$rhs)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTOp CRC:$lhs, CRC:$rhs), DRC:$F)>; + def : Pat<(select (i32 (setuge CRC:$lhs, CRC:$rhs)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTuOp CRC:$lhs, CRC:$rhs), DRC:$F)>; + def : Pat<(select (i32 (setge CRC:$lhs, immSExt16:$rhs)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTiOp CRC:$lhs, immSExt16:$rhs), DRC:$F)>; + def : Pat<(select (i32 (setuge CRC:$lh, immSExt16:$rh)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTiuOp CRC:$lh, immSExt16:$rh), DRC:$F)>; + def : Pat<(select (i32 (setle CRC:$lhs, CRC:$rhs)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTOp CRC:$rhs, CRC:$lhs), DRC:$F)>; + def : Pat<(select (i32 (setule CRC:$lhs, CRC:$rhs)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTuOp CRC:$rhs, CRC:$lhs), DRC:$F)>; +} + +multiclass MovzPats1<RegisterClass CRC, RegisterClass DRC, + Instruction MOVZInst, Instruction XOROp> { + def : Pat<(select (i32 (seteq CRC:$lhs, CRC:$rhs)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (XOROp CRC:$lhs, CRC:$rhs), DRC:$F)>; + def : Pat<(select (i32 (seteq CRC:$lhs, 0)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, CRC:$lhs, DRC:$F)>; +} + +multiclass MovnPats<RegisterClass CRC, RegisterClass DRC, Instruction MOVNInst, + Instruction XOROp> { + def : Pat<(select (i32 (setne CRC:$lhs, CRC:$rhs)), DRC:$T, DRC:$F), + (MOVNInst DRC:$T, (XOROp CRC:$lhs, CRC:$rhs), DRC:$F)>; + def : Pat<(select CRC:$cond, DRC:$T, DRC:$F), + (MOVNInst DRC:$T, CRC:$cond, DRC:$F)>; + def : Pat<(select (i32 (setne CRC:$lhs, 0)),DRC:$T, DRC:$F), + (MOVNInst DRC:$T, CRC:$lhs, DRC:$F)>; +} + +// Instantiation of instructions. +def MOVZ_I_I : CondMovIntInt<CPURegs, CPURegs, 0x0a, "movz">; +let Predicates = [HasMips64] in { + def MOVZ_I_I64 : CondMovIntInt<CPURegs, CPU64Regs, 0x0a, "movz">; + def MOVZ_I64_I : CondMovIntInt<CPU64Regs, CPURegs, 0x0a, "movz">; + def MOVZ_I64_I64 : CondMovIntInt<CPU64Regs, CPU64Regs, 0x0a, "movz">; +} + +def MOVN_I_I : CondMovIntInt<CPURegs, CPURegs, 0x0b, "movn">; +let Predicates = [HasMips64] in { + def MOVN_I_I64 : CondMovIntInt<CPURegs, CPU64Regs, 0x0b, "movn">; + def MOVN_I64_I : CondMovIntInt<CPU64Regs, CPURegs, 0x0b, "movn">; + def MOVN_I64_I64 : CondMovIntInt<CPU64Regs, CPU64Regs, 0x0b, "movn">; +} + +def MOVZ_I_S : CondMovIntFP<CPURegs, FGR32, 16, 18, "movz.s">; +def MOVZ_I64_S : CondMovIntFP<CPU64Regs, FGR32, 16, 18, "movz.s">, + Requires<[HasMips64]>; + +def MOVN_I_S : CondMovIntFP<CPURegs, FGR32, 16, 19, "movn.s">; +def MOVN_I64_S : CondMovIntFP<CPU64Regs, FGR32, 16, 19, "movn.s">, + Requires<[HasMips64]>; + +let Predicates = [NotFP64bit] in { + def MOVZ_I_D32 : CondMovIntFP<CPURegs, AFGR64, 17, 18, "movz.d">; + def MOVN_I_D32 : CondMovIntFP<CPURegs, AFGR64, 17, 19, "movn.d">; +} +let Predicates = [IsFP64bit] in { + def MOVZ_I_D64 : CondMovIntFP<CPURegs, FGR64, 17, 18, "movz.d">; + def MOVZ_I64_D64 : CondMovIntFP<CPU64Regs, FGR64, 17, 18, "movz.d">; + def MOVN_I_D64 : CondMovIntFP<CPURegs, FGR64, 17, 19, "movn.d">; + def MOVN_I64_D64 : CondMovIntFP<CPU64Regs, FGR64, 17, 19, "movn.d">; +} + +def MOVT_I : CondMovFPInt<CPURegs, MipsCMovFP_T, 1, "movt">; +def MOVT_I64 : CondMovFPInt<CPU64Regs, MipsCMovFP_T, 1, "movt">, + Requires<[HasMips64]>; + +def MOVF_I : CondMovFPInt<CPURegs, MipsCMovFP_F, 0, "movf">; +def MOVF_I64 : CondMovFPInt<CPU64Regs, MipsCMovFP_F, 0, "movf">, + Requires<[HasMips64]>; + +def MOVT_S : CondMovFPFP<FGR32, MipsCMovFP_T, 16, 1, "movt.s">; +def MOVF_S : CondMovFPFP<FGR32, MipsCMovFP_F, 16, 0, "movf.s">; + +let Predicates = [NotFP64bit] in { + def MOVT_D32 : CondMovFPFP<AFGR64, MipsCMovFP_T, 17, 1, "movt.d">; + def MOVF_D32 : CondMovFPFP<AFGR64, MipsCMovFP_F, 17, 0, "movf.d">; +} +let Predicates = [IsFP64bit] in { + def MOVT_D64 : CondMovFPFP<FGR64, MipsCMovFP_T, 17, 1, "movt.d">; + def MOVF_D64 : CondMovFPFP<FGR64, MipsCMovFP_F, 17, 0, "movf.d">; +} + +// Instantiation of conditional move patterns. +defm : MovzPats0<CPURegs, CPURegs, MOVZ_I_I, SLT, SLTu, SLTi, SLTiu>; +defm : MovzPats1<CPURegs, CPURegs, MOVZ_I_I, XOR>; +let Predicates = [HasMips64] in { + defm : MovzPats0<CPURegs, CPU64Regs, MOVZ_I_I64, SLT, SLTu, SLTi, SLTiu>; + defm : MovzPats0<CPU64Regs, CPURegs, MOVZ_I_I, SLT64, SLTu64, SLTi64, + SLTiu64>; + defm : MovzPats0<CPU64Regs, CPU64Regs, MOVZ_I_I64, SLT64, SLTu64, SLTi64, + SLTiu64>; + defm : MovzPats1<CPURegs, CPU64Regs, MOVZ_I_I64, XOR>; + defm : MovzPats1<CPU64Regs, CPURegs, MOVZ_I64_I, XOR64>; + defm : MovzPats1<CPU64Regs, CPU64Regs, MOVZ_I64_I64, XOR64>; +} + +defm : MovnPats<CPURegs, CPURegs, MOVN_I_I, XOR>; +let Predicates = [HasMips64] in { + defm : MovnPats<CPURegs, CPU64Regs, MOVN_I_I64, XOR>; + defm : MovnPats<CPU64Regs, CPURegs, MOVN_I64_I, XOR64>; + defm : MovnPats<CPU64Regs, CPU64Regs, MOVN_I64_I64, XOR64>; +} + +defm : MovzPats0<CPURegs, FGR32, MOVZ_I_S, SLT, SLTu, SLTi, SLTiu>; +defm : MovzPats1<CPURegs, FGR32, MOVZ_I_S, XOR>; +defm : MovnPats<CPURegs, FGR32, MOVN_I_S, XOR>; +let Predicates = [HasMips64] in { + defm : MovzPats0<CPU64Regs, FGR32, MOVZ_I_S, SLT64, SLTu64, SLTi64, + SLTiu64>; + defm : MovzPats1<CPU64Regs, FGR32, MOVZ_I64_S, XOR64>; + defm : MovnPats<CPU64Regs, FGR32, MOVN_I64_S, XOR64>; +} + +let Predicates = [NotFP64bit] in { + defm : MovzPats0<CPURegs, AFGR64, MOVZ_I_D32, SLT, SLTu, SLTi, SLTiu>; + defm : MovzPats1<CPURegs, AFGR64, MOVZ_I_D32, XOR>; + defm : MovnPats<CPURegs, AFGR64, MOVN_I_D32, XOR>; +} +let Predicates = [IsFP64bit] in { + defm : MovzPats0<CPURegs, FGR64, MOVZ_I_D64, SLT, SLTu, SLTi, SLTiu>; + defm : MovzPats0<CPU64Regs, FGR64, MOVZ_I_D64, SLT64, SLTu64, SLTi64, + SLTiu64>; + defm : MovzPats1<CPURegs, FGR64, MOVZ_I_D64, XOR>; + defm : MovzPats1<CPU64Regs, FGR64, MOVZ_I64_D64, XOR64>; + defm : MovnPats<CPURegs, FGR64, MOVN_I_D64, XOR>; + defm : MovnPats<CPU64Regs, FGR64, MOVN_I64_D64, XOR64>; +} diff --git a/lib/Target/Mips/MipsDelaySlotFiller.cpp b/lib/Target/Mips/MipsDelaySlotFiller.cpp index be3b7a02ec31..debf2f1b85c1 100644 --- a/lib/Target/Mips/MipsDelaySlotFiller.cpp +++ b/lib/Target/Mips/MipsDelaySlotFiller.cpp @@ -1,4 +1,4 @@ -//===-- DelaySlotFiller.cpp - Mips delay slot filler ---------------------===// +//===-- DelaySlotFiller.cpp - Mips Delay Slot Filler ----------------------===// // // The LLVM Compiler Infrastructure // @@ -96,7 +96,7 @@ runOnMachineBasicBlock(MachineBasicBlock &MBB) { LastFiller = MBB.end(); for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) - if (I->getDesc().hasDelaySlot()) { + if (I->hasDelaySlot()) { ++FilledSlots; Changed = true; @@ -105,8 +105,7 @@ runOnMachineBasicBlock(MachineBasicBlock &MBB) { if (EnableDelaySlotFiller && findDelayInstr(MBB, I, D)) { MBB.splice(llvm::next(I), &MBB, D); ++UsefulSlots; - } - else + } else BuildMI(MBB, llvm::next(I), I->getDebugLoc(), TII->get(Mips::NOP)); // Record the filler instruction that filled the delay slot. @@ -146,7 +145,7 @@ bool Filler::findDelayInstr(MachineBasicBlock &MBB, || I->isInlineAsm() || I->isLabel() || FI == LastFiller - || I->getDesc().isPseudo() + || I->isPseudo() // // Should not allow: // ERET, DERET or WAIT, PAUSE. Need to add these to instruction @@ -167,23 +166,21 @@ bool Filler::findDelayInstr(MachineBasicBlock &MBB, } bool Filler::delayHasHazard(MachineBasicBlock::iterator candidate, - bool &sawLoad, - bool &sawStore, + bool &sawLoad, bool &sawStore, SmallSet<unsigned, 32> &RegDefs, SmallSet<unsigned, 32> &RegUses) { if (candidate->isImplicitDef() || candidate->isKill()) return true; - MCInstrDesc MCID = candidate->getDesc(); // Loads or stores cannot be moved past a store to the delay slot - // and stores cannot be moved past a load. - if (MCID.mayLoad()) { + // and stores cannot be moved past a load. + if (candidate->mayLoad()) { if (sawStore) return true; sawLoad = true; } - if (MCID.mayStore()) { + if (candidate->mayStore()) { if (sawStore) return true; sawStore = true; @@ -191,7 +188,7 @@ bool Filler::delayHasHazard(MachineBasicBlock::iterator candidate, return true; } - assert((!MCID.isCall() && !MCID.isReturn()) && + assert((!candidate->isCall() && !candidate->isReturn()) && "Cannot put calls or returns in delay slot."); for (unsigned i = 0, e = candidate->getNumOperands(); i!= e; ++i) { @@ -221,11 +218,11 @@ void Filler::insertDefsUses(MachineBasicBlock::iterator MI, SmallSet<unsigned, 32>& RegUses) { // If MI is a call or return, just examine the explicit non-variadic operands. MCInstrDesc MCID = MI->getDesc(); - unsigned e = MCID.isCall() || MCID.isReturn() ? MCID.getNumOperands() : - MI->getNumOperands(); - - // Add RA to RegDefs to prevent users of RA from going into delay slot. - if (MCID.isCall()) + unsigned e = MI->isCall() || MI->isReturn() ? MCID.getNumOperands() : + MI->getNumOperands(); + + // Add RA to RegDefs to prevent users of RA from going into delay slot. + if (MI->isCall()) RegDefs.insert(Mips::RA); for (unsigned i = 0; i != e; ++i) { @@ -247,7 +244,7 @@ bool Filler::IsRegInSet(SmallSet<unsigned, 32>& RegSet, unsigned Reg) { if (RegSet.count(Reg)) return true; // check Aliased Registers - for (const unsigned *Alias = TM.getRegisterInfo()->getAliasSet(Reg); + for (const uint16_t *Alias = TM.getRegisterInfo()->getAliasSet(Reg); *Alias; ++Alias) if (RegSet.count(*Alias)) return true; diff --git a/lib/Target/Mips/MipsEmitGPRestore.cpp b/lib/Target/Mips/MipsEmitGPRestore.cpp index 03d922fe7cd6..119d1a824688 100644 --- a/lib/Target/Mips/MipsEmitGPRestore.cpp +++ b/lib/Target/Mips/MipsEmitGPRestore.cpp @@ -1,4 +1,4 @@ -//===-- MipsEmitGPRestore.cpp - Emit GP restore instruction----------------===// +//===-- MipsEmitGPRestore.cpp - Emit GP Restore Instruction ---------------===// // // The LLVM Compiler Infrastructure // @@ -44,11 +44,14 @@ namespace { } // end of anonymous namespace bool Inserter::runOnMachineFunction(MachineFunction &F) { - if (TM.getRelocationModel() != Reloc::PIC_) + MipsFunctionInfo *MipsFI = F.getInfo<MipsFunctionInfo>(); + + if ((TM.getRelocationModel() != Reloc::PIC_) || + (!MipsFI->globalBaseRegFixed())) return false; bool Changed = false; - int FI = F.getInfo<MipsFunctionInfo>()->getGPFI(); + int FI = MipsFI->getGPFI(); for (MachineFunction::iterator MFI = F.begin(), MFE = F.end(); MFI != MFE; ++MFI) { @@ -60,7 +63,7 @@ bool Inserter::runOnMachineFunction(MachineFunction &F) { if (MBB.isLandingPad()) { // Find EH_LABEL first. for (; I->getOpcode() != TargetOpcode::EH_LABEL; ++I) ; - + // Insert lw. ++I; DebugLoc dl = I != MBB.end() ? I->getDebugLoc() : DebugLoc(); @@ -81,7 +84,7 @@ bool Inserter::runOnMachineFunction(MachineFunction &F) { .addImm(0); Changed = true; } - } + } return Changed; } diff --git a/lib/Target/Mips/MipsExpandPseudo.cpp b/lib/Target/Mips/MipsExpandPseudo.cpp index a622258a4dcb..baeae97a4f52 100644 --- a/lib/Target/Mips/MipsExpandPseudo.cpp +++ b/lib/Target/Mips/MipsExpandPseudo.cpp @@ -1,4 +1,4 @@ -//===-- MipsExpandPseudo.cpp - Expand pseudo instructions ----------------===// +//===-- MipsExpandPseudo.cpp - Expand Pseudo Instructions ----------------===// // // The LLVM Compiler Infrastructure // @@ -64,16 +64,22 @@ bool MipsExpandPseudo::runOnMachineBasicBlock(MachineBasicBlock& MBB) { const MCInstrDesc& MCid = I->getDesc(); switch(MCid.getOpcode()) { - default: + default: ++I; continue; + case Mips::SETGP2: + // Convert "setgp2 $globalreg, $t9" to "addu $globalreg, $v0, $t9" + BuildMI(MBB, I, I->getDebugLoc(), TII->get(Mips::ADDu), + I->getOperand(0).getReg()) + .addReg(Mips::V0).addReg(I->getOperand(1).getReg()); + break; case Mips::BuildPairF64: ExpandBuildPairF64(MBB, I); break; case Mips::ExtractElementF64: ExpandExtractElementF64(MBB, I); break; - } + } // delete original instr MBB.erase(I++); @@ -84,12 +90,12 @@ bool MipsExpandPseudo::runOnMachineBasicBlock(MachineBasicBlock& MBB) { } void MipsExpandPseudo::ExpandBuildPairF64(MachineBasicBlock& MBB, - MachineBasicBlock::iterator I) { + MachineBasicBlock::iterator I) { unsigned DstReg = I->getOperand(0).getReg(); unsigned LoReg = I->getOperand(1).getReg(), HiReg = I->getOperand(2).getReg(); const MCInstrDesc& Mtc1Tdd = TII->get(Mips::MTC1); DebugLoc dl = I->getDebugLoc(); - const unsigned* SubReg = + const uint16_t* SubReg = TM.getRegisterInfo()->getSubRegisters(DstReg); // mtc1 Lo, $fp @@ -105,12 +111,12 @@ void MipsExpandPseudo::ExpandExtractElementF64(MachineBasicBlock& MBB, unsigned N = I->getOperand(2).getImm(); const MCInstrDesc& Mfc1Tdd = TII->get(Mips::MFC1); DebugLoc dl = I->getDebugLoc(); - const unsigned* SubReg = TM.getRegisterInfo()->getSubRegisters(SrcReg); + const uint16_t* SubReg = TM.getRegisterInfo()->getSubRegisters(SrcReg); BuildMI(MBB, I, dl, Mfc1Tdd, DstReg).addReg(*(SubReg + N)); } -/// createMipsMipsExpandPseudoPass - Returns a pass that expands pseudo +/// createMipsMipsExpandPseudoPass - Returns a pass that expands pseudo /// instrs into real instrs FunctionPass *llvm::createMipsExpandPseudoPass(MipsTargetMachine &tm) { return new MipsExpandPseudo(tm); diff --git a/lib/Target/Mips/MipsFrameLowering.cpp b/lib/Target/Mips/MipsFrameLowering.cpp index 22d1e47b1a2b..f8ea3d0321d2 100644 --- a/lib/Target/Mips/MipsFrameLowering.cpp +++ b/lib/Target/Mips/MipsFrameLowering.cpp @@ -1,4 +1,4 @@ -//=======- MipsFrameLowering.cpp - Mips Frame Information ------*- C++ -*-====// +//===-- MipsFrameLowering.cpp - Mips Frame Information --------------------===// // // The LLVM Compiler Infrastructure // @@ -12,8 +12,10 @@ //===----------------------------------------------------------------------===// #include "MipsFrameLowering.h" +#include "MipsAnalyzeImmediate.h" #include "MipsInstrInfo.h" #include "MipsMachineFunction.h" +#include "MCTargetDesc/MipsBaseInfo.h" #include "llvm/Function.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" @@ -84,55 +86,44 @@ using namespace llvm; // if frame pointer elimination is disabled. bool MipsFrameLowering::hasFP(const MachineFunction &MF) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); - return DisableFramePointerElim(MF) || MFI->hasVarSizedObjects() - || MFI->isFrameAddressTaken(); + return MF.getTarget().Options.DisableFramePointerElim(MF) || + MFI->hasVarSizedObjects() || MFI->isFrameAddressTaken(); } bool MipsFrameLowering::targetHandlesStackFrameRounding() const { return true; } -static unsigned AlignOffset(unsigned Offset, unsigned Align) { - return (Offset + Align - 1) / Align * Align; -} - -// expand pair of register and immediate if the immediate doesn't fit in the -// 16-bit offset field. -// e.g. -// if OrigImm = 0x10000, OrigReg = $sp: -// generate the following sequence of instrs: -// lui $at, hi(0x10000) -// addu $at, $sp, $at -// -// (NewReg, NewImm) = ($at, lo(Ox10000)) -// return true -static bool expandRegLargeImmPair(unsigned OrigReg, int OrigImm, - unsigned& NewReg, int& NewImm, - MachineBasicBlock& MBB, - MachineBasicBlock::iterator I) { - // OrigImm fits in the 16-bit field - if (OrigImm < 0x8000 && OrigImm >= -0x8000) { - NewReg = OrigReg; - NewImm = OrigImm; - return false; - } +// Build an instruction sequence to load an immediate that is too large to fit +// in 16-bit and add the result to Reg. +static void expandLargeImm(unsigned Reg, int64_t Imm, bool IsN64, + const MipsInstrInfo &TII, MachineBasicBlock& MBB, + MachineBasicBlock::iterator II, DebugLoc DL) { + unsigned LUi = IsN64 ? Mips::LUi64 : Mips::LUi; + unsigned ADDu = IsN64 ? Mips::DADDu : Mips::ADDu; + unsigned ZEROReg = IsN64 ? Mips::ZERO_64 : Mips::ZERO; + unsigned ATReg = IsN64 ? Mips::AT_64 : Mips::AT; + MipsAnalyzeImmediate AnalyzeImm; + const MipsAnalyzeImmediate::InstSeq &Seq = + AnalyzeImm.Analyze(Imm, IsN64 ? 64 : 32, false /* LastInstrIsADDiu */); + MipsAnalyzeImmediate::InstSeq::const_iterator Inst = Seq.begin(); + + // The first instruction can be a LUi, which is different from other + // instructions (ADDiu, ORI and SLL) in that it does not have a register + // operand. + if (Inst->Opc == LUi) + BuildMI(MBB, II, DL, TII.get(LUi), ATReg) + .addImm(SignExtend64<16>(Inst->ImmOpnd)); + else + BuildMI(MBB, II, DL, TII.get(Inst->Opc), ATReg).addReg(ZEROReg) + .addImm(SignExtend64<16>(Inst->ImmOpnd)); - MachineFunction* MF = MBB.getParent(); - const TargetInstrInfo *TII = MF->getTarget().getInstrInfo(); - DebugLoc DL = I->getDebugLoc(); - int ImmLo = (short)(OrigImm & 0xffff); - int ImmHi = (((unsigned)OrigImm & 0xffff0000) >> 16) + - ((OrigImm & 0x8000) != 0); - - // FIXME: change this when mips goes MC". - BuildMI(MBB, I, DL, TII->get(Mips::NOAT)); - BuildMI(MBB, I, DL, TII->get(Mips::LUi), Mips::AT).addImm(ImmHi); - BuildMI(MBB, I, DL, TII->get(Mips::ADDu), Mips::AT).addReg(OrigReg) - .addReg(Mips::AT); - NewReg = Mips::AT; - NewImm = ImmLo; + // Build the remaining instructions in Seq. + for (++Inst; Inst != Seq.end(); ++Inst) + BuildMI(MBB, II, DL, TII.get(Inst->Opc), ATReg).addReg(ATReg) + .addImm(SignExtend64<16>(Inst->ImmOpnd)); - return true; + BuildMI(MBB, II, DL, TII.get(ADDu), Reg).addReg(Reg).addReg(ATReg); } void MipsFrameLowering::emitPrologue(MachineFunction &MF) const { @@ -146,29 +137,41 @@ void MipsFrameLowering::emitPrologue(MachineFunction &MF) const { MachineBasicBlock::iterator MBBI = MBB.begin(); DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); bool isPIC = (MF.getTarget().getRelocationModel() == Reloc::PIC_); - unsigned NewReg = 0; - int NewImm = 0; - bool ATUsed; + unsigned SP = STI.isABI_N64() ? Mips::SP_64 : Mips::SP; + unsigned FP = STI.isABI_N64() ? Mips::FP_64 : Mips::FP; + unsigned ZERO = STI.isABI_N64() ? Mips::ZERO_64 : Mips::ZERO; + unsigned ADDu = STI.isABI_N64() ? Mips::DADDu : Mips::ADDu; + unsigned ADDiu = STI.isABI_N64() ? Mips::DADDiu : Mips::ADDiu; // First, compute final stack size. unsigned RegSize = STI.isGP32bit() ? 4 : 8; unsigned StackAlign = getStackAlignment(); - unsigned LocalVarAreaOffset = MipsFI->needGPSaveRestore() ? + unsigned LocalVarAreaOffset = MipsFI->needGPSaveRestore() ? (MFI->getObjectOffset(MipsFI->getGPFI()) + RegSize) : MipsFI->getMaxCallFrameSize(); - unsigned StackSize = AlignOffset(LocalVarAreaOffset, StackAlign) + - AlignOffset(MFI->getStackSize(), StackAlign); + uint64_t StackSize = RoundUpToAlignment(LocalVarAreaOffset, StackAlign) + + RoundUpToAlignment(MFI->getStackSize(), StackAlign); // Update stack size - MFI->setStackSize(StackSize); - - BuildMI(MBB, MBBI, dl, TII.get(Mips::NOREORDER)); - - // TODO: check need from GP here. - if (isPIC && STI.isABI_O32()) - BuildMI(MBB, MBBI, dl, TII.get(Mips::CPLOAD)) - .addReg(RegInfo->getPICCallReg()); - BuildMI(MBB, MBBI, dl, TII.get(Mips::NOMACRO)); + MFI->setStackSize(StackSize); + + // Emit instructions that set the global base register if the target ABI is + // O32. + if (isPIC && MipsFI->globalBaseRegSet() && STI.isABI_O32() && + !MipsFI->globalBaseRegFixed()) { + // See MipsInstrInfo.td for explanation. + MachineBasicBlock *NewEntry = MF.CreateMachineBasicBlock(); + MF.insert(&MBB, NewEntry); + NewEntry->addSuccessor(&MBB); + + // Copy live in registers. + for (MachineBasicBlock::livein_iterator R = MBB.livein_begin(); + R != MBB.livein_end(); ++R) + NewEntry->addLiveIn(*R); + + BuildMI(*NewEntry, NewEntry->begin(), dl, TII.get(Mips:: SETGP01), + Mips::V0); + } // No need to allocate space on the stack. if (StackSize == 0 && !MFI->adjustsStack()) return; @@ -177,15 +180,13 @@ void MipsFrameLowering::emitPrologue(MachineFunction &MF) const { std::vector<MachineMove> &Moves = MMI.getFrameMoves(); MachineLocation DstML, SrcML; - // Adjust stack : addi sp, sp, (-imm) - ATUsed = expandRegLargeImmPair(Mips::SP, -StackSize, NewReg, NewImm, MBB, - MBBI); - BuildMI(MBB, MBBI, dl, TII.get(Mips::ADDiu), Mips::SP) - .addReg(NewReg).addImm(NewImm); - - // FIXME: change this when mips goes MC". - if (ATUsed) - BuildMI(MBB, MBBI, dl, TII.get(Mips::ATMACRO)); + // Adjust stack. + if (isInt<16>(-StackSize)) // addi sp, sp, (-stacksize) + BuildMI(MBB, MBBI, dl, TII.get(ADDiu), SP).addReg(SP).addImm(-StackSize); + else { // Expand immediate that doesn't fit in 16-bit. + MipsFI->setEmitNOAT(); + expandLargeImm(SP, -StackSize, STI.isABI_N64(), TII, MBB, MBBI, dl); + } // emit ".cfi_def_cfa_offset StackSize" MCSymbol *AdjustSPLabel = MMI.getContext().CreateTempSymbol(); @@ -202,13 +203,13 @@ void MipsFrameLowering::emitPrologue(MachineFunction &MF) const { // register to the stack. for (unsigned i = 0; i < CSI.size(); ++i) ++MBBI; - + // Iterate over list of callee-saved registers and emit .cfi_offset // directives. MCSymbol *CSLabel = MMI.getContext().CreateTempSymbol(); BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::PROLOG_LABEL)).addSym(CSLabel); - + for (std::vector<CalleeSavedInfo>::const_iterator I = CSI.begin(), E = CSI.end(); I != E; ++I) { int64_t Offset = MFI->getObjectOffset(I->getFrameIdx()); @@ -217,7 +218,7 @@ void MipsFrameLowering::emitPrologue(MachineFunction &MF) const { // If Reg is a double precision register, emit two cfa_offsets, // one for each of the paired single precision registers. if (Mips::AFGR64RegisterClass->contains(Reg)) { - const unsigned *SubRegs = RegInfo->getSubRegisters(Reg); + const uint16_t *SubRegs = RegInfo->getSubRegisters(Reg); MachineLocation DstML0(MachineLocation::VirtualFP, Offset); MachineLocation DstML1(MachineLocation::VirtualFP, Offset + 4); MachineLocation SrcML0(*SubRegs); @@ -236,19 +237,18 @@ void MipsFrameLowering::emitPrologue(MachineFunction &MF) const { Moves.push_back(MachineMove(CSLabel, DstML, SrcML)); } } - } + } // if framepointer enabled, set it to point to the stack pointer. if (hasFP(MF)) { - // Insert instruction "move $fp, $sp" at this location. - BuildMI(MBB, MBBI, dl, TII.get(Mips::ADDu), Mips::FP) - .addReg(Mips::SP).addReg(Mips::ZERO); + // Insert instruction "move $fp, $sp" at this location. + BuildMI(MBB, MBBI, dl, TII.get(ADDu), FP).addReg(SP).addReg(ZERO); - // emit ".cfi_def_cfa_register $fp" + // emit ".cfi_def_cfa_register $fp" MCSymbol *SetFPLabel = MMI.getContext().CreateTempSymbol(); BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::PROLOG_LABEL)).addSym(SetFPLabel); - DstML = MachineLocation(Mips::FP); + DstML = MachineLocation(FP); SrcML = MachineLocation(MachineLocation::VirtualFP); Moves.push_back(MachineMove(SetFPLabel, DstML, SrcML)); } @@ -256,12 +256,8 @@ void MipsFrameLowering::emitPrologue(MachineFunction &MF) const { // Restore GP from the saved stack location if (MipsFI->needGPSaveRestore()) { unsigned Offset = MFI->getObjectOffset(MipsFI->getGPFI()); - BuildMI(MBB, MBBI, dl, TII.get(Mips::CPRESTORE)).addImm(Offset); - - if (Offset >= 0x8000) { - BuildMI(MBB, llvm::prior(MBBI), dl, TII.get(Mips::MACRO)); - BuildMI(MBB, MBBI, dl, TII.get(Mips::NOMACRO)); - } + BuildMI(MBB, MBBI, dl, TII.get(Mips::CPRESTORE)).addImm(Offset) + .addReg(Mips::GP); } } @@ -272,59 +268,59 @@ void MipsFrameLowering::emitEpilogue(MachineFunction &MF, const MipsInstrInfo &TII = *static_cast<const MipsInstrInfo*>(MF.getTarget().getInstrInfo()); DebugLoc dl = MBBI->getDebugLoc(); - - // Get the number of bytes from FrameInfo - unsigned StackSize = MFI->getStackSize(); - - unsigned NewReg = 0; - int NewImm = 0; - bool ATUsed = false; + unsigned SP = STI.isABI_N64() ? Mips::SP_64 : Mips::SP; + unsigned FP = STI.isABI_N64() ? Mips::FP_64 : Mips::FP; + unsigned ZERO = STI.isABI_N64() ? Mips::ZERO_64 : Mips::ZERO; + unsigned ADDu = STI.isABI_N64() ? Mips::DADDu : Mips::ADDu; + unsigned ADDiu = STI.isABI_N64() ? Mips::DADDiu : Mips::ADDiu; // if framepointer enabled, restore the stack pointer. if (hasFP(MF)) { // Find the first instruction that restores a callee-saved register. MachineBasicBlock::iterator I = MBBI; - + for (unsigned i = 0; i < MFI->getCalleeSavedInfo().size(); ++i) --I; // Insert instruction "move $sp, $fp" at this location. - BuildMI(MBB, I, dl, TII.get(Mips::ADDu), Mips::SP) - .addReg(Mips::FP).addReg(Mips::ZERO); + BuildMI(MBB, I, dl, TII.get(ADDu), SP).addReg(FP).addReg(ZERO); } - // adjust stack : insert addi sp, sp, (imm) - if (StackSize) { - ATUsed = expandRegLargeImmPair(Mips::SP, StackSize, NewReg, NewImm, MBB, - MBBI); - BuildMI(MBB, MBBI, dl, TII.get(Mips::ADDiu), Mips::SP) - .addReg(NewReg).addImm(NewImm); + // Get the number of bytes from FrameInfo + uint64_t StackSize = MFI->getStackSize(); - // FIXME: change this when mips goes MC". - if (ATUsed) - BuildMI(MBB, MBBI, dl, TII.get(Mips::ATMACRO)); - } + if (!StackSize) + return; + + // Adjust stack. + if (isInt<16>(StackSize)) // addi sp, sp, (-stacksize) + BuildMI(MBB, MBBI, dl, TII.get(ADDiu), SP).addReg(SP).addImm(StackSize); + else // Expand immediate that doesn't fit in 16-bit. + expandLargeImm(SP, StackSize, STI.isABI_N64(), TII, MBB, MBBI, dl); } void MipsFrameLowering:: processFunctionBeforeCalleeSavedScan(MachineFunction &MF, RegScavenger *RS) const { MachineRegisterInfo& MRI = MF.getRegInfo(); + unsigned FP = STI.isABI_N64() ? Mips::FP_64 : Mips::FP; // FIXME: remove this code if register allocator can correctly mark // $fp and $ra used or unused. // Mark $fp and $ra as used or unused. if (hasFP(MF)) - MRI.setPhysRegUsed(Mips::FP); + MRI.setPhysRegUsed(FP); - // The register allocator might determine $ra is used after seeing + // The register allocator might determine $ra is used after seeing // instruction "jr $ra", but we do not want PrologEpilogInserter to insert // instructions to save/restore $ra unless there is a function call. // To correct this, $ra is explicitly marked unused if there is no // function call. if (MF.getFrameInfo()->hasCalls()) MRI.setPhysRegUsed(Mips::RA); - else + else { MRI.setPhysRegUnused(Mips::RA); + MRI.setPhysRegUnused(Mips::RA_64); + } } diff --git a/lib/Target/Mips/MipsFrameLowering.h b/lib/Target/Mips/MipsFrameLowering.h index c24975614c8d..bd1d89f04bc1 100644 --- a/lib/Target/Mips/MipsFrameLowering.h +++ b/lib/Target/Mips/MipsFrameLowering.h @@ -1,4 +1,4 @@ -//==--- MipsFrameLowering.h - Define frame lowering for Mips --*- C++ -*---===// +//===-- MipsFrameLowering.h - Define frame lowering for Mips ----*- C++ -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/Mips/MipsISelDAGToDAG.cpp b/lib/Target/Mips/MipsISelDAGToDAG.cpp index 9c831ede9dbf..f0651c61311b 100644 --- a/lib/Target/Mips/MipsISelDAGToDAG.cpp +++ b/lib/Target/Mips/MipsISelDAGToDAG.cpp @@ -1,4 +1,4 @@ -//===-- MipsISelDAGToDAG.cpp - A dag to dag inst selector for Mips --------===// +//===-- MipsISelDAGToDAG.cpp - A Dag to Dag Inst Selector for Mips --------===// // // The LLVM Compiler Infrastructure // @@ -13,10 +13,12 @@ #define DEBUG_TYPE "mips-isel" #include "Mips.h" +#include "MipsAnalyzeImmediate.h" #include "MipsMachineFunction.h" #include "MipsRegisterInfo.h" #include "MipsSubtarget.h" #include "MipsTargetMachine.h" +#include "MCTargetDesc/MipsBaseInfo.h" #include "llvm/GlobalValue.h" #include "llvm/Instructions.h" #include "llvm/Intrinsics.h" @@ -28,6 +30,7 @@ #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/CodeGen/SelectionDAGNodes.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" @@ -63,6 +66,7 @@ public: return "MIPS DAG->DAG Pattern Instruction Selection"; } + virtual bool runOnMachineFunction(MachineFunction &MF); private: // Include the pieces autogenerated from the target description. @@ -81,17 +85,24 @@ private: } SDNode *getGlobalBaseReg(); + + std::pair<SDNode*, SDNode*> SelectMULT(SDNode *N, unsigned Opc, DebugLoc dl, + EVT Ty, bool HasLo, bool HasHi); + SDNode *Select(SDNode *N); // Complex Pattern. - bool SelectAddr(SDValue N, SDValue &Base, SDValue &Offset); + bool SelectAddr(SDNode *Parent, SDValue N, SDValue &Base, SDValue &Offset); - // getI32Imm - Return a target constant with the specified - // value, of type i32. - inline SDValue getI32Imm(unsigned Imm) { - return CurDAG->getTargetConstant(Imm, MVT::i32); + // getImm - Return a target constant with the specified value. + inline SDValue getImm(const SDNode *Node, unsigned Imm) { + return CurDAG->getTargetConstant(Imm, Node->getValueType(0)); } + void ProcessFunctionAfterISel(MachineFunction &MF); + bool ReplaceUsesWithZeroReg(MachineRegisterInfo *MRI, const MachineInstr&); + void InitGlobalBaseReg(MachineFunction &MF); + virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, std::vector<SDValue> &OutOps); @@ -99,20 +110,163 @@ private: } +// Insert instructions to initialize the global base register in the +// first MBB of the function. When the ABI is O32 and the relocation model is +// PIC, the necessary instructions are emitted later to prevent optimization +// passes from moving them. +void MipsDAGToDAGISel::InitGlobalBaseReg(MachineFunction &MF) { + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + if (!MipsFI->globalBaseRegSet()) + return; + + MachineBasicBlock &MBB = MF.front(); + MachineBasicBlock::iterator I = MBB.begin(); + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); + DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc(); + unsigned V0, V1, GlobalBaseReg = MipsFI->getGlobalBaseReg(); + bool FixGlobalBaseReg = MipsFI->globalBaseRegFixed(); + + if (Subtarget.isABI_O32() && FixGlobalBaseReg) + // $gp is the global base register. + V0 = V1 = GlobalBaseReg; + else { + const TargetRegisterClass *RC; + RC = Subtarget.isABI_N64() ? + Mips::CPU64RegsRegisterClass : Mips::CPURegsRegisterClass; + + V0 = RegInfo.createVirtualRegister(RC); + V1 = RegInfo.createVirtualRegister(RC); + } + + if (Subtarget.isABI_N64()) { + MF.getRegInfo().addLiveIn(Mips::T9_64); + MBB.addLiveIn(Mips::T9_64); + + // lui $v0, %hi(%neg(%gp_rel(fname))) + // daddu $v1, $v0, $t9 + // daddiu $globalbasereg, $v1, %lo(%neg(%gp_rel(fname))) + const GlobalValue *FName = MF.getFunction(); + BuildMI(MBB, I, DL, TII.get(Mips::LUi64), V0) + .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_HI); + BuildMI(MBB, I, DL, TII.get(Mips::DADDu), V1).addReg(V0).addReg(Mips::T9_64); + BuildMI(MBB, I, DL, TII.get(Mips::DADDiu), GlobalBaseReg).addReg(V1) + .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_LO); + } else if (MF.getTarget().getRelocationModel() == Reloc::Static) { + // Set global register to __gnu_local_gp. + // + // lui $v0, %hi(__gnu_local_gp) + // addiu $globalbasereg, $v0, %lo(__gnu_local_gp) + BuildMI(MBB, I, DL, TII.get(Mips::LUi), V0) + .addExternalSymbol("__gnu_local_gp", MipsII::MO_ABS_HI); + BuildMI(MBB, I, DL, TII.get(Mips::ADDiu), GlobalBaseReg).addReg(V0) + .addExternalSymbol("__gnu_local_gp", MipsII::MO_ABS_LO); + } else { + MF.getRegInfo().addLiveIn(Mips::T9); + MBB.addLiveIn(Mips::T9); + + if (Subtarget.isABI_N32()) { + // lui $v0, %hi(%neg(%gp_rel(fname))) + // addu $v1, $v0, $t9 + // addiu $globalbasereg, $v1, %lo(%neg(%gp_rel(fname))) + const GlobalValue *FName = MF.getFunction(); + BuildMI(MBB, I, DL, TII.get(Mips::LUi), V0) + .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_HI); + BuildMI(MBB, I, DL, TII.get(Mips::ADDu), V1).addReg(V0).addReg(Mips::T9); + BuildMI(MBB, I, DL, TII.get(Mips::ADDiu), GlobalBaseReg).addReg(V1) + .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_LO); + } else if (!MipsFI->globalBaseRegFixed()) { + assert(Subtarget.isABI_O32()); + + BuildMI(MBB, I, DL, TII.get(Mips::SETGP2), GlobalBaseReg) + .addReg(Mips::T9); + } + } +} + +bool MipsDAGToDAGISel::ReplaceUsesWithZeroReg(MachineRegisterInfo *MRI, + const MachineInstr& MI) { + unsigned DstReg = 0, ZeroReg = 0; + + // Check if MI is "addiu $dst, $zero, 0" or "daddiu $dst, $zero, 0". + if ((MI.getOpcode() == Mips::ADDiu) && + (MI.getOperand(1).getReg() == Mips::ZERO) && + (MI.getOperand(2).getImm() == 0)) { + DstReg = MI.getOperand(0).getReg(); + ZeroReg = Mips::ZERO; + } else if ((MI.getOpcode() == Mips::DADDiu) && + (MI.getOperand(1).getReg() == Mips::ZERO_64) && + (MI.getOperand(2).getImm() == 0)) { + DstReg = MI.getOperand(0).getReg(); + ZeroReg = Mips::ZERO_64; + } + + if (!DstReg) + return false; + + // Replace uses with ZeroReg. + for (MachineRegisterInfo::use_iterator U = MRI->use_begin(DstReg), + E = MRI->use_end(); U != E; ++U) { + MachineOperand &MO = U.getOperand(); + MachineInstr *MI = MO.getParent(); + + // Do not replace if it is a phi's operand or is tied to def operand. + if (MI->isPHI() || MI->isRegTiedToDefOperand(U.getOperandNo())) + continue; + + MO.setReg(ZeroReg); + } + + return true; +} + +void MipsDAGToDAGISel::ProcessFunctionAfterISel(MachineFunction &MF) { + InitGlobalBaseReg(MF); + + MachineRegisterInfo *MRI = &MF.getRegInfo(); + + for (MachineFunction::iterator MFI = MF.begin(), MFE = MF.end(); MFI != MFE; + ++MFI) + for (MachineBasicBlock::iterator I = MFI->begin(); I != MFI->end(); ++I) + ReplaceUsesWithZeroReg(MRI, *I); +} + +bool MipsDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { + bool Ret = SelectionDAGISel::runOnMachineFunction(MF); + + ProcessFunctionAfterISel(MF); + + return Ret; +} /// getGlobalBaseReg - Output the instructions required to put the /// GOT address into a register. SDNode *MipsDAGToDAGISel::getGlobalBaseReg() { - unsigned GlobalBaseReg = getInstrInfo()->getGlobalBaseReg(MF); + unsigned GlobalBaseReg = MF->getInfo<MipsFunctionInfo>()->getGlobalBaseReg(); return CurDAG->getRegister(GlobalBaseReg, TLI.getPointerTy()).getNode(); } /// ComplexPattern used on MipsInstrInfo /// Used on Mips Load/Store instructions bool MipsDAGToDAGISel:: -SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) { +SelectAddr(SDNode *Parent, SDValue Addr, SDValue &Base, SDValue &Offset) { EVT ValTy = Addr.getValueType(); - unsigned GPReg = ValTy == MVT::i32 ? Mips::GP : Mips::GP_64; + + // If Parent is an unaligned f32 load or store, select a (base + index) + // floating point load/store instruction (luxc1 or suxc1). + const LSBaseSDNode* LS = 0; + + if (Parent && (LS = dyn_cast<LSBaseSDNode>(Parent))) { + EVT VT = LS->getMemoryVT(); + + if (VT.getSizeInBits() / 8 > LS->getAlignment()) { + assert(TLI.allowsUnalignedMemoryAccesses(VT) && + "Unaligned loads/stores not supported for this type."); + if (VT == MVT::f32) + return false; + } + } // if Address is FI, get the TargetFrameIndex. if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { @@ -122,21 +276,16 @@ SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) { } // on PIC code Load GA - if (TM.getRelocationModel() == Reloc::PIC_) { - if (Addr.getOpcode() == MipsISD::WrapperPIC) { - Base = CurDAG->getRegister(GPReg, ValTy); - Offset = Addr.getOperand(0); - return true; - } - } else { + if (Addr.getOpcode() == MipsISD::Wrapper) { + Base = Addr.getOperand(0); + Offset = Addr.getOperand(1); + return true; + } + + if (TM.getRelocationModel() != Reloc::PIC_) { if ((Addr.getOpcode() == ISD::TargetExternalSymbol || Addr.getOpcode() == ISD::TargetGlobalAddress)) return false; - else if (Addr.getOpcode() == ISD::TargetGlobalTLSAddress) { - Base = CurDAG->getRegister(GPReg, ValTy); - Offset = Addr; - return true; - } } // Addresses of the form FI+const or FI|const @@ -166,17 +315,20 @@ SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) { // 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) { + if (Addr.getOperand(1).getOpcode() == MipsISD::Lo) { SDValue LoVal = Addr.getOperand(1); - if (isa<ConstantPoolSDNode>(LoVal.getOperand(0)) || + if (isa<ConstantPoolSDNode>(LoVal.getOperand(0)) || isa<GlobalAddressSDNode>(LoVal.getOperand(0))) { Base = Addr.getOperand(0); Offset = LoVal.getOperand(0); return true; } } + + // If an indexed floating point load/store can be emitted, return false. + if (LS && (LS->getMemoryVT() == MVT::f32 || LS->getMemoryVT() == MVT::f64) && + Subtarget.hasMips32r2Or64()) + return false; } Base = Addr; @@ -184,6 +336,28 @@ SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) { return true; } +/// Select multiply instructions. +std::pair<SDNode*, SDNode*> +MipsDAGToDAGISel::SelectMULT(SDNode *N, unsigned Opc, DebugLoc dl, EVT Ty, + bool HasLo, bool HasHi) { + SDNode *Lo = 0, *Hi = 0; + SDNode *Mul = CurDAG->getMachineNode(Opc, dl, MVT::Glue, N->getOperand(0), + N->getOperand(1)); + SDValue InFlag = SDValue(Mul, 0); + + if (HasLo) { + Lo = CurDAG->getMachineNode(Ty == MVT::i32 ? Mips::MFLO : Mips::MFLO64, dl, + Ty, MVT::Glue, InFlag); + InFlag = SDValue(Lo, 1); + } + if (HasHi) + Hi = CurDAG->getMachineNode(Ty == MVT::i32 ? Mips::MFHI : Mips::MFHI64, dl, + Ty, InFlag); + + return std::make_pair(Lo, Hi); +} + + /// Select instructions not customized! Used for /// expanded, promoted and normal instructions SDNode* MipsDAGToDAGISel::Select(SDNode *Node) { @@ -203,123 +377,167 @@ SDNode* MipsDAGToDAGISel::Select(SDNode *Node) { // Instruction Selection not handled by the auto-generated // tablegen selection should be handled here. /// + EVT NodeTy = Node->getValueType(0); + unsigned MultOpc; + switch(Opcode) { - default: break; - - case ISD::SUBE: - case ISD::ADDE: { - SDValue InFlag = Node->getOperand(2), CmpLHS; - unsigned Opc = InFlag.getOpcode(); (void)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; - } + default: break; + + case ISD::SUBE: + case ISD::ADDE: { + SDValue InFlag = Node->getOperand(2), CmpLHS; + unsigned Opc = InFlag.getOpcode(); (void)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 Ops[] = { CmpLHS, InFlag.getOperand(1) }; - SDValue LHS = Node->getOperand(0); - SDValue RHS = Node->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); + 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::Glue, - LHS, SDValue(AddCarry,0)); - } + return CurDAG->SelectNodeTo(Node, MOp, VT, MVT::Glue, + LHS, SDValue(AddCarry,0)); + } - /// Mul with two results - case ISD::SMUL_LOHI: - case ISD::UMUL_LOHI: { - assert(Node->getValueType(0) != MVT::i64 && - "64-bit multiplication with two results not handled."); - SDValue Op1 = Node->getOperand(0); - SDValue Op2 = Node->getOperand(1); + /// Mul with two results + case ISD::SMUL_LOHI: + case ISD::UMUL_LOHI: { + if (NodeTy == MVT::i32) + MultOpc = (Opcode == ISD::UMUL_LOHI ? Mips::MULTu : Mips::MULT); + else + MultOpc = (Opcode == ISD::UMUL_LOHI ? Mips::DMULTu : Mips::DMULT); - unsigned Op; - Op = (Opcode == ISD::UMUL_LOHI ? Mips::MULTu : Mips::MULT); + std::pair<SDNode*, SDNode*> LoHi = SelectMULT(Node, MultOpc, dl, NodeTy, + true, true); - SDNode *Mul = CurDAG->getMachineNode(Op, dl, MVT::Glue, Op1, Op2); + if (!SDValue(Node, 0).use_empty()) + ReplaceUses(SDValue(Node, 0), SDValue(LoHi.first, 0)); - SDValue InFlag = SDValue(Mul, 0); - SDNode *Lo = CurDAG->getMachineNode(Mips::MFLO, dl, MVT::i32, - MVT::Glue, InFlag); - InFlag = SDValue(Lo,1); - SDNode *Hi = CurDAG->getMachineNode(Mips::MFHI, dl, MVT::i32, InFlag); + if (!SDValue(Node, 1).use_empty()) + ReplaceUses(SDValue(Node, 1), SDValue(LoHi.second, 0)); - if (!SDValue(Node, 0).use_empty()) - ReplaceUses(SDValue(Node, 0), SDValue(Lo,0)); + return NULL; + } - if (!SDValue(Node, 1).use_empty()) - ReplaceUses(SDValue(Node, 1), SDValue(Hi,0)); + /// Special Muls + case ISD::MUL: { + // Mips32 has a 32-bit three operand mul instruction. + if (Subtarget.hasMips32() && NodeTy == MVT::i32) + break; + return SelectMULT(Node, NodeTy == MVT::i32 ? Mips::MULT : Mips::DMULT, + dl, NodeTy, true, false).first; + } + case ISD::MULHS: + case ISD::MULHU: { + if (NodeTy == MVT::i32) + MultOpc = (Opcode == ISD::MULHU ? Mips::MULTu : Mips::MULT); + else + MultOpc = (Opcode == ISD::MULHU ? Mips::DMULTu : Mips::DMULT); + + return SelectMULT(Node, MultOpc, dl, NodeTy, false, true).second; + } - return NULL; - } + // Get target GOT address. + case ISD::GLOBAL_OFFSET_TABLE: + return getGlobalBaseReg(); - /// Special Muls - case ISD::MUL: - // Mips32 has a 32-bit three operand mul instruction. - if (Subtarget.hasMips32() && Node->getValueType(0) == MVT::i32) - break; - case ISD::MULHS: - case ISD::MULHU: { - assert((Opcode == ISD::MUL || Node->getValueType(0) != MVT::i64) && - "64-bit MULH* not handled."); - EVT Ty = Node->getValueType(0); - SDValue MulOp1 = Node->getOperand(0); - SDValue MulOp2 = Node->getOperand(1); - - unsigned MulOp = (Opcode == ISD::MULHU ? - Mips::MULTu : - (Ty == MVT::i32 ? Mips::MULT : Mips::DMULT)); - SDNode *MulNode = CurDAG->getMachineNode(MulOp, dl, - MVT::Glue, MulOp1, MulOp2); - - SDValue InFlag = SDValue(MulNode, 0); - - if (Opcode == ISD::MUL) { - unsigned Opc = (Ty == MVT::i32 ? Mips::MFLO : Mips::MFLO64); - return CurDAG->getMachineNode(Opc, dl, Ty, InFlag); + case ISD::ConstantFP: { + ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(Node); + if (Node->getValueType(0) == MVT::f64 && CN->isExactlyValue(+0.0)) { + if (Subtarget.hasMips64()) { + SDValue Zero = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl, + Mips::ZERO_64, MVT::i64); + return CurDAG->getMachineNode(Mips::DMTC1, dl, MVT::f64, Zero); } - else - return CurDAG->getMachineNode(Mips::MFHI, dl, MVT::i32, InFlag); + + SDValue Zero = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl, + Mips::ZERO, MVT::i32); + return CurDAG->getMachineNode(Mips::BuildPairF64, dl, MVT::f64, Zero, + Zero); } + break; + } - // Get target GOT address. - case ISD::GLOBAL_OFFSET_TABLE: - return getGlobalBaseReg(); + case ISD::Constant: { + const ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Node); + unsigned Size = CN->getValueSizeInBits(0); - 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); - return CurDAG->getMachineNode(Mips::BuildPairF64, dl, MVT::f64, Zero, - Zero); - } + if (Size == 32) break; + + MipsAnalyzeImmediate AnalyzeImm; + int64_t Imm = CN->getSExtValue(); + + const MipsAnalyzeImmediate::InstSeq &Seq = + AnalyzeImm.Analyze(Imm, Size, false); + + MipsAnalyzeImmediate::InstSeq::const_iterator Inst = Seq.begin(); + DebugLoc DL = CN->getDebugLoc(); + SDNode *RegOpnd; + SDValue ImmOpnd = CurDAG->getTargetConstant(SignExtend64<16>(Inst->ImmOpnd), + MVT::i64); + + // The first instruction can be a LUi which is different from other + // instructions (ADDiu, ORI and SLL) in that it does not have a register + // operand. + if (Inst->Opc == Mips::LUi64) + RegOpnd = CurDAG->getMachineNode(Inst->Opc, DL, MVT::i64, ImmOpnd); + else + RegOpnd = + CurDAG->getMachineNode(Inst->Opc, DL, MVT::i64, + CurDAG->getRegister(Mips::ZERO_64, MVT::i64), + ImmOpnd); + + // The remaining instructions in the sequence are handled here. + for (++Inst; Inst != Seq.end(); ++Inst) { + ImmOpnd = CurDAG->getTargetConstant(SignExtend64<16>(Inst->ImmOpnd), + MVT::i64); + RegOpnd = CurDAG->getMachineNode(Inst->Opc, DL, MVT::i64, + SDValue(RegOpnd, 0), ImmOpnd); } - case MipsISD::ThreadPointer: { - unsigned SrcReg = Mips::HWR29; - unsigned DestReg = Mips::V1; - SDNode *Rdhwr = CurDAG->getMachineNode(Mips::RDHWR, Node->getDebugLoc(), - Node->getValueType(0), CurDAG->getRegister(SrcReg, MVT::i32)); - SDValue Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, DestReg, - SDValue(Rdhwr, 0)); - SDValue ResNode = CurDAG->getCopyFromReg(Chain, dl, DestReg, MVT::i32); - ReplaceUses(SDValue(Node, 0), ResNode); - return ResNode.getNode(); + return RegOpnd; + } + + case MipsISD::ThreadPointer: { + EVT PtrVT = TLI.getPointerTy(); + unsigned RdhwrOpc, SrcReg, DestReg; + + if (PtrVT == MVT::i32) { + RdhwrOpc = Mips::RDHWR; + SrcReg = Mips::HWR29; + DestReg = Mips::V1; + } else { + RdhwrOpc = Mips::RDHWR64; + SrcReg = Mips::HWR29_64; + DestReg = Mips::V1_64; } + + SDNode *Rdhwr = + CurDAG->getMachineNode(RdhwrOpc, Node->getDebugLoc(), + Node->getValueType(0), + CurDAG->getRegister(SrcReg, PtrVT)); + SDValue Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, DestReg, + SDValue(Rdhwr, 0)); + SDValue ResNode = CurDAG->getCopyFromReg(Chain, dl, DestReg, PtrVT); + ReplaceUses(SDValue(Node, 0), ResNode); + return ResNode.getNode(); + } } // Select the default instruction diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp index 1932e745c593..6a23bc3d1d7c 100644 --- a/lib/Target/Mips/MipsISelLowering.cpp +++ b/lib/Target/Mips/MipsISelLowering.cpp @@ -18,12 +18,13 @@ #include "MipsTargetMachine.h" #include "MipsTargetObjectFile.h" #include "MipsSubtarget.h" +#include "InstPrinter/MipsInstPrinter.h" +#include "MCTargetDesc/MipsBaseInfo.h" #include "llvm/DerivedTypes.h" #include "llvm/Function.h" #include "llvm/GlobalVariable.h" #include "llvm/Intrinsics.h" #include "llvm/CallingConv.h" -#include "InstPrinter/MipsInstPrinter.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" @@ -35,27 +36,29 @@ #include "llvm/Support/ErrorHandling.h" using namespace llvm; -// If I is a shifted mask, set the size (Size) and the first bit of the +// If I is a shifted mask, set the size (Size) and the first bit of the // mask (Pos), and return true. -// For example, if I is 0x003ff800, (Pos, Size) = (11, 11). +// For example, if I is 0x003ff800, (Pos, Size) = (11, 11). static bool IsShiftedMask(uint64_t I, uint64_t &Pos, uint64_t &Size) { - if (!isUInt<32>(I) || !isShiftedMask_32(I)) + if (!isShiftedMask_64(I)) return false; - Size = CountPopulation_32(I); - Pos = CountTrailingZeros_32(I); + Size = CountPopulation_64(I); + Pos = CountTrailingZeros_64(I); return true; } +static SDValue GetGlobalReg(SelectionDAG &DAG, EVT Ty) { + MipsFunctionInfo *FI = DAG.getMachineFunction().getInfo<MipsFunctionInfo>(); + return DAG.getRegister(FI->getGlobalBaseReg(), Ty); +} + 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::TlsGd: return "MipsISD::TlsGd"; - case MipsISD::TprelHi: return "MipsISD::TprelHi"; - case MipsISD::TprelLo: return "MipsISD::TprelLo"; case MipsISD::ThreadPointer: return "MipsISD::ThreadPointer"; case MipsISD::Ret: return "MipsISD::Ret"; case MipsISD::FPBrcond: return "MipsISD::FPBrcond"; @@ -71,7 +74,7 @@ const char *MipsTargetLowering::getTargetNodeName(unsigned Opcode) const { case MipsISD::DivRemU: return "MipsISD::DivRemU"; case MipsISD::BuildPairF64: return "MipsISD::BuildPairF64"; case MipsISD::ExtractElementF64: return "MipsISD::ExtractElementF64"; - case MipsISD::WrapperPIC: return "MipsISD::WrapperPIC"; + case MipsISD::Wrapper: return "MipsISD::Wrapper"; case MipsISD::DynAlloc: return "MipsISD::DynAlloc"; case MipsISD::Sync: return "MipsISD::Sync"; case MipsISD::Ext: return "MipsISD::Ext"; @@ -84,7 +87,8 @@ MipsTargetLowering:: MipsTargetLowering(MipsTargetMachine &TM) : TargetLowering(TM, new MipsTargetObjectFile()), Subtarget(&TM.getSubtarget<MipsSubtarget>()), - HasMips64(Subtarget->hasMips64()), IsN64(Subtarget->isABI_N64()) { + HasMips64(Subtarget->hasMips64()), IsN64(Subtarget->isABI_N64()), + IsO32(Subtarget->isABI_O32()) { // Mips does not have i1 type, so use i32 for // setcc operations results (slt, sgt, ...). @@ -93,17 +97,20 @@ MipsTargetLowering(MipsTargetMachine &TM) // Set up the register classes addRegisterClass(MVT::i32, Mips::CPURegsRegisterClass); - addRegisterClass(MVT::f32, Mips::FGR32RegisterClass); if (HasMips64) addRegisterClass(MVT::i64, Mips::CPU64RegsRegisterClass); - // When dealing with single precision only, use libcalls - if (!Subtarget->isSingleFloat()) { - if (HasMips64) - addRegisterClass(MVT::f64, Mips::FGR64RegisterClass); - else - addRegisterClass(MVT::f64, Mips::AFGR64RegisterClass); + if (!TM.Options.UseSoftFloat) { + addRegisterClass(MVT::f32, Mips::FGR32RegisterClass); + + // When dealing with single precision only, use libcalls + if (!Subtarget->isSingleFloat()) { + if (HasMips64) + addRegisterClass(MVT::f64, Mips::FGR64RegisterClass); + else + addRegisterClass(MVT::f64, Mips::AFGR64RegisterClass); + } } // Load extented operations for i1 types must be promoted @@ -123,7 +130,6 @@ MipsTargetLowering(MipsTargetMachine &TM) // Mips Custom Operations setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); - setOperationAction(ISD::GlobalAddress, MVT::i64, Custom); setOperationAction(ISD::BlockAddress, MVT::i32, Custom); setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom); setOperationAction(ISD::JumpTable, MVT::i32, Custom); @@ -131,9 +137,30 @@ MipsTargetLowering(MipsTargetMachine &TM) 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::VASTART, MVT::Other, Custom); + setOperationAction(ISD::FCOPYSIGN, MVT::f32, Custom); + setOperationAction(ISD::FCOPYSIGN, MVT::f64, Custom); + setOperationAction(ISD::MEMBARRIER, MVT::Other, Custom); + setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom); + + if (!TM.Options.NoNaNsFPMath) { + setOperationAction(ISD::FABS, MVT::f32, Custom); + setOperationAction(ISD::FABS, MVT::f64, Custom); + } + + if (HasMips64) { + setOperationAction(ISD::GlobalAddress, MVT::i64, Custom); + setOperationAction(ISD::BlockAddress, MVT::i64, Custom); + setOperationAction(ISD::GlobalTLSAddress, MVT::i64, Custom); + setOperationAction(ISD::JumpTable, MVT::i64, Custom); + setOperationAction(ISD::ConstantPool, MVT::i64, Custom); + setOperationAction(ISD::SELECT, MVT::i64, Custom); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Custom); + } setOperationAction(ISD::SDIV, MVT::i32, Expand); setOperationAction(ISD::SREM, MVT::i32, Expand); @@ -149,10 +176,18 @@ MipsTargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::BR_CC, MVT::Other, Expand); setOperationAction(ISD::SELECT_CC, MVT::Other, Expand); setOperationAction(ISD::UINT_TO_FP, MVT::i32, Expand); + setOperationAction(ISD::UINT_TO_FP, MVT::i64, Expand); setOperationAction(ISD::FP_TO_UINT, MVT::i32, Expand); + setOperationAction(ISD::FP_TO_UINT, MVT::i64, Expand); setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); setOperationAction(ISD::CTPOP, MVT::i32, Expand); + setOperationAction(ISD::CTPOP, MVT::i64, Expand); setOperationAction(ISD::CTTZ, MVT::i32, Expand); + setOperationAction(ISD::CTTZ, MVT::i64, Expand); + setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i32, Expand); + setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i64, Expand); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i32, Expand); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i64, Expand); setOperationAction(ISD::ROTL, MVT::i32, Expand); setOperationAction(ISD::ROTL, MVT::i64, Expand); @@ -165,8 +200,6 @@ MipsTargetLowering(MipsTargetMachine &TM) 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, Custom); - setOperationAction(ISD::FCOPYSIGN, MVT::f64, Custom); setOperationAction(ISD::FSIN, MVT::f32, Expand); setOperationAction(ISD::FSIN, MVT::f64, Expand); setOperationAction(ISD::FCOS, MVT::f32, Expand); @@ -180,9 +213,18 @@ MipsTargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::FEXP, MVT::f32, Expand); setOperationAction(ISD::FMA, MVT::f32, Expand); setOperationAction(ISD::FMA, MVT::f64, Expand); + setOperationAction(ISD::FREM, MVT::f32, Expand); + setOperationAction(ISD::FREM, MVT::f64, Expand); + + if (!TM.Options.NoNaNsFPMath) { + setOperationAction(ISD::FNEG, MVT::f32, Expand); + setOperationAction(ISD::FNEG, MVT::f64, Expand); + } setOperationAction(ISD::EXCEPTIONADDR, MVT::i32, Expand); + setOperationAction(ISD::EXCEPTIONADDR, MVT::i64, Expand); setOperationAction(ISD::EHSELECTION, MVT::i32, Expand); + setOperationAction(ISD::EHSELECTION, MVT::i64, Expand); setOperationAction(ISD::VAARG, MVT::Other, Expand); setOperationAction(ISD::VACOPY, MVT::Other, Expand); @@ -192,11 +234,10 @@ MipsTargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); - setOperationAction(ISD::MEMBARRIER, MVT::Other, Custom); - setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom); - - setOperationAction(ISD::ATOMIC_LOAD, MVT::i32, Expand); - setOperationAction(ISD::ATOMIC_STORE, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD, MVT::i64, Expand); + setOperationAction(ISD::ATOMIC_STORE, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_STORE, MVT::i64, Expand); setInsertFencesForAtomic(true); @@ -208,32 +249,46 @@ MipsTargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand); } - if (!Subtarget->hasBitCount()) + if (!Subtarget->hasBitCount()) { setOperationAction(ISD::CTLZ, MVT::i32, Expand); + setOperationAction(ISD::CTLZ, MVT::i64, Expand); + } - if (!Subtarget->hasSwap()) + if (!Subtarget->hasSwap()) { setOperationAction(ISD::BSWAP, MVT::i32, Expand); + setOperationAction(ISD::BSWAP, MVT::i64, Expand); + } setTargetDAGCombine(ISD::ADDE); setTargetDAGCombine(ISD::SUBE); setTargetDAGCombine(ISD::SDIVREM); setTargetDAGCombine(ISD::UDIVREM); - setTargetDAGCombine(ISD::SETCC); + setTargetDAGCombine(ISD::SELECT); setTargetDAGCombine(ISD::AND); setTargetDAGCombine(ISD::OR); - setMinFunctionAlignment(2); + setMinFunctionAlignment(HasMips64 ? 3 : 2); - setStackPointerRegisterToSaveRestore(Mips::SP); + setStackPointerRegisterToSaveRestore(IsN64 ? Mips::SP_64 : Mips::SP); computeRegisterProperties(); - setExceptionPointerRegister(Mips::A0); - setExceptionSelectorRegister(Mips::A1); + setExceptionPointerRegister(IsN64 ? Mips::A0_64 : Mips::A0); + setExceptionSelectorRegister(IsN64 ? Mips::A1_64 : Mips::A1); } bool MipsTargetLowering::allowsUnalignedMemoryAccesses(EVT VT) const { MVT::SimpleValueType SVT = VT.getSimpleVT().SimpleTy; - return SVT == MVT::i64 || SVT == MVT::i32 || SVT == MVT::i16; + + switch (SVT) { + case MVT::i64: + case MVT::i32: + case MVT::i16: + return true; + case MVT::f32: + return Subtarget->hasMips32r2Or64(); + default: + return false; + } } EVT MipsTargetLowering::getSetCCResultType(EVT VT) const { @@ -290,8 +345,7 @@ static bool SelectMadd(SDNode* ADDENode, SelectionDAG* CurDAG) { // create MipsMAdd(u) node MultOpc = MultOpc == ISD::UMUL_LOHI ? MipsISD::MAddu : MipsISD::MAdd; - SDValue MAdd = CurDAG->getNode(MultOpc, dl, - MVT::Glue, + SDValue MAdd = CurDAG->getNode(MultOpc, dl, MVT::Glue, MultNode->getOperand(0),// Factor 0 MultNode->getOperand(1),// Factor 1 ADDCNode->getOperand(1),// Lo0 @@ -364,8 +418,7 @@ static bool SelectMsub(SDNode* SUBENode, SelectionDAG* CurDAG) { // create MipsSub(u) node MultOpc = MultOpc == ISD::UMUL_LOHI ? MipsISD::MSubu : MipsISD::MSub; - SDValue MSub = CurDAG->getNode(MultOpc, dl, - MVT::Glue, + SDValue MSub = CurDAG->getNode(MultOpc, dl, MVT::Glue, MultNode->getOperand(0),// Factor 0 MultNode->getOperand(1),// Factor 1 SUBCNode->getOperand(0),// Lo0 @@ -394,7 +447,8 @@ static SDValue PerformADDECombine(SDNode *N, SelectionDAG& DAG, if (DCI.isBeforeLegalize()) return SDValue(); - if (Subtarget->hasMips32() && SelectMadd(N, &DAG)) + if (Subtarget->hasMips32() && N->getValueType(0) == MVT::i32 && + SelectMadd(N, &DAG)) return SDValue(N, 0); return SDValue(); @@ -406,7 +460,8 @@ static SDValue PerformSUBECombine(SDNode *N, SelectionDAG& DAG, if (DCI.isBeforeLegalize()) return SDValue(); - if (Subtarget->hasMips32() && SelectMsub(N, &DAG)) + if (Subtarget->hasMips32() && N->getValueType(0) == MVT::i32 && + SelectMsub(N, &DAG)) return SDValue(N, 0); return SDValue(); @@ -419,8 +474,8 @@ static SDValue PerformDivRemCombine(SDNode *N, SelectionDAG& DAG, return SDValue(); EVT Ty = N->getValueType(0); - unsigned LO = (Ty == MVT::i32) ? Mips::LO : Mips::LO64; - unsigned HI = (Ty == MVT::i32) ? Mips::HI : Mips::HI64; + unsigned LO = (Ty == MVT::i32) ? Mips::LO : Mips::LO64; + unsigned HI = (Ty == MVT::i32) ? Mips::HI : Mips::HI64; unsigned opc = N->getOpcode() == ISD::SDIVREM ? MipsISD::DivRem : MipsISD::DivRemU; DebugLoc dl = N->getDebugLoc(); @@ -481,11 +536,10 @@ static bool InvertFPCondCode(Mips::CondCode CC) { if (CC >= Mips::FCOND_F && CC <= Mips::FCOND_NGT) return false; - if (CC >= Mips::FCOND_T && CC <= Mips::FCOND_GT) - return true; + assert((CC >= Mips::FCOND_T && CC <= Mips::FCOND_GT) && + "Illegal Condition Code"); - assert(false && "Illegal Condition Code"); - return false; + return true; } // Creates and returns an FPCmp node from a setcc node. @@ -522,21 +576,37 @@ static SDValue CreateCMovFP(SelectionDAG& DAG, SDValue Cond, SDValue True, True.getValueType(), True, False, Cond); } -static SDValue PerformSETCCCombine(SDNode *N, SelectionDAG& DAG, - TargetLowering::DAGCombinerInfo &DCI, - const MipsSubtarget* Subtarget) { +static SDValue PerformSELECTCombine(SDNode *N, SelectionDAG& DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget* Subtarget) { if (DCI.isBeforeLegalizeOps()) return SDValue(); - SDValue Cond = CreateFPCmp(DAG, SDValue(N, 0)); + SDValue SetCC = N->getOperand(0); - if (Cond.getOpcode() != MipsISD::FPCmp) + if ((SetCC.getOpcode() != ISD::SETCC) || + !SetCC.getOperand(0).getValueType().isInteger()) return SDValue(); - SDValue True = DAG.getConstant(1, MVT::i32); - SDValue False = DAG.getConstant(0, MVT::i32); + SDValue False = N->getOperand(2); + EVT FalseTy = False.getValueType(); + + if (!FalseTy.isInteger()) + return SDValue(); + + ConstantSDNode *CN = dyn_cast<ConstantSDNode>(False); + + if (!CN || CN->getZExtValue()) + return SDValue(); - return CreateCMovFP(DAG, Cond, True, False, N->getDebugLoc()); + const DebugLoc DL = N->getDebugLoc(); + ISD::CondCode CC = cast<CondCodeSDNode>(SetCC.getOperand(2))->get(); + SDValue True = N->getOperand(1); + + SetCC = DAG.getSetCC(DL, SetCC.getValueType(), SetCC.getOperand(0), + SetCC.getOperand(1), ISD::getSetCCInverse(CC, true)); + + return DAG.getNode(ISD::SELECT, DL, FalseTy, SetCC, False, True); } static SDValue PerformANDCombine(SDNode *N, SelectionDAG& DAG, @@ -549,20 +619,20 @@ static SDValue PerformANDCombine(SDNode *N, SelectionDAG& DAG, return SDValue(); SDValue ShiftRight = N->getOperand(0), Mask = N->getOperand(1); - + unsigned ShiftRightOpc = ShiftRight.getOpcode(); + // Op's first operand must be a shift right. - if (ShiftRight.getOpcode() != ISD::SRA && ShiftRight.getOpcode() != ISD::SRL) + if (ShiftRightOpc != ISD::SRA && ShiftRightOpc != ISD::SRL) return SDValue(); // The second operand of the shift must be an immediate. - uint64_t Pos; ConstantSDNode *CN; if (!(CN = dyn_cast<ConstantSDNode>(ShiftRight.getOperand(1)))) return SDValue(); - - Pos = CN->getZExtValue(); + uint64_t Pos = CN->getZExtValue(); uint64_t SMPos, SMSize; + // Op's second operand must be a shifted mask. if (!(CN = dyn_cast<ConstantSDNode>(Mask)) || !IsShiftedMask(CN->getZExtValue(), SMPos, SMSize)) @@ -570,21 +640,21 @@ static SDValue PerformANDCombine(SDNode *N, SelectionDAG& DAG, // Return if the shifted mask does not start at bit 0 or the sum of its size // and Pos exceeds the word's size. - if (SMPos != 0 || Pos + SMSize > 32) + EVT ValTy = N->getValueType(0); + if (SMPos != 0 || Pos + SMSize > ValTy.getSizeInBits()) return SDValue(); - return DAG.getNode(MipsISD::Ext, N->getDebugLoc(), MVT::i32, - ShiftRight.getOperand(0), - DAG.getConstant(Pos, MVT::i32), + return DAG.getNode(MipsISD::Ext, N->getDebugLoc(), ValTy, + ShiftRight.getOperand(0), DAG.getConstant(Pos, MVT::i32), DAG.getConstant(SMSize, MVT::i32)); } - + static SDValue PerformORCombine(SDNode *N, SelectionDAG& DAG, TargetLowering::DAGCombinerInfo &DCI, const MipsSubtarget* Subtarget) { // Pattern match INS. // $dst = or (and $src1 , mask0), (and (shl $src, pos), mask1), - // where mask1 = (2**size - 1) << pos, mask0 = ~mask1 + // where mask1 = (2**size - 1) << pos, mask0 = ~mask1 // => ins $dst, $src, size, pos, $src1 if (DCI.isBeforeLegalizeOps() || !Subtarget->hasMips32r2()) return SDValue(); @@ -604,7 +674,7 @@ static SDValue PerformORCombine(SDNode *N, SelectionDAG& DAG, // See if Op's second operand matches (and (shl $src, pos), mask1). if (And1.getOpcode() != ISD::AND) return SDValue(); - + if (!(CN = dyn_cast<ConstantSDNode>(And1.getOperand(1))) || !IsShiftedMask(CN->getZExtValue(), SMPos1, SMSize1)) return SDValue(); @@ -623,17 +693,16 @@ static SDValue PerformORCombine(SDNode *N, SelectionDAG& DAG, unsigned Shamt = CN->getZExtValue(); // Return if the shift amount and the first bit position of mask are not the - // same. - if (Shamt != SMPos0) + // same. + EVT ValTy = N->getValueType(0); + if ((Shamt != SMPos0) || (SMPos0 + SMSize0 > ValTy.getSizeInBits())) return SDValue(); - - return DAG.getNode(MipsISD::Ins, N->getDebugLoc(), MVT::i32, - Shl.getOperand(0), + + return DAG.getNode(MipsISD::Ins, N->getDebugLoc(), ValTy, Shl.getOperand(0), DAG.getConstant(SMPos0, MVT::i32), - DAG.getConstant(SMSize0, MVT::i32), - And0.getOperand(0)); + DAG.getConstant(SMSize0, MVT::i32), And0.getOperand(0)); } - + SDValue MipsTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const { SelectionDAG &DAG = DCI.DAG; @@ -648,8 +717,8 @@ SDValue MipsTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) case ISD::SDIVREM: case ISD::UDIVREM: return PerformDivRemCombine(N, DAG, DCI, Subtarget); - case ISD::SETCC: - return PerformSETCCCombine(N, DAG, DCI, Subtarget); + case ISD::SELECT: + return PerformSELECTCombine(N, DAG, DCI, Subtarget); case ISD::AND: return PerformANDCombine(N, DAG, DCI, Subtarget); case ISD::OR: @@ -672,8 +741,10 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG); case ISD::JumpTable: return LowerJumpTable(Op, DAG); case ISD::SELECT: return LowerSELECT(Op, DAG); + case ISD::SETCC: return LowerSETCC(Op, DAG); case ISD::VASTART: return LowerVASTART(Op, DAG); case ISD::FCOPYSIGN: return LowerFCOPYSIGN(Op, DAG); + case ISD::FABS: return LowerFABS(Op, DAG); case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG); case ISD::MEMBARRIER: return LowerMEMBARRIER(Op, DAG); case ISD::ATOMIC_FENCE: return LowerATOMIC_FENCE(Op, DAG); @@ -689,7 +760,7 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const // MachineFunction as a live in value. It also creates a corresponding // virtual register for it. static unsigned -AddLiveIn(MachineFunction &MF, unsigned PReg, TargetRegisterClass *RC) +AddLiveIn(MachineFunction &MF, unsigned PReg, const TargetRegisterClass *RC) { assert(RC->contains(PReg) && "Not the correct regclass!"); unsigned VReg = MF.getRegInfo().createVirtualRegister(RC); @@ -702,12 +773,13 @@ 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; + assert((CC >= Mips::FCOND_T && CC <= Mips::FCOND_GT) && + "Invalid CondCode."); - return Mips::BRANCH_INVALID; + return Mips::BRANCH_F; } +/* static MachineBasicBlock* ExpandCondMov(MachineInstr *MI, MachineBasicBlock *BB, DebugLoc dl, const MipsSubtarget* Subtarget, @@ -783,89 +855,115 @@ static MachineBasicBlock* ExpandCondMov(MachineInstr *MI, MachineBasicBlock *BB, MI->eraseFromParent(); // The pseudo instruction is gone now. return BB; } - +*/ MachineBasicBlock * MipsTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *BB) const { - const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); - DebugLoc dl = MI->getDebugLoc(); - switch (MI->getOpcode()) { - default: - assert(false && "Unexpected instr type to insert"); - return NULL; - case Mips::MOVT: - case Mips::MOVT_S: - case Mips::MOVT_D: - return ExpandCondMov(MI, BB, dl, Subtarget, TII, true, Mips::BC1F); - case Mips::MOVF: - case Mips::MOVF_S: - case Mips::MOVF_D: - return ExpandCondMov(MI, BB, dl, Subtarget, TII, true, Mips::BC1T); - case Mips::MOVZ_I: - case Mips::MOVZ_S: - case Mips::MOVZ_D: - return ExpandCondMov(MI, BB, dl, Subtarget, TII, false, Mips::BNE); - case Mips::MOVN_I: - case Mips::MOVN_S: - case Mips::MOVN_D: - return ExpandCondMov(MI, BB, dl, Subtarget, TII, false, Mips::BEQ); - + default: llvm_unreachable("Unexpected instr type to insert"); case Mips::ATOMIC_LOAD_ADD_I8: + case Mips::ATOMIC_LOAD_ADD_I8_P8: return EmitAtomicBinaryPartword(MI, BB, 1, Mips::ADDu); case Mips::ATOMIC_LOAD_ADD_I16: + case Mips::ATOMIC_LOAD_ADD_I16_P8: return EmitAtomicBinaryPartword(MI, BB, 2, Mips::ADDu); case Mips::ATOMIC_LOAD_ADD_I32: + case Mips::ATOMIC_LOAD_ADD_I32_P8: return EmitAtomicBinary(MI, BB, 4, Mips::ADDu); + case Mips::ATOMIC_LOAD_ADD_I64: + case Mips::ATOMIC_LOAD_ADD_I64_P8: + return EmitAtomicBinary(MI, BB, 8, Mips::DADDu); case Mips::ATOMIC_LOAD_AND_I8: + case Mips::ATOMIC_LOAD_AND_I8_P8: return EmitAtomicBinaryPartword(MI, BB, 1, Mips::AND); case Mips::ATOMIC_LOAD_AND_I16: + case Mips::ATOMIC_LOAD_AND_I16_P8: return EmitAtomicBinaryPartword(MI, BB, 2, Mips::AND); case Mips::ATOMIC_LOAD_AND_I32: + case Mips::ATOMIC_LOAD_AND_I32_P8: return EmitAtomicBinary(MI, BB, 4, Mips::AND); + case Mips::ATOMIC_LOAD_AND_I64: + case Mips::ATOMIC_LOAD_AND_I64_P8: + return EmitAtomicBinary(MI, BB, 8, Mips::AND64); case Mips::ATOMIC_LOAD_OR_I8: + case Mips::ATOMIC_LOAD_OR_I8_P8: return EmitAtomicBinaryPartword(MI, BB, 1, Mips::OR); case Mips::ATOMIC_LOAD_OR_I16: + case Mips::ATOMIC_LOAD_OR_I16_P8: return EmitAtomicBinaryPartword(MI, BB, 2, Mips::OR); case Mips::ATOMIC_LOAD_OR_I32: + case Mips::ATOMIC_LOAD_OR_I32_P8: return EmitAtomicBinary(MI, BB, 4, Mips::OR); + case Mips::ATOMIC_LOAD_OR_I64: + case Mips::ATOMIC_LOAD_OR_I64_P8: + return EmitAtomicBinary(MI, BB, 8, Mips::OR64); case Mips::ATOMIC_LOAD_XOR_I8: + case Mips::ATOMIC_LOAD_XOR_I8_P8: return EmitAtomicBinaryPartword(MI, BB, 1, Mips::XOR); case Mips::ATOMIC_LOAD_XOR_I16: + case Mips::ATOMIC_LOAD_XOR_I16_P8: return EmitAtomicBinaryPartword(MI, BB, 2, Mips::XOR); case Mips::ATOMIC_LOAD_XOR_I32: + case Mips::ATOMIC_LOAD_XOR_I32_P8: return EmitAtomicBinary(MI, BB, 4, Mips::XOR); + case Mips::ATOMIC_LOAD_XOR_I64: + case Mips::ATOMIC_LOAD_XOR_I64_P8: + return EmitAtomicBinary(MI, BB, 8, Mips::XOR64); case Mips::ATOMIC_LOAD_NAND_I8: + case Mips::ATOMIC_LOAD_NAND_I8_P8: return EmitAtomicBinaryPartword(MI, BB, 1, 0, true); case Mips::ATOMIC_LOAD_NAND_I16: + case Mips::ATOMIC_LOAD_NAND_I16_P8: return EmitAtomicBinaryPartword(MI, BB, 2, 0, true); case Mips::ATOMIC_LOAD_NAND_I32: + case Mips::ATOMIC_LOAD_NAND_I32_P8: return EmitAtomicBinary(MI, BB, 4, 0, true); + case Mips::ATOMIC_LOAD_NAND_I64: + case Mips::ATOMIC_LOAD_NAND_I64_P8: + return EmitAtomicBinary(MI, BB, 8, 0, true); case Mips::ATOMIC_LOAD_SUB_I8: + case Mips::ATOMIC_LOAD_SUB_I8_P8: return EmitAtomicBinaryPartword(MI, BB, 1, Mips::SUBu); case Mips::ATOMIC_LOAD_SUB_I16: + case Mips::ATOMIC_LOAD_SUB_I16_P8: return EmitAtomicBinaryPartword(MI, BB, 2, Mips::SUBu); case Mips::ATOMIC_LOAD_SUB_I32: + case Mips::ATOMIC_LOAD_SUB_I32_P8: return EmitAtomicBinary(MI, BB, 4, Mips::SUBu); + case Mips::ATOMIC_LOAD_SUB_I64: + case Mips::ATOMIC_LOAD_SUB_I64_P8: + return EmitAtomicBinary(MI, BB, 8, Mips::DSUBu); case Mips::ATOMIC_SWAP_I8: + case Mips::ATOMIC_SWAP_I8_P8: return EmitAtomicBinaryPartword(MI, BB, 1, 0); case Mips::ATOMIC_SWAP_I16: + case Mips::ATOMIC_SWAP_I16_P8: return EmitAtomicBinaryPartword(MI, BB, 2, 0); case Mips::ATOMIC_SWAP_I32: + case Mips::ATOMIC_SWAP_I32_P8: return EmitAtomicBinary(MI, BB, 4, 0); + case Mips::ATOMIC_SWAP_I64: + case Mips::ATOMIC_SWAP_I64_P8: + return EmitAtomicBinary(MI, BB, 8, 0); case Mips::ATOMIC_CMP_SWAP_I8: + case Mips::ATOMIC_CMP_SWAP_I8_P8: return EmitAtomicCmpSwapPartword(MI, BB, 1); case Mips::ATOMIC_CMP_SWAP_I16: + case Mips::ATOMIC_CMP_SWAP_I16_P8: return EmitAtomicCmpSwapPartword(MI, BB, 2); case Mips::ATOMIC_CMP_SWAP_I32: + case Mips::ATOMIC_CMP_SWAP_I32_P8: return EmitAtomicCmpSwap(MI, BB, 4); + case Mips::ATOMIC_CMP_SWAP_I64: + case Mips::ATOMIC_CMP_SWAP_I64_P8: + return EmitAtomicCmpSwap(MI, BB, 8); } } @@ -875,13 +973,31 @@ MachineBasicBlock * MipsTargetLowering::EmitAtomicBinary(MachineInstr *MI, MachineBasicBlock *BB, unsigned Size, unsigned BinOpcode, bool Nand) const { - assert(Size == 4 && "Unsupported size for EmitAtomicBinary."); + assert((Size == 4 || Size == 8) && "Unsupported size for EmitAtomicBinary."); MachineFunction *MF = BB->getParent(); MachineRegisterInfo &RegInfo = MF->getRegInfo(); - const TargetRegisterClass *RC = getRegClassFor(MVT::i32); + const TargetRegisterClass *RC = getRegClassFor(MVT::getIntegerVT(Size * 8)); const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); DebugLoc dl = MI->getDebugLoc(); + unsigned LL, SC, AND, NOR, ZERO, BEQ; + + if (Size == 4) { + LL = IsN64 ? Mips::LL_P8 : Mips::LL; + SC = IsN64 ? Mips::SC_P8 : Mips::SC; + AND = Mips::AND; + NOR = Mips::NOR; + ZERO = Mips::ZERO; + BEQ = Mips::BEQ; + } + else { + LL = IsN64 ? Mips::LLD_P8 : Mips::LLD; + SC = IsN64 ? Mips::SCD_P8 : Mips::SCD; + AND = Mips::AND64; + NOR = Mips::NOR64; + ZERO = Mips::ZERO_64; + BEQ = Mips::BEQ64; + } unsigned OldVal = MI->getOperand(0).getReg(); unsigned Ptr = MI->getOperand(1).getReg(); @@ -919,23 +1035,20 @@ MipsTargetLowering::EmitAtomicBinary(MachineInstr *MI, MachineBasicBlock *BB, // sc success, storeval, 0(ptr) // beq success, $0, loopMBB BB = loopMBB; - BuildMI(BB, dl, TII->get(Mips::LL), OldVal).addReg(Ptr).addImm(0); + BuildMI(BB, dl, TII->get(LL), OldVal).addReg(Ptr).addImm(0); if (Nand) { // and andres, oldval, incr // nor storeval, $0, andres - BuildMI(BB, dl, TII->get(Mips::AND), AndRes).addReg(OldVal).addReg(Incr); - BuildMI(BB, dl, TII->get(Mips::NOR), StoreVal) - .addReg(Mips::ZERO).addReg(AndRes); + BuildMI(BB, dl, TII->get(AND), AndRes).addReg(OldVal).addReg(Incr); + BuildMI(BB, dl, TII->get(NOR), StoreVal).addReg(ZERO).addReg(AndRes); } else if (BinOpcode) { // <binop> storeval, oldval, incr BuildMI(BB, dl, TII->get(BinOpcode), StoreVal).addReg(OldVal).addReg(Incr); } else { StoreVal = Incr; } - BuildMI(BB, dl, TII->get(Mips::SC), Success) - .addReg(StoreVal).addReg(Ptr).addImm(0); - BuildMI(BB, dl, TII->get(Mips::BEQ)) - .addReg(Success).addReg(Mips::ZERO).addMBB(loopMBB); + BuildMI(BB, dl, TII->get(SC), Success).addReg(StoreVal).addReg(Ptr).addImm(0); + BuildMI(BB, dl, TII->get(BEQ)).addReg(Success).addReg(ZERO).addMBB(loopMBB); MI->eraseFromParent(); // The instruction is gone now. @@ -955,6 +1068,8 @@ MipsTargetLowering::EmitAtomicBinaryPartword(MachineInstr *MI, const TargetRegisterClass *RC = getRegClassFor(MVT::i32); const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); DebugLoc dl = MI->getDebugLoc(); + unsigned LL = IsN64 ? Mips::LL_P8 : Mips::LL; + unsigned SC = IsN64 ? Mips::SC_P8 : Mips::SC; unsigned Dest = MI->getOperand(0).getReg(); unsigned Ptr = MI->getOperand(1).getReg(); @@ -992,8 +1107,7 @@ MipsTargetLowering::EmitAtomicBinaryPartword(MachineInstr *MI, // Transfer the remainder of BB and its successor edges to exitMBB. exitMBB->splice(exitMBB->begin(), BB, - llvm::next(MachineBasicBlock::iterator(MI)), - BB->end()); + llvm::next(MachineBasicBlock::iterator(MI)), BB->end()); exitMBB->transferSuccessorsAndUpdatePHIs(BB); BB->addSuccessor(loopMBB); @@ -1025,7 +1139,6 @@ MipsTargetLowering::EmitAtomicBinaryPartword(MachineInstr *MI, BuildMI(BB, dl, TII->get(Mips::NOR), Mask2).addReg(Mips::ZERO).addReg(Mask); BuildMI(BB, dl, TII->get(Mips::SLLV), Incr2).addReg(ShiftAmt).addReg(Incr); - // atomic.load.binop // loopMBB: // ll oldval,0(alignedaddr) @@ -1046,7 +1159,7 @@ MipsTargetLowering::EmitAtomicBinaryPartword(MachineInstr *MI, // beq success,$0,loopMBB BB = loopMBB; - BuildMI(BB, dl, TII->get(Mips::LL), OldVal).addReg(AlignedAddr).addImm(0); + BuildMI(BB, dl, TII->get(LL), OldVal).addReg(AlignedAddr).addImm(0); if (Nand) { // and andres, oldval, incr2 // nor binopres, $0, andres @@ -1064,12 +1177,12 @@ MipsTargetLowering::EmitAtomicBinaryPartword(MachineInstr *MI, // and newval, incr2, mask BuildMI(BB, dl, TII->get(Mips::AND), NewVal).addReg(Incr2).addReg(Mask); } - + BuildMI(BB, dl, TII->get(Mips::AND), MaskedOldVal0) .addReg(OldVal).addReg(Mask2); BuildMI(BB, dl, TII->get(Mips::OR), StoreVal) .addReg(MaskedOldVal0).addReg(NewVal); - BuildMI(BB, dl, TII->get(Mips::SC), Success) + BuildMI(BB, dl, TII->get(SC), Success) .addReg(StoreVal).addReg(AlignedAddr).addImm(0); BuildMI(BB, dl, TII->get(Mips::BEQ)) .addReg(Success).addReg(Mips::ZERO).addMBB(loopMBB); @@ -1100,13 +1213,29 @@ MachineBasicBlock * MipsTargetLowering::EmitAtomicCmpSwap(MachineInstr *MI, MachineBasicBlock *BB, unsigned Size) const { - assert(Size == 4 && "Unsupported size for EmitAtomicCmpSwap."); + assert((Size == 4 || Size == 8) && "Unsupported size for EmitAtomicCmpSwap."); MachineFunction *MF = BB->getParent(); MachineRegisterInfo &RegInfo = MF->getRegInfo(); - const TargetRegisterClass *RC = getRegClassFor(MVT::i32); + const TargetRegisterClass *RC = getRegClassFor(MVT::getIntegerVT(Size * 8)); const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); DebugLoc dl = MI->getDebugLoc(); + unsigned LL, SC, ZERO, BNE, BEQ; + + if (Size == 4) { + LL = IsN64 ? Mips::LL_P8 : Mips::LL; + SC = IsN64 ? Mips::SC_P8 : Mips::SC; + ZERO = Mips::ZERO; + BNE = Mips::BNE; + BEQ = Mips::BEQ; + } + else { + LL = IsN64 ? Mips::LLD_P8 : Mips::LLD; + SC = IsN64 ? Mips::SCD_P8 : Mips::SCD; + ZERO = Mips::ZERO_64; + BNE = Mips::BNE64; + BEQ = Mips::BEQ64; + } unsigned Dest = MI->getOperand(0).getReg(); unsigned Ptr = MI->getOperand(1).getReg(); @@ -1128,8 +1257,7 @@ MipsTargetLowering::EmitAtomicCmpSwap(MachineInstr *MI, // Transfer the remainder of BB and its successor edges to exitMBB. exitMBB->splice(exitMBB->begin(), BB, - llvm::next(MachineBasicBlock::iterator(MI)), - BB->end()); + llvm::next(MachineBasicBlock::iterator(MI)), BB->end()); exitMBB->transferSuccessorsAndUpdatePHIs(BB); // thisMBB: @@ -1145,18 +1273,18 @@ MipsTargetLowering::EmitAtomicCmpSwap(MachineInstr *MI, // ll dest, 0(ptr) // bne dest, oldval, exitMBB BB = loop1MBB; - BuildMI(BB, dl, TII->get(Mips::LL), Dest).addReg(Ptr).addImm(0); - BuildMI(BB, dl, TII->get(Mips::BNE)) + BuildMI(BB, dl, TII->get(LL), Dest).addReg(Ptr).addImm(0); + BuildMI(BB, dl, TII->get(BNE)) .addReg(Dest).addReg(OldVal).addMBB(exitMBB); // loop2MBB: // sc success, newval, 0(ptr) // beq success, $0, loop1MBB BB = loop2MBB; - BuildMI(BB, dl, TII->get(Mips::SC), Success) + BuildMI(BB, dl, TII->get(SC), Success) .addReg(NewVal).addReg(Ptr).addImm(0); - BuildMI(BB, dl, TII->get(Mips::BEQ)) - .addReg(Success).addReg(Mips::ZERO).addMBB(loop1MBB); + BuildMI(BB, dl, TII->get(BEQ)) + .addReg(Success).addReg(ZERO).addMBB(loop1MBB); MI->eraseFromParent(); // The instruction is gone now. @@ -1175,6 +1303,8 @@ MipsTargetLowering::EmitAtomicCmpSwapPartword(MachineInstr *MI, const TargetRegisterClass *RC = getRegClassFor(MVT::i32); const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); DebugLoc dl = MI->getDebugLoc(); + unsigned LL = IsN64 ? Mips::LL_P8 : Mips::LL; + unsigned SC = IsN64 ? Mips::SC_P8 : Mips::SC; unsigned Dest = MI->getOperand(0).getReg(); unsigned Ptr = MI->getOperand(1).getReg(); @@ -1215,8 +1345,7 @@ MipsTargetLowering::EmitAtomicCmpSwapPartword(MachineInstr *MI, // Transfer the remainder of BB and its successor edges to exitMBB. exitMBB->splice(exitMBB->begin(), BB, - llvm::next(MachineBasicBlock::iterator(MI)), - BB->end()); + llvm::next(MachineBasicBlock::iterator(MI)), BB->end()); exitMBB->transferSuccessorsAndUpdatePHIs(BB); BB->addSuccessor(loop1MBB); @@ -1265,7 +1394,7 @@ MipsTargetLowering::EmitAtomicCmpSwapPartword(MachineInstr *MI, // and maskedoldval0,oldval,mask // bne maskedoldval0,shiftedcmpval,sinkMBB BB = loop1MBB; - BuildMI(BB, dl, TII->get(Mips::LL), OldVal).addReg(AlignedAddr).addImm(0); + BuildMI(BB, dl, TII->get(LL), OldVal).addReg(AlignedAddr).addImm(0); BuildMI(BB, dl, TII->get(Mips::AND), MaskedOldVal0) .addReg(OldVal).addReg(Mask); BuildMI(BB, dl, TII->get(Mips::BNE)) @@ -1281,7 +1410,7 @@ MipsTargetLowering::EmitAtomicCmpSwapPartword(MachineInstr *MI, .addReg(OldVal).addReg(Mask2); BuildMI(BB, dl, TII->get(Mips::OR), StoreVal) .addReg(MaskedOldVal1).addReg(ShiftedNewVal); - BuildMI(BB, dl, TII->get(Mips::SC), Success) + BuildMI(BB, dl, TII->get(SC), Success) .addReg(StoreVal).addReg(AlignedAddr).addImm(0); BuildMI(BB, dl, TII->get(Mips::BEQ)) .addReg(Success).addReg(Mips::ZERO).addMBB(loop1MBB); @@ -1313,6 +1442,7 @@ LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const { MachineFunction &MF = DAG.getMachineFunction(); MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + unsigned SP = IsN64 ? Mips::SP_64 : Mips::SP; assert(getTargetMachine().getFrameLowering()->getStackAlignment() >= cast<ConstantSDNode>(Op.getOperand(2).getNode())->getZExtValue() && @@ -1324,20 +1454,19 @@ LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const DebugLoc dl = Op.getDebugLoc(); // Get a reference from Mips stack pointer - SDValue StackPointer = DAG.getCopyFromReg(Chain, dl, Mips::SP, MVT::i32); + SDValue StackPointer = DAG.getCopyFromReg(Chain, dl, SP, getPointerTy()); // 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); + SDValue Sub = DAG.getNode(ISD::SUB, dl, getPointerTy(), 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, - SDValue()); + Chain = DAG.getCopyToReg(StackPointer.getValue(1), dl, SP, Sub, SDValue()); // This node always has two return values: a new stack pointer // value and a chain - SDVTList VTLs = DAG.getVTList(MVT::i32, MVT::Other); + SDVTList VTLs = DAG.getVTList(getPointerTy(), MVT::Other); SDValue Ptr = DAG.getFrameIndex(MipsFI->getDynAllocFI(), getPointerTy()); SDValue Ops[] = { Chain, Ptr, Chain.getValue(1) }; @@ -1381,11 +1510,23 @@ LowerSELECT(SDValue Op, SelectionDAG &DAG) const Op.getDebugLoc()); } +SDValue MipsTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const { + SDValue Cond = CreateFPCmp(DAG, Op); + + assert(Cond.getOpcode() == MipsISD::FPCmp && + "Floating point operand expected."); + + SDValue True = DAG.getConstant(1, MVT::i32); + SDValue False = DAG.getConstant(0, MVT::i32); + + return CreateCMovFP(DAG, Cond, True, False, Op.getDebugLoc()); +} + 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(); + const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal(); if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !IsN64) { SDVTList VTs = DAG.getVTList(MVT::i32); @@ -1413,21 +1554,20 @@ SDValue MipsTargetLowering::LowerGlobalAddress(SDValue Op, EVT ValTy = Op.getValueType(); bool HasGotOfst = (GV->hasInternalLinkage() || (GV->hasLocalLinkage() && !isa<Function>(GV))); - unsigned GotFlag = IsN64 ? + unsigned GotFlag = HasMips64 ? (HasGotOfst ? MipsII::MO_GOT_PAGE : MipsII::MO_GOT_DISP) : - MipsII::MO_GOT; + (HasGotOfst ? MipsII::MO_GOT : MipsII::MO_GOT16); SDValue GA = DAG.getTargetGlobalAddress(GV, dl, ValTy, 0, GotFlag); - GA = DAG.getNode(MipsISD::WrapperPIC, dl, ValTy, GA); - SDValue ResNode = DAG.getLoad(ValTy, dl, - DAG.getEntryNode(), GA, MachinePointerInfo(), - false, false, 0); + GA = DAG.getNode(MipsISD::Wrapper, dl, ValTy, GetGlobalReg(DAG, ValTy), GA); + SDValue ResNode = DAG.getLoad(ValTy, dl, DAG.getEntryNode(), GA, + MachinePointerInfo(), false, false, false, 0); // On functions and global targets not internal linked only // a load from got/GP is necessary for PIC to work. if (!HasGotOfst) return ResNode; SDValue GALo = DAG.getTargetGlobalAddress(GV, dl, ValTy, 0, - IsN64 ? MipsII::MO_GOT_OFST : - MipsII::MO_ABS_LO); + HasMips64 ? MipsII::MO_GOT_OFST : + MipsII::MO_ABS_LO); SDValue Lo = DAG.getNode(MipsISD::Lo, dl, ValTy, GALo); return DAG.getNode(ISD::ADD, dl, ValTy, ResNode, Lo); } @@ -1438,35 +1578,34 @@ SDValue MipsTargetLowering::LowerBlockAddress(SDValue Op, // FIXME there isn't actually debug info here DebugLoc dl = Op.getDebugLoc(); - if (getTargetMachine().getRelocationModel() != Reloc::PIC_) { + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !IsN64) { // %hi/%lo relocation - SDValue BAHi = DAG.getBlockAddress(BA, MVT::i32, true, - MipsII::MO_ABS_HI); - SDValue BALo = DAG.getBlockAddress(BA, MVT::i32, true, - MipsII::MO_ABS_LO); + SDValue BAHi = DAG.getBlockAddress(BA, MVT::i32, true, MipsII::MO_ABS_HI); + SDValue BALo = DAG.getBlockAddress(BA, MVT::i32, true, MipsII::MO_ABS_LO); SDValue Hi = DAG.getNode(MipsISD::Hi, dl, MVT::i32, BAHi); SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, BALo); return DAG.getNode(ISD::ADD, dl, MVT::i32, Hi, Lo); } - SDValue BAGOTOffset = DAG.getBlockAddress(BA, MVT::i32, true, - MipsII::MO_GOT); - BAGOTOffset = DAG.getNode(MipsISD::WrapperPIC, dl, MVT::i32, BAGOTOffset); - SDValue BALOOffset = DAG.getBlockAddress(BA, MVT::i32, true, - MipsII::MO_ABS_LO); - SDValue Load = DAG.getLoad(MVT::i32, dl, - DAG.getEntryNode(), BAGOTOffset, - MachinePointerInfo(), false, false, 0); - SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, BALOOffset); - return DAG.getNode(ISD::ADD, dl, MVT::i32, Load, Lo); + EVT ValTy = Op.getValueType(); + unsigned GOTFlag = HasMips64 ? MipsII::MO_GOT_PAGE : MipsII::MO_GOT; + unsigned OFSTFlag = HasMips64 ? MipsII::MO_GOT_OFST : MipsII::MO_ABS_LO; + SDValue BAGOTOffset = DAG.getBlockAddress(BA, ValTy, true, GOTFlag); + BAGOTOffset = DAG.getNode(MipsISD::Wrapper, dl, ValTy, + GetGlobalReg(DAG, ValTy), BAGOTOffset); + SDValue BALOOffset = DAG.getBlockAddress(BA, ValTy, true, OFSTFlag); + SDValue Load = DAG.getLoad(ValTy, dl, DAG.getEntryNode(), BAGOTOffset, + MachinePointerInfo(), false, false, false, 0); + SDValue Lo = DAG.getNode(MipsISD::Lo, dl, ValTy, BALOOffset); + return DAG.getNode(ISD::ADD, dl, ValTy, Load, Lo); } SDValue MipsTargetLowering:: LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const { - // If the relocation model is PIC, use the General Dynamic TLS Model, - // otherwise use the Initial Exec or Local Exec TLS Model. - // TODO: implement Local Dynamic TLS model + // If the relocation model is PIC, use the General Dynamic TLS Model or + // Local Dynamic TLS model, otherwise use the Initial Exec or + // Local Exec TLS Model. GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op); DebugLoc dl = GA->getDebugLoc(); @@ -1475,45 +1614,63 @@ LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const if (getTargetMachine().getRelocationModel() == Reloc::PIC_) { // General Dynamic TLS Model - SDValue TGA = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, - 0, MipsII::MO_TLSGD); - SDValue Tlsgd = DAG.getNode(MipsISD::TlsGd, dl, MVT::i32, TGA); - SDValue GP = DAG.getRegister(Mips::GP, MVT::i32); - SDValue Argument = DAG.getNode(ISD::ADD, dl, MVT::i32, GP, Tlsgd); + bool LocalDynamic = GV->hasInternalLinkage(); + unsigned Flag = LocalDynamic ? MipsII::MO_TLSLDM :MipsII::MO_TLSGD; + SDValue TGA = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, Flag); + SDValue Argument = DAG.getNode(MipsISD::Wrapper, dl, PtrVT, + GetGlobalReg(DAG, PtrVT), TGA); + unsigned PtrSize = PtrVT.getSizeInBits(); + IntegerType *PtrTy = Type::getIntNTy(*DAG.getContext(), PtrSize); + + SDValue TlsGetAddr = DAG.getExternalSymbol("__tls_get_addr", PtrVT); ArgListTy Args; ArgListEntry Entry; Entry.Node = Argument; - Entry.Ty = (Type *) Type::getInt32Ty(*DAG.getContext()); + Entry.Ty = PtrTy; Args.push_back(Entry); - std::pair<SDValue, SDValue> CallResult = - LowerCallTo(DAG.getEntryNode(), - (Type *) Type::getInt32Ty(*DAG.getContext()), - false, false, false, false, 0, CallingConv::C, false, true, - DAG.getExternalSymbol("__tls_get_addr", PtrVT), Args, DAG, - dl); - return CallResult.first; + std::pair<SDValue, SDValue> CallResult = + LowerCallTo(DAG.getEntryNode(), PtrTy, + false, false, false, false, 0, CallingConv::C, + /*isTailCall=*/false, /*doesNotRet=*/false, + /*isReturnValueUsed=*/true, + TlsGetAddr, Args, DAG, dl); + + SDValue Ret = CallResult.first; + + if (!LocalDynamic) + return Ret; + + SDValue TGAHi = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, + MipsII::MO_DTPREL_HI); + SDValue Hi = DAG.getNode(MipsISD::Hi, dl, PtrVT, TGAHi); + SDValue TGALo = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, + MipsII::MO_DTPREL_LO); + SDValue Lo = DAG.getNode(MipsISD::Lo, dl, PtrVT, TGALo); + SDValue Add = DAG.getNode(ISD::ADD, dl, PtrVT, Hi, Ret); + return DAG.getNode(ISD::ADD, dl, PtrVT, Add, Lo); } SDValue Offset; if (GV->isDeclaration()) { // Initial Exec TLS Model - SDValue TGA = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, 0, + SDValue TGA = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, MipsII::MO_GOTTPREL); - Offset = DAG.getLoad(MVT::i32, dl, + TGA = DAG.getNode(MipsISD::Wrapper, dl, PtrVT, GetGlobalReg(DAG, PtrVT), + TGA); + Offset = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), TGA, MachinePointerInfo(), - false, false, 0); + false, false, false, 0); } else { // Local Exec TLS Model - SDVTList VTs = DAG.getVTList(MVT::i32); - SDValue TGAHi = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, 0, + SDValue TGAHi = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, MipsII::MO_TPREL_HI); - SDValue TGALo = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, 0, + SDValue TGALo = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, MipsII::MO_TPREL_LO); - SDValue Hi = DAG.getNode(MipsISD::TprelHi, dl, VTs, &TGAHi, 1); - SDValue Lo = DAG.getNode(MipsISD::TprelLo, dl, MVT::i32, TGALo); - Offset = DAG.getNode(ISD::ADD, dl, MVT::i32, Hi, Lo); + SDValue Hi = DAG.getNode(MipsISD::Hi, dl, PtrVT, TGAHi); + SDValue Lo = DAG.getNode(MipsISD::Lo, dl, PtrVT, TGALo); + Offset = DAG.getNode(ISD::ADD, dl, PtrVT, Hi, Lo); } SDValue ThreadPointer = DAG.getNode(MipsISD::ThreadPointer, dl, PtrVT); @@ -1523,34 +1680,30 @@ LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const SDValue MipsTargetLowering:: LowerJumpTable(SDValue Op, SelectionDAG &DAG) const { - SDValue ResNode; - SDValue HiPart; + SDValue HiPart, JTI, JTILo; // 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_HI; - EVT PtrVT = Op.getValueType(); - JumpTableSDNode *JT = cast<JumpTableSDNode>(Op); + 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); + if (!IsPIC && !IsN64) { + JTI = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, MipsII::MO_ABS_HI); + HiPart = DAG.getNode(MipsISD::Hi, dl, PtrVT, JTI); + JTILo = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, MipsII::MO_ABS_LO); } else {// Emit Load from Global Pointer - JTI = DAG.getNode(MipsISD::WrapperPIC, dl, MVT::i32, JTI); - HiPart = DAG.getLoad(MVT::i32, dl, DAG.getEntryNode(), JTI, - MachinePointerInfo(), - false, false, 0); + unsigned GOTFlag = HasMips64 ? MipsII::MO_GOT_PAGE : MipsII::MO_GOT; + unsigned OfstFlag = HasMips64 ? MipsII::MO_GOT_OFST : MipsII::MO_ABS_LO; + JTI = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, GOTFlag); + JTI = DAG.getNode(MipsISD::Wrapper, dl, PtrVT, GetGlobalReg(DAG, PtrVT), + JTI); + HiPart = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), JTI, + MachinePointerInfo(), false, false, false, 0); + JTILo = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, OfstFlag); } - SDValue JTILo = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, - MipsII::MO_ABS_LO); - SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, JTILo); - ResNode = DAG.getNode(ISD::ADD, dl, MVT::i32, HiPart, Lo); - - return ResNode; + SDValue Lo = DAG.getNode(MipsISD::Lo, dl, PtrVT, JTILo); + return DAG.getNode(ISD::ADD, dl, PtrVT, HiPart, Lo); } SDValue MipsTargetLowering:: @@ -1572,7 +1725,7 @@ LowerConstantPool(SDValue Op, SelectionDAG &DAG) const // SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(MVT::i32); // ResNode = DAG.getNode(ISD::ADD, MVT::i32, GOT, GPRelNode); - if (getTargetMachine().getRelocationModel() != Reloc::PIC_) { + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !IsN64) { SDValue CPHi = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment(), N->getOffset(), MipsII::MO_ABS_HI); SDValue CPLo = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment(), @@ -1581,16 +1734,19 @@ LowerConstantPool(SDValue Op, SelectionDAG &DAG) const SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, CPLo); 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); - CP = DAG.getNode(MipsISD::WrapperPIC, dl, MVT::i32, CP); - SDValue Load = DAG.getLoad(MVT::i32, dl, DAG.getEntryNode(), - CP, MachinePointerInfo::getConstantPool(), + EVT ValTy = Op.getValueType(); + unsigned GOTFlag = HasMips64 ? MipsII::MO_GOT_PAGE : MipsII::MO_GOT; + unsigned OFSTFlag = HasMips64 ? MipsII::MO_GOT_OFST : MipsII::MO_ABS_LO; + SDValue CP = DAG.getTargetConstantPool(C, ValTy, N->getAlignment(), + N->getOffset(), GOTFlag); + CP = DAG.getNode(MipsISD::Wrapper, dl, ValTy, GetGlobalReg(DAG, ValTy), CP); + SDValue Load = DAG.getLoad(ValTy, dl, DAG.getEntryNode(), CP, + MachinePointerInfo::getConstantPool(), false, false, false, 0); - SDValue CPLo = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment(), - N->getOffset(), MipsII::MO_ABS_LO); - SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, CPLo); - ResNode = DAG.getNode(ISD::ADD, dl, MVT::i32, Load, Lo); + SDValue CPLo = DAG.getTargetConstantPool(C, ValTy, N->getAlignment(), + N->getOffset(), OFSTFlag); + SDValue Lo = DAG.getNode(MipsISD::Lo, dl, ValTy, CPLo); + ResNode = DAG.getNode(ISD::ADD, dl, ValTy, Load, Lo); } return ResNode; @@ -1608,62 +1764,165 @@ SDValue MipsTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const { // memory location argument. const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); return DAG.getStore(Op.getOperand(0), dl, FI, Op.getOperand(1), - MachinePointerInfo(SV), - false, false, 0); + MachinePointerInfo(SV), false, false, 0); } -static SDValue LowerFCOPYSIGN32(SDValue Op, SelectionDAG &DAG) { - // FIXME: Use ext/ins instructions if target architecture is Mips32r2. - DebugLoc dl = Op.getDebugLoc(); - SDValue Op0 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Op.getOperand(0)); - SDValue Op1 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Op.getOperand(1)); - SDValue And0 = DAG.getNode(ISD::AND, dl, MVT::i32, Op0, - DAG.getConstant(0x7fffffff, MVT::i32)); - SDValue And1 = DAG.getNode(ISD::AND, dl, MVT::i32, Op1, - DAG.getConstant(0x80000000, MVT::i32)); - SDValue Result = DAG.getNode(ISD::OR, dl, MVT::i32, And0, And1); - return DAG.getNode(ISD::BITCAST, dl, MVT::f32, Result); +static SDValue LowerFCOPYSIGN32(SDValue Op, SelectionDAG &DAG, bool HasR2) { + EVT TyX = Op.getOperand(0).getValueType(); + EVT TyY = Op.getOperand(1).getValueType(); + SDValue Const1 = DAG.getConstant(1, MVT::i32); + SDValue Const31 = DAG.getConstant(31, MVT::i32); + DebugLoc DL = Op.getDebugLoc(); + SDValue Res; + + // If operand is of type f64, extract the upper 32-bit. Otherwise, bitcast it + // to i32. + SDValue X = (TyX == MVT::f32) ? + DAG.getNode(ISD::BITCAST, DL, MVT::i32, Op.getOperand(0)) : + DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, Op.getOperand(0), + Const1); + SDValue Y = (TyY == MVT::f32) ? + DAG.getNode(ISD::BITCAST, DL, MVT::i32, Op.getOperand(1)) : + DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, Op.getOperand(1), + Const1); + + if (HasR2) { + // ext E, Y, 31, 1 ; extract bit31 of Y + // ins X, E, 31, 1 ; insert extracted bit at bit31 of X + SDValue E = DAG.getNode(MipsISD::Ext, DL, MVT::i32, Y, Const31, Const1); + Res = DAG.getNode(MipsISD::Ins, DL, MVT::i32, E, Const31, Const1, X); + } else { + // sll SllX, X, 1 + // srl SrlX, SllX, 1 + // srl SrlY, Y, 31 + // sll SllY, SrlX, 31 + // or Or, SrlX, SllY + SDValue SllX = DAG.getNode(ISD::SHL, DL, MVT::i32, X, Const1); + SDValue SrlX = DAG.getNode(ISD::SRL, DL, MVT::i32, SllX, Const1); + SDValue SrlY = DAG.getNode(ISD::SRL, DL, MVT::i32, Y, Const31); + SDValue SllY = DAG.getNode(ISD::SHL, DL, MVT::i32, SrlY, Const31); + Res = DAG.getNode(ISD::OR, DL, MVT::i32, SrlX, SllY); + } + + if (TyX == MVT::f32) + return DAG.getNode(ISD::BITCAST, DL, Op.getOperand(0).getValueType(), Res); + + SDValue LowX = DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, + Op.getOperand(0), DAG.getConstant(0, MVT::i32)); + return DAG.getNode(MipsISD::BuildPairF64, DL, MVT::f64, LowX, Res); } -static SDValue LowerFCOPYSIGN64(SDValue Op, SelectionDAG &DAG, bool isLittle) { - // FIXME: - // Use ext/ins instructions if target architecture is Mips32r2. - // Eliminate redundant mfc1 and mtc1 instructions. - unsigned LoIdx = 0, HiIdx = 1; +static SDValue LowerFCOPYSIGN64(SDValue Op, SelectionDAG &DAG, bool HasR2) { + unsigned WidthX = Op.getOperand(0).getValueSizeInBits(); + unsigned WidthY = Op.getOperand(1).getValueSizeInBits(); + EVT TyX = MVT::getIntegerVT(WidthX), TyY = MVT::getIntegerVT(WidthY); + SDValue Const1 = DAG.getConstant(1, MVT::i32); + DebugLoc DL = Op.getDebugLoc(); + + // Bitcast to integer nodes. + SDValue X = DAG.getNode(ISD::BITCAST, DL, TyX, Op.getOperand(0)); + SDValue Y = DAG.getNode(ISD::BITCAST, DL, TyY, Op.getOperand(1)); + + if (HasR2) { + // ext E, Y, width(Y) - 1, 1 ; extract bit width(Y)-1 of Y + // ins X, E, width(X) - 1, 1 ; insert extracted bit at bit width(X)-1 of X + SDValue E = DAG.getNode(MipsISD::Ext, DL, TyY, Y, + DAG.getConstant(WidthY - 1, MVT::i32), Const1); + + if (WidthX > WidthY) + E = DAG.getNode(ISD::ZERO_EXTEND, DL, TyX, E); + else if (WidthY > WidthX) + E = DAG.getNode(ISD::TRUNCATE, DL, TyX, E); + + SDValue I = DAG.getNode(MipsISD::Ins, DL, TyX, E, + DAG.getConstant(WidthX - 1, MVT::i32), Const1, X); + return DAG.getNode(ISD::BITCAST, DL, Op.getOperand(0).getValueType(), I); + } - if (!isLittle) - std::swap(LoIdx, HiIdx); + // (d)sll SllX, X, 1 + // (d)srl SrlX, SllX, 1 + // (d)srl SrlY, Y, width(Y)-1 + // (d)sll SllY, SrlX, width(Y)-1 + // or Or, SrlX, SllY + SDValue SllX = DAG.getNode(ISD::SHL, DL, TyX, X, Const1); + SDValue SrlX = DAG.getNode(ISD::SRL, DL, TyX, SllX, Const1); + SDValue SrlY = DAG.getNode(ISD::SRL, DL, TyY, Y, + DAG.getConstant(WidthY - 1, MVT::i32)); + + if (WidthX > WidthY) + SrlY = DAG.getNode(ISD::ZERO_EXTEND, DL, TyX, SrlY); + else if (WidthY > WidthX) + SrlY = DAG.getNode(ISD::TRUNCATE, DL, TyX, SrlY); + + SDValue SllY = DAG.getNode(ISD::SHL, DL, TyX, SrlY, + DAG.getConstant(WidthX - 1, MVT::i32)); + SDValue Or = DAG.getNode(ISD::OR, DL, TyX, SrlX, SllY); + return DAG.getNode(ISD::BITCAST, DL, Op.getOperand(0).getValueType(), Or); +} - DebugLoc dl = Op.getDebugLoc(); - SDValue Word0 = DAG.getNode(MipsISD::ExtractElementF64, dl, MVT::i32, - Op.getOperand(0), - DAG.getConstant(LoIdx, MVT::i32)); - SDValue Hi0 = DAG.getNode(MipsISD::ExtractElementF64, dl, MVT::i32, - Op.getOperand(0), DAG.getConstant(HiIdx, MVT::i32)); - SDValue Hi1 = DAG.getNode(MipsISD::ExtractElementF64, dl, MVT::i32, - Op.getOperand(1), DAG.getConstant(HiIdx, MVT::i32)); - SDValue And0 = DAG.getNode(ISD::AND, dl, MVT::i32, Hi0, - DAG.getConstant(0x7fffffff, MVT::i32)); - SDValue And1 = DAG.getNode(ISD::AND, dl, MVT::i32, Hi1, - DAG.getConstant(0x80000000, MVT::i32)); - SDValue Word1 = DAG.getNode(ISD::OR, dl, MVT::i32, And0, And1); - - if (!isLittle) - std::swap(Word0, Word1); - - return DAG.getNode(MipsISD::BuildPairF64, dl, MVT::f64, Word0, Word1); -} - -SDValue MipsTargetLowering::LowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) - const { - EVT Ty = Op.getValueType(); +SDValue +MipsTargetLowering::LowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) const { + if (Subtarget->hasMips64()) + return LowerFCOPYSIGN64(Op, DAG, Subtarget->hasMips32r2()); - assert(Ty == MVT::f32 || Ty == MVT::f64); + return LowerFCOPYSIGN32(Op, DAG, Subtarget->hasMips32r2()); +} - if (Ty == MVT::f32) - return LowerFCOPYSIGN32(Op, DAG); - else - return LowerFCOPYSIGN64(Op, DAG, Subtarget->isLittle()); +static SDValue LowerFABS32(SDValue Op, SelectionDAG &DAG, bool HasR2) { + SDValue Res, Const1 = DAG.getConstant(1, MVT::i32); + DebugLoc DL = Op.getDebugLoc(); + + // If operand is of type f64, extract the upper 32-bit. Otherwise, bitcast it + // to i32. + SDValue X = (Op.getValueType() == MVT::f32) ? + DAG.getNode(ISD::BITCAST, DL, MVT::i32, Op.getOperand(0)) : + DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, Op.getOperand(0), + Const1); + + // Clear MSB. + if (HasR2) + Res = DAG.getNode(MipsISD::Ins, DL, MVT::i32, + DAG.getRegister(Mips::ZERO, MVT::i32), + DAG.getConstant(31, MVT::i32), Const1, X); + else { + SDValue SllX = DAG.getNode(ISD::SHL, DL, MVT::i32, X, Const1); + Res = DAG.getNode(ISD::SRL, DL, MVT::i32, SllX, Const1); + } + + if (Op.getValueType() == MVT::f32) + return DAG.getNode(ISD::BITCAST, DL, MVT::f32, Res); + + SDValue LowX = DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, + Op.getOperand(0), DAG.getConstant(0, MVT::i32)); + return DAG.getNode(MipsISD::BuildPairF64, DL, MVT::f64, LowX, Res); +} + +static SDValue LowerFABS64(SDValue Op, SelectionDAG &DAG, bool HasR2) { + SDValue Res, Const1 = DAG.getConstant(1, MVT::i32); + DebugLoc DL = Op.getDebugLoc(); + + // Bitcast to integer node. + SDValue X = DAG.getNode(ISD::BITCAST, DL, MVT::i64, Op.getOperand(0)); + + // Clear MSB. + if (HasR2) + Res = DAG.getNode(MipsISD::Ins, DL, MVT::i64, + DAG.getRegister(Mips::ZERO_64, MVT::i64), + DAG.getConstant(63, MVT::i32), Const1, X); + else { + SDValue SllX = DAG.getNode(ISD::SHL, DL, MVT::i64, X, Const1); + Res = DAG.getNode(ISD::SRL, DL, MVT::i64, SllX, Const1); + } + + return DAG.getNode(ISD::BITCAST, DL, MVT::f64, Res); +} + +SDValue +MipsTargetLowering::LowerFABS(SDValue Op, SelectionDAG &DAG) const { + if (Subtarget->hasMips64() && (Op.getValueType() == MVT::f64)) + return LowerFABS64(Op, DAG, Subtarget->hasMips32r2()); + + return LowerFABS32(Op, DAG, Subtarget->hasMips32r2()); } SDValue MipsTargetLowering:: @@ -1676,13 +1935,14 @@ LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const { MFI->setFrameAddressIsTaken(true); EVT VT = Op.getValueType(); DebugLoc dl = Op.getDebugLoc(); - SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, Mips::FP, VT); + SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, + IsN64 ? Mips::FP_64 : Mips::FP, VT); return FrameAddr; } // TODO: set SType according to the desired memory barrier behavior. -SDValue MipsTargetLowering::LowerMEMBARRIER(SDValue Op, - SelectionDAG& DAG) const { +SDValue +MipsTargetLowering::LowerMEMBARRIER(SDValue Op, SelectionDAG& DAG) const { unsigned SType = 0; DebugLoc dl = Op.getDebugLoc(); return DAG.getNode(MipsISD::Sync, dl, MVT::Other, Op.getOperand(0), @@ -1703,8 +1963,6 @@ SDValue MipsTargetLowering::LowerATOMIC_FENCE(SDValue Op, // Calling Convention Implementation //===----------------------------------------------------------------------===// -#include "MipsGenCallingConv.inc" - //===----------------------------------------------------------------------===// // TODO: Implement a generic logic using tblgen that can support this. // Mips O32 ABI rules: @@ -1726,13 +1984,13 @@ static bool CC_MipsO32(unsigned ValNo, MVT ValVT, static const unsigned IntRegsSize=4, FloatRegsSize=2; - static const unsigned IntRegs[] = { + static const uint16_t IntRegs[] = { Mips::A0, Mips::A1, Mips::A2, Mips::A3 }; - static const unsigned F32Regs[] = { + static const uint16_t F32Regs[] = { Mips::F12, Mips::F14 }; - static const unsigned F64Regs[] = { + static const uint16_t F64Regs[] = { Mips::D6, Mips::D7 }; @@ -1811,13 +2069,77 @@ static bool CC_MipsO32(unsigned ValNo, MVT ValVT, return false; // CC must always match } +static const uint16_t Mips64IntRegs[8] = + {Mips::A0_64, Mips::A1_64, Mips::A2_64, Mips::A3_64, + Mips::T0_64, Mips::T1_64, Mips::T2_64, Mips::T3_64}; +static const uint16_t Mips64DPRegs[8] = + {Mips::D12_64, Mips::D13_64, Mips::D14_64, Mips::D15_64, + Mips::D16_64, Mips::D17_64, Mips::D18_64, Mips::D19_64}; + +static bool CC_Mips64Byval(unsigned ValNo, MVT ValVT, MVT LocVT, + CCValAssign::LocInfo LocInfo, + ISD::ArgFlagsTy ArgFlags, CCState &State) { + unsigned Align = std::max(ArgFlags.getByValAlign(), (unsigned)8); + unsigned Size = (ArgFlags.getByValSize() + 7) / 8 * 8; + unsigned FirstIdx = State.getFirstUnallocated(Mips64IntRegs, 8); + + assert(Align <= 16 && "Cannot handle alignments larger than 16."); + + // If byval is 16-byte aligned, the first arg register must be even. + if ((Align == 16) && (FirstIdx % 2)) { + State.AllocateReg(Mips64IntRegs[FirstIdx], Mips64DPRegs[FirstIdx]); + ++FirstIdx; + } + + // Mark the registers allocated. + for (unsigned I = FirstIdx; Size && (I < 8); Size -= 8, ++I) + State.AllocateReg(Mips64IntRegs[I], Mips64DPRegs[I]); + + // Allocate space on caller's stack. + unsigned Offset = State.AllocateStack(Size, Align); + + if (FirstIdx < 8) + State.addLoc(CCValAssign::getReg(ValNo, ValVT, Mips64IntRegs[FirstIdx], + LocVT, LocInfo)); + else + State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); + + return true; +} + +#include "MipsGenCallingConv.inc" + +static void +AnalyzeMips64CallOperands(CCState &CCInfo, + const SmallVectorImpl<ISD::OutputArg> &Outs) { + unsigned NumOps = Outs.size(); + for (unsigned i = 0; i != NumOps; ++i) { + MVT ArgVT = Outs[i].VT; + ISD::ArgFlagsTy ArgFlags = Outs[i].Flags; + bool R; + + if (Outs[i].IsFixed) + R = CC_MipsN(i, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, CCInfo); + else + R = CC_MipsN_VarArg(i, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, CCInfo); + + if (R) { +#ifndef NDEBUG + dbgs() << "Call operand #" << i << " has unhandled type " + << EVT(ArgVT).getEVTString(); +#endif + llvm_unreachable(0); + } + } +} + //===----------------------------------------------------------------------===// // Call Calling Convention Implementation //===----------------------------------------------------------------------===// static const unsigned O32IntRegsSize = 4; -static const unsigned O32IntRegs[] = { +static const uint16_t O32IntRegs[] = { Mips::A0, Mips::A1, Mips::A2, Mips::A3 }; @@ -1848,9 +2170,8 @@ WriteByValArg(SDValue& ByValChain, SDValue Chain, DebugLoc dl, SDValue LoadPtr = DAG.getNode(ISD::ADD, dl, MVT::i32, Arg, DAG.getConstant(Offset, MVT::i32)); SDValue LoadVal = DAG.getLoad(MVT::i32, dl, Chain, LoadPtr, - MachinePointerInfo(), - false, false, std::min(ByValAlign, - (unsigned )4)); + MachinePointerInfo(), false, false, false, + std::min(ByValAlign, (unsigned )4)); MemOpChains.push_back(LoadVal.getValue(1)); unsigned DstReg = O32IntRegs[LocMemOffset / 4]; RegsToPass.push_back(std::make_pair(DstReg, LoadVal)); @@ -1886,7 +2207,7 @@ WriteByValArg(SDValue& ByValChain, SDValue Chain, DebugLoc dl, // Read second subword if necessary. if (RemainingSize != 0) { assert(RemainingSize == 1 && "There must be one byte remaining."); - LoadPtr = DAG.getNode(ISD::ADD, dl, MVT::i32, Arg, + LoadPtr = DAG.getNode(ISD::ADD, dl, MVT::i32, Arg, DAG.getConstant(Offset, MVT::i32)); unsigned Alignment = std::min(ByValAlign, (unsigned )2); SDValue Subword = DAG.getExtLoad(ISD::ZEXTLOAD, dl, MVT::i32, Chain, @@ -1919,13 +2240,101 @@ WriteByValArg(SDValue& ByValChain, SDValue Chain, DebugLoc dl, MachinePointerInfo(0), MachinePointerInfo(0)); } +// Copy Mips64 byVal arg to registers and stack. +void static +PassByValArg64(SDValue& ByValChain, SDValue Chain, DebugLoc dl, + SmallVector<std::pair<unsigned, SDValue>, 16>& RegsToPass, + SmallVector<SDValue, 8>& MemOpChains, int& LastFI, + MachineFrameInfo *MFI, SelectionDAG &DAG, SDValue Arg, + const CCValAssign &VA, const ISD::ArgFlagsTy& Flags, + EVT PtrTy, bool isLittle) { + unsigned ByValSize = Flags.getByValSize(); + unsigned Alignment = std::min(Flags.getByValAlign(), (unsigned)8); + bool IsRegLoc = VA.isRegLoc(); + unsigned Offset = 0; // Offset in # of bytes from the beginning of struct. + unsigned LocMemOffset = 0; + unsigned MemCpySize = ByValSize; + + if (!IsRegLoc) + LocMemOffset = VA.getLocMemOffset(); + else { + const uint16_t *Reg = std::find(Mips64IntRegs, Mips64IntRegs + 8, + VA.getLocReg()); + const uint16_t *RegEnd = Mips64IntRegs + 8; + + // Copy double words to registers. + for (; (Reg != RegEnd) && (ByValSize >= Offset + 8); ++Reg, Offset += 8) { + SDValue LoadPtr = DAG.getNode(ISD::ADD, dl, PtrTy, Arg, + DAG.getConstant(Offset, PtrTy)); + SDValue LoadVal = DAG.getLoad(MVT::i64, dl, Chain, LoadPtr, + MachinePointerInfo(), false, false, false, + Alignment); + MemOpChains.push_back(LoadVal.getValue(1)); + RegsToPass.push_back(std::make_pair(*Reg, LoadVal)); + } + + // Return if the struct has been fully copied. + if (!(MemCpySize = ByValSize - Offset)) + return; + + // If there is an argument register available, copy the remainder of the + // byval argument with sub-doubleword loads and shifts. + if (Reg != RegEnd) { + assert((ByValSize < Offset + 8) && + "Size of the remainder should be smaller than 8-byte."); + SDValue Val; + for (unsigned LoadSize = 4; Offset < ByValSize; LoadSize /= 2) { + unsigned RemSize = ByValSize - Offset; + + if (RemSize < LoadSize) + continue; + + SDValue LoadPtr = DAG.getNode(ISD::ADD, dl, PtrTy, Arg, + DAG.getConstant(Offset, PtrTy)); + SDValue LoadVal = + DAG.getExtLoad(ISD::ZEXTLOAD, dl, MVT::i64, Chain, LoadPtr, + MachinePointerInfo(), MVT::getIntegerVT(LoadSize * 8), + false, false, Alignment); + MemOpChains.push_back(LoadVal.getValue(1)); + + // Offset in number of bits from double word boundary. + unsigned OffsetDW = (Offset % 8) * 8; + unsigned Shamt = isLittle ? OffsetDW : 64 - (OffsetDW + LoadSize * 8); + SDValue Shift = DAG.getNode(ISD::SHL, dl, MVT::i64, LoadVal, + DAG.getConstant(Shamt, MVT::i32)); + + Val = Val.getNode() ? DAG.getNode(ISD::OR, dl, MVT::i64, Val, Shift) : + Shift; + Offset += LoadSize; + Alignment = std::min(Alignment, LoadSize); + } + + RegsToPass.push_back(std::make_pair(*Reg, Val)); + return; + } + } + + assert(MemCpySize && "MemCpySize must not be zero."); + + // Create a fixed object on stack at offset LocMemOffset and copy + // remainder of byval arg to it with memcpy. + SDValue Src = DAG.getNode(ISD::ADD, dl, PtrTy, Arg, + DAG.getConstant(Offset, PtrTy)); + LastFI = MFI->CreateFixedObject(MemCpySize, LocMemOffset, true); + SDValue Dst = DAG.getFrameIndex(LastFI, PtrTy); + ByValChain = DAG.getMemcpy(ByValChain, dl, Dst, Src, + DAG.getConstant(MemCpySize, PtrTy), Alignment, + /*isVolatile=*/false, /*AlwaysInline=*/false, + MachinePointerInfo(0), MachinePointerInfo(0)); +} + /// 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 InChain, SDValue Callee, CallingConv::ID CallConv, bool isVarArg, - bool &isTailCall, + bool doesNotRet, bool &isTailCall, const SmallVectorImpl<ISD::OutputArg> &Outs, const SmallVectorImpl<SDValue> &OutVals, const SmallVectorImpl<ISD::InputArg> &Ins, @@ -1943,10 +2352,12 @@ MipsTargetLowering::LowerCall(SDValue InChain, SDValue Callee, // Analyze operands of the call, assigning locations to each operand. SmallVector<CCValAssign, 16> ArgLocs; CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), - getTargetMachine(), ArgLocs, *DAG.getContext()); + getTargetMachine(), ArgLocs, *DAG.getContext()); - if (Subtarget->isABI_O32()) + if (IsO32) CCInfo.AnalyzeCallOperands(Outs, CC_MipsO32); + else if (HasMips64) + AnalyzeMips64CallOperands(CCInfo, Outs); else CCInfo.AnalyzeCallOperands(Outs, CC_Mips); @@ -1963,7 +2374,7 @@ MipsTargetLowering::LowerCall(SDValue InChain, SDValue Callee, // If this is the first call, create a stack frame object that points to // a location to which .cprestore saves $gp. - if (IsPIC && !MipsFI->getGPFI()) + if (IsO32 && IsPIC && MipsFI->globalBaseRegFixed() && !MipsFI->getGPFI()) MipsFI->setGPFI(MFI->CreateFixedObject(4, 0, true)); // Get the frame index of the stack frame object that points to the location @@ -1973,7 +2384,7 @@ MipsTargetLowering::LowerCall(SDValue InChain, SDValue Callee, // Update size of the maximum argument space. // For O32, a minimum of four words (16 bytes) of argument space is // allocated. - if (Subtarget->isABI_O32()) + if (IsO32) NextStackOffset = std::max(NextStackOffset, (unsigned)16); unsigned MaxCallFrameSize = MipsFI->getMaxCallFrameSize(); @@ -1988,7 +2399,7 @@ MipsTargetLowering::LowerCall(SDValue InChain, SDValue Callee, NextStackOffset = (NextStackOffset + StackAlignment - 1) / StackAlignment * StackAlignment; - if (IsPIC) + if (MipsFI->needGPSaveRestore()) MFI->setObjectOffset(MipsFI->getGPFI(), NextStackOffset); MFI->setObjectOffset(DynAllocFI, NextStackOffset); @@ -2004,22 +2415,40 @@ MipsTargetLowering::LowerCall(SDValue InChain, SDValue Callee, for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { SDValue Arg = OutVals[i]; CCValAssign &VA = ArgLocs[i]; + MVT ValVT = VA.getValVT(), LocVT = VA.getLocVT(); + ISD::ArgFlagsTy Flags = Outs[i].Flags; + + // ByVal Arg. + if (Flags.isByVal()) { + assert(Flags.getByValSize() && + "ByVal args of size 0 should have been ignored by front-end."); + if (IsO32) + WriteByValArg(ByValChain, Chain, dl, RegsToPass, MemOpChains, LastFI, + MFI, DAG, Arg, VA, Flags, getPointerTy(), + Subtarget->isLittle()); + else + PassByValArg64(ByValChain, Chain, dl, RegsToPass, MemOpChains, LastFI, + MFI, DAG, Arg, VA, Flags, getPointerTy(), + Subtarget->isLittle()); + continue; + } // 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::BITCAST, dl, MVT::i32, Arg); - if (VA.getValVT() == MVT::f64 && VA.getLocVT() == MVT::i32) { + if (VA.isRegLoc()) { + if ((ValVT == MVT::f32 && LocVT == MVT::i32) || + (ValVT == MVT::f64 && LocVT == MVT::i64)) + Arg = DAG.getNode(ISD::BITCAST, dl, LocVT, Arg); + else if (ValVT == MVT::f64 && LocVT == MVT::i32) { SDValue Lo = DAG.getNode(MipsISD::ExtractElementF64, dl, MVT::i32, Arg, DAG.getConstant(0, MVT::i32)); SDValue Hi = DAG.getNode(MipsISD::ExtractElementF64, dl, MVT::i32, Arg, DAG.getConstant(1, MVT::i32)); if (!Subtarget->isLittle()) std::swap(Lo, Hi); - unsigned LocRegLo = VA.getLocReg(); + unsigned LocRegLo = VA.getLocReg(); unsigned LocRegHigh = getNextIntArgReg(LocRegLo); RegsToPass.push_back(std::make_pair(LocRegLo, Lo)); RegsToPass.push_back(std::make_pair(LocRegHigh, Hi)); @@ -2028,13 +2457,13 @@ MipsTargetLowering::LowerCall(SDValue InChain, SDValue Callee, } break; case CCValAssign::SExt: - Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg); + Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, LocVT, Arg); break; case CCValAssign::ZExt: - Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg); + Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, LocVT, Arg); break; case CCValAssign::AExt: - Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg); + Arg = DAG.getNode(ISD::ANY_EXTEND, dl, LocVT, Arg); break; } @@ -2048,28 +2477,15 @@ MipsTargetLowering::LowerCall(SDValue InChain, SDValue Callee, // Register can't get to this point... assert(VA.isMemLoc()); - // ByVal Arg. - ISD::ArgFlagsTy Flags = Outs[i].Flags; - if (Flags.isByVal()) { - assert(Subtarget->isABI_O32() && - "No support for ByVal args by ABIs other than O32 yet."); - assert(Flags.getByValSize() && - "ByVal args of size 0 should have been ignored by front-end."); - WriteByValArg(ByValChain, Chain, dl, RegsToPass, MemOpChains, LastFI, MFI, - DAG, Arg, VA, Flags, getPointerTy(), Subtarget->isLittle()); - continue; - } - // Create the frame index object for this incoming parameter - LastFI = MFI->CreateFixedObject(VA.getValVT().getSizeInBits()/8, + LastFI = MFI->CreateFixedObject(ValVT.getSizeInBits()/8, VA.getLocMemOffset(), true); SDValue PtrOff = DAG.getFrameIndex(LastFI, getPointerTy()); // emit ISD::STORE whichs stores the // parameter value to a stack Location MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff, - MachinePointerInfo(), - false, false, 0)); + MachinePointerInfo(), false, false, 0)); } // Extend range of indices of frame objects for outgoing arguments that were @@ -2093,52 +2509,68 @@ MipsTargetLowering::LowerCall(SDValue InChain, SDValue Callee, // 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; - bool LoadSymAddr = false; + unsigned char OpFlag; + bool IsPICCall = (IsN64 || IsPIC); // true if calls are translated to jalr $25 + bool GlobalOrExternal = false; SDValue CalleeLo; if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) { - if (IsPIC && G->getGlobal()->hasInternalLinkage()) { - Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, - getPointerTy(), 0,MipsII:: MO_GOT); + if (IsPICCall && G->getGlobal()->hasInternalLinkage()) { + OpFlag = IsO32 ? MipsII::MO_GOT : MipsII::MO_GOT_PAGE; + unsigned char LoFlag = IsO32 ? MipsII::MO_ABS_LO : MipsII::MO_GOT_OFST; + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, getPointerTy(), 0, + OpFlag); CalleeLo = DAG.getTargetGlobalAddress(G->getGlobal(), dl, getPointerTy(), - 0, MipsII::MO_ABS_LO); + 0, LoFlag); } else { + OpFlag = IsPICCall ? MipsII::MO_GOT_CALL : MipsII::MO_NO_FLAG; Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, getPointerTy(), 0, OpFlag); } - LoadSymAddr = true; + GlobalOrExternal = true; } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) { - Callee = DAG.getTargetExternalSymbol(S->getSymbol(), - getPointerTy(), OpFlag); - LoadSymAddr = true; + if (IsN64 || (!IsO32 && IsPIC)) + OpFlag = MipsII::MO_GOT_DISP; + else if (!IsPIC) // !N64 && static + OpFlag = MipsII::MO_NO_FLAG; + else // O32 & PIC + OpFlag = MipsII::MO_GOT_CALL; + Callee = DAG.getTargetExternalSymbol(S->getSymbol(), getPointerTy(), + OpFlag); + GlobalOrExternal = true; } SDValue InFlag; // Create nodes that load address of callee and copy it to T9 - if (IsPIC) { - if (LoadSymAddr) { + if (IsPICCall) { + if (GlobalOrExternal) { // Load callee address - Callee = DAG.getNode(MipsISD::WrapperPIC, dl, MVT::i32, Callee); - SDValue LoadValue = DAG.getLoad(MVT::i32, dl, DAG.getEntryNode(), Callee, - MachinePointerInfo::getGOT(), - false, false, 0); + Callee = DAG.getNode(MipsISD::Wrapper, dl, getPointerTy(), + GetGlobalReg(DAG, getPointerTy()), Callee); + SDValue LoadValue = DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(), + Callee, MachinePointerInfo::getGOT(), + false, false, false, 0); // Use GOT+LO if callee has internal linkage. if (CalleeLo.getNode()) { - SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, CalleeLo); - Callee = DAG.getNode(ISD::ADD, dl, MVT::i32, LoadValue, Lo); + SDValue Lo = DAG.getNode(MipsISD::Lo, dl, getPointerTy(), CalleeLo); + Callee = DAG.getNode(ISD::ADD, dl, getPointerTy(), LoadValue, Lo); } else Callee = LoadValue; } + } + // T9 should contain the address of the callee function if + // -reloction-model=pic or it is an indirect call. + if (IsPICCall || !GlobalOrExternal) { // copy to T9 - Chain = DAG.getCopyToReg(Chain, dl, Mips::T9, Callee, SDValue(0, 0)); + unsigned T9Reg = IsN64 ? Mips::T9_64 : Mips::T9; + Chain = DAG.getCopyToReg(Chain, dl, T9Reg, Callee, SDValue(0, 0)); InFlag = Chain.getValue(1); - Callee = DAG.getRegister(Mips::T9, MVT::i32); + Callee = DAG.getRegister(T9Reg, getPointerTy()); } // Build a sequence of copy-to-reg nodes chained together with token @@ -2166,6 +2598,12 @@ MipsTargetLowering::LowerCall(SDValue InChain, SDValue Callee, Ops.push_back(DAG.getRegister(RegsToPass[i].first, RegsToPass[i].second.getValueType())); + // Add a register mask operand representing the call-preserved registers. + const TargetRegisterInfo *TRI = getTargetMachine().getRegisterInfo(); + const uint32_t *Mask = TRI->getCallPreservedMask(CallConv); + assert(Mask && "Missing call preserved mask for calling convention"); + Ops.push_back(DAG.getRegisterMask(Mask)); + if (InFlag.getNode()) Ops.push_back(InFlag); @@ -2216,7 +2654,8 @@ MipsTargetLowering::LowerCallResult(SDValue Chain, SDValue InFlag, static void ReadByValArg(MachineFunction &MF, SDValue Chain, DebugLoc dl, std::vector<SDValue>& OutChains, SelectionDAG &DAG, unsigned NumWords, SDValue FIN, - const CCValAssign &VA, const ISD::ArgFlagsTy& Flags) { + const CCValAssign &VA, const ISD::ArgFlagsTy& Flags, + const Argument *FuncArg) { unsigned LocMem = VA.getLocMemOffset(); unsigned FirstWord = LocMem / 4; @@ -2231,20 +2670,58 @@ static void ReadByValArg(MachineFunction &MF, SDValue Chain, DebugLoc dl, SDValue StorePtr = DAG.getNode(ISD::ADD, dl, MVT::i32, FIN, DAG.getConstant(i * 4, MVT::i32)); SDValue Store = DAG.getStore(Chain, dl, DAG.getRegister(Reg, MVT::i32), - StorePtr, MachinePointerInfo(), false, - false, 0); + StorePtr, MachinePointerInfo(FuncArg, i * 4), + false, false, 0); OutChains.push_back(Store); } } +// Create frame object on stack and copy registers used for byval passing to it. +static unsigned +CopyMips64ByValRegs(MachineFunction &MF, SDValue Chain, DebugLoc dl, + std::vector<SDValue>& OutChains, SelectionDAG &DAG, + const CCValAssign &VA, const ISD::ArgFlagsTy& Flags, + MachineFrameInfo *MFI, bool IsRegLoc, + SmallVectorImpl<SDValue> &InVals, MipsFunctionInfo *MipsFI, + EVT PtrTy, const Argument *FuncArg) { + const uint16_t *Reg = Mips64IntRegs + 8; + int FOOffset; // Frame object offset from virtual frame pointer. + + if (IsRegLoc) { + Reg = std::find(Mips64IntRegs, Mips64IntRegs + 8, VA.getLocReg()); + FOOffset = (Reg - Mips64IntRegs) * 8 - 8 * 8; + } + else + FOOffset = VA.getLocMemOffset(); + + // Create frame object. + unsigned NumRegs = (Flags.getByValSize() + 7) / 8; + unsigned LastFI = MFI->CreateFixedObject(NumRegs * 8, FOOffset, true); + SDValue FIN = DAG.getFrameIndex(LastFI, PtrTy); + InVals.push_back(FIN); + + // Copy arg registers. + for (unsigned I = 0; (Reg != Mips64IntRegs + 8) && (I < NumRegs); + ++Reg, ++I) { + unsigned VReg = AddLiveIn(MF, *Reg, Mips::CPU64RegsRegisterClass); + SDValue StorePtr = DAG.getNode(ISD::ADD, dl, PtrTy, FIN, + DAG.getConstant(I * 8, PtrTy)); + SDValue Store = DAG.getStore(Chain, dl, DAG.getRegister(VReg, MVT::i64), + StorePtr, MachinePointerInfo(FuncArg, I * 8), + false, false, 0); + OutChains.push_back(Store); + } + + return LastFI; +} + /// 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, + const SmallVectorImpl<ISD::InputArg> &Ins, DebugLoc dl, SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { @@ -2260,23 +2737,46 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain, // Assign locations to all of the incoming arguments. SmallVector<CCValAssign, 16> ArgLocs; CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), - getTargetMachine(), ArgLocs, *DAG.getContext()); + getTargetMachine(), ArgLocs, *DAG.getContext()); - if (Subtarget->isABI_O32()) + if (IsO32) CCInfo.AnalyzeFormalArguments(Ins, CC_MipsO32); else CCInfo.AnalyzeFormalArguments(Ins, CC_Mips); + Function::const_arg_iterator FuncArg = + DAG.getMachineFunction().getFunction()->arg_begin(); int LastFI = 0;// MipsFI->LastInArgFI is 0 at the entry of this function. - for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i, ++FuncArg) { CCValAssign &VA = ArgLocs[i]; + EVT ValVT = VA.getValVT(); + ISD::ArgFlagsTy Flags = Ins[i].Flags; + bool IsRegLoc = VA.isRegLoc(); + + if (Flags.isByVal()) { + assert(Flags.getByValSize() && + "ByVal args of size 0 should have been ignored by front-end."); + if (IsO32) { + unsigned NumWords = (Flags.getByValSize() + 3) / 4; + LastFI = MFI->CreateFixedObject(NumWords * 4, VA.getLocMemOffset(), + true); + SDValue FIN = DAG.getFrameIndex(LastFI, getPointerTy()); + InVals.push_back(FIN); + ReadByValArg(MF, Chain, dl, OutChains, DAG, NumWords, FIN, VA, Flags, + &*FuncArg); + } else // N32/64 + LastFI = CopyMips64ByValRegs(MF, Chain, dl, OutChains, DAG, VA, Flags, + MFI, IsRegLoc, InVals, MipsFI, + getPointerTy(), &*FuncArg); + continue; + } // Arguments stored on registers - if (VA.isRegLoc()) { + if (IsRegLoc) { EVT RegVT = VA.getLocVT(); unsigned ArgReg = VA.getLocReg(); - TargetRegisterClass *RC = 0; + const TargetRegisterClass *RC; if (RegVT == MVT::i32) RC = Mips::CPURegsRegisterClass; @@ -2305,23 +2805,22 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain, 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); + DAG.getValueType(ValVT)); + ArgValue = DAG.getNode(ISD::TRUNCATE, dl, ValVT, 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::BITCAST, dl, MVT::f32, ArgValue); - if (RegVT == MVT::i32 && VA.getValVT() == MVT::f64) { - unsigned Reg2 = AddLiveIn(DAG.getMachineFunction(), - getNextIntArgReg(ArgReg), RC); - SDValue ArgValue2 = DAG.getCopyFromReg(Chain, dl, Reg2, RegVT); - if (!Subtarget->isLittle()) - std::swap(ArgValue, ArgValue2); - ArgValue = DAG.getNode(MipsISD::BuildPairF64, dl, MVT::f64, - ArgValue, ArgValue2); - } + // Handle floating point arguments passed in integer registers. + if ((RegVT == MVT::i32 && ValVT == MVT::f32) || + (RegVT == MVT::i64 && ValVT == MVT::f64)) + ArgValue = DAG.getNode(ISD::BITCAST, dl, ValVT, ArgValue); + else if (IsO32 && RegVT == MVT::i32 && ValVT == MVT::f64) { + unsigned Reg2 = AddLiveIn(DAG.getMachineFunction(), + getNextIntArgReg(ArgReg), RC); + SDValue ArgValue2 = DAG.getCopyFromReg(Chain, dl, Reg2, RegVT); + if (!Subtarget->isLittle()) + std::swap(ArgValue, ArgValue2); + ArgValue = DAG.getNode(MipsISD::BuildPairF64, dl, MVT::f64, + ArgValue, ArgValue2); } InVals.push_back(ArgValue); @@ -2330,32 +2829,15 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain, // sanity check assert(VA.isMemLoc()); - ISD::ArgFlagsTy Flags = Ins[i].Flags; - - if (Flags.isByVal()) { - assert(Subtarget->isABI_O32() && - "No support for ByVal args by ABIs other than O32 yet."); - assert(Flags.getByValSize() && - "ByVal args of size 0 should have been ignored by front-end."); - unsigned NumWords = (Flags.getByValSize() + 3) / 4; - LastFI = MFI->CreateFixedObject(NumWords * 4, VA.getLocMemOffset(), - true); - SDValue FIN = DAG.getFrameIndex(LastFI, getPointerTy()); - InVals.push_back(FIN); - ReadByValArg(MF, Chain, dl, OutChains, DAG, NumWords, FIN, VA, Flags); - - continue; - } - // The stack pointer offset is relative to the caller stack frame. - LastFI = MFI->CreateFixedObject(VA.getValVT().getSizeInBits()/8, + LastFI = MFI->CreateFixedObject(ValVT.getSizeInBits()/8, VA.getLocMemOffset(), true); // Create load nodes to retrieve arguments from the stack SDValue FIN = DAG.getFrameIndex(LastFI, getPointerTy()); - InVals.push_back(DAG.getLoad(VA.getValVT(), dl, Chain, FIN, + InVals.push_back(DAG.getLoad(ValVT, dl, Chain, FIN, MachinePointerInfo::getFixedStack(LastFI), - false, false, 0)); + false, false, false, 0)); } } @@ -2372,28 +2854,43 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain, Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Copy, Chain); } - if (isVarArg && Subtarget->isABI_O32()) { + if (isVarArg) { + unsigned NumOfRegs = IsO32 ? 4 : 8; + const uint16_t *ArgRegs = IsO32 ? O32IntRegs : Mips64IntRegs; + unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs, NumOfRegs); + int FirstRegSlotOffset = IsO32 ? 0 : -64 ; // offset of $a0's slot. + const TargetRegisterClass *RC + = IsO32 ? Mips::CPURegsRegisterClass : Mips::CPU64RegsRegisterClass; + unsigned RegSize = RC->getSize(); + int RegSlotOffset = FirstRegSlotOffset + Idx * RegSize; + + // Offset of the first variable argument from stack pointer. + int FirstVaArgOffset; + + if (IsO32 || (Idx == NumOfRegs)) { + FirstVaArgOffset = + (CCInfo.getNextStackOffset() + RegSize - 1) / RegSize * RegSize; + } else + FirstVaArgOffset = RegSlotOffset; + // Record the frame index of the first variable argument // which is a value necessary to VASTART. - unsigned NextStackOffset = CCInfo.getNextStackOffset(); - assert(NextStackOffset % 4 == 0 && - "NextStackOffset must be aligned to 4-byte boundaries."); - LastFI = MFI->CreateFixedObject(4, NextStackOffset, true); + LastFI = MFI->CreateFixedObject(RegSize, FirstVaArgOffset, true); MipsFI->setVarArgsFrameIndex(LastFI); - // If NextStackOffset is smaller than o32's 16-byte reserved argument area, - // copy the integer registers that have not been used for argument passing - // to the caller's stack frame. - for (; NextStackOffset < 16; NextStackOffset += 4) { - TargetRegisterClass *RC = Mips::CPURegsRegisterClass; - unsigned Idx = NextStackOffset / 4; - unsigned Reg = AddLiveIn(DAG.getMachineFunction(), O32IntRegs[Idx], RC); - SDValue ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, MVT::i32); - LastFI = MFI->CreateFixedObject(4, NextStackOffset, true); + // Copy the integer registers that have not been used for argument passing + // to the argument register save area. For O32, the save area is allocated + // in the caller's stack frame, while for N32/64, it is allocated in the + // callee's stack frame. + for (int StackOffset = RegSlotOffset; + Idx < NumOfRegs; ++Idx, StackOffset += RegSize) { + unsigned Reg = AddLiveIn(DAG.getMachineFunction(), ArgRegs[Idx], RC); + SDValue ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, + MVT::getIntegerVT(RegSize * 8)); + LastFI = MFI->CreateFixedObject(RegSize, StackOffset, true); SDValue PtrOff = DAG.getFrameIndex(LastFI, getPointerTy()); OutChains.push_back(DAG.getStore(Chain, dl, ArgValue, PtrOff, - MachinePointerInfo(), - false, false, 0)); + MachinePointerInfo(), false, false, 0)); } } @@ -2447,8 +2944,7 @@ MipsTargetLowering::LowerReturn(SDValue Chain, CCValAssign &VA = RVLocs[i]; assert(VA.isRegLoc() && "Can only return in registers!"); - Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), - OutVals[i], Flag); + Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), OutVals[i], Flag); // guarantee that all emitted copies are // stuck together, avoiding something bad @@ -2505,7 +3001,6 @@ getConstraintType(const std::string &Constraint) const case 'y': case 'f': return C_RegisterClass; - break; } } return TargetLowering::getConstraintType(Constraint); @@ -2553,14 +3048,19 @@ getRegForInlineAsmConstraint(const std::string &Constraint, EVT VT) const case 'd': // Address register. Same as 'r' unless generating MIPS16 code. case 'y': // Same as 'r'. Exists for compatibility. case 'r': - return std::make_pair(0U, Mips::CPURegsRegisterClass); + if (VT == MVT::i32) + return std::make_pair(0U, Mips::CPURegsRegisterClass); + assert(VT == MVT::i64 && "Unexpected type."); + return std::make_pair(0U, Mips::CPU64RegsRegisterClass); case 'f': if (VT == MVT::f32) return std::make_pair(0U, Mips::FGR32RegisterClass); - if (VT == MVT::f64) - if ((!Subtarget->isSingleFloat()) && (!Subtarget->isFP64bit())) + if ((VT == MVT::f64) && (!Subtarget->isSingleFloat())) { + if (Subtarget->isFP64bit()) + return std::make_pair(0U, Mips::FGR64RegisterClass); + else return std::make_pair(0U, Mips::AFGR64RegisterClass); - break; + } } } return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT); @@ -2579,3 +3079,10 @@ bool MipsTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const { return false; return Imm.isZero(); } + +unsigned MipsTargetLowering::getJumpTableEncoding() const { + if (IsN64) + return MachineJumpTableInfo::EK_GPRel64BlockAddress; + + return TargetLowering::getJumpTableEncoding(); +} diff --git a/lib/Target/Mips/MipsISelLowering.h b/lib/Target/Mips/MipsISelLowering.h index 4be3fed59fc0..c36f40f639f3 100644 --- a/lib/Target/Mips/MipsISelLowering.h +++ b/lib/Target/Mips/MipsISelLowering.h @@ -15,10 +15,10 @@ #ifndef MipsISELLOWERING_H #define MipsISELLOWERING_H -#include "llvm/CodeGen/SelectionDAG.h" -#include "llvm/Target/TargetLowering.h" #include "Mips.h" #include "MipsSubtarget.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/Target/TargetLowering.h" namespace llvm { namespace MipsISD { @@ -40,13 +40,6 @@ namespace llvm { // Handle gp_rel (small data/bss sections) relocation. GPRel, - // General Dynamic TLS - TlsGd, - - // Local Exec TLS - TprelHi, - TprelLo, - // Thread Pointer ThreadPointer, @@ -79,7 +72,7 @@ namespace llvm { BuildPairF64, ExtractElementF64, - WrapperPIC, + Wrapper, DynAlloc, @@ -98,6 +91,8 @@ namespace llvm { public: explicit MipsTargetLowering(MipsTargetMachine &TM); + virtual MVT getShiftAmountTy(EVT LHSTy) const { return MVT::i32; } + virtual bool allowsUnalignedMemoryAccesses (EVT VT) const; /// LowerOperation - Provide custom lowering hooks for some operations. @@ -114,8 +109,8 @@ namespace llvm { private: // Subtarget Info const MipsSubtarget *Subtarget; - - bool HasMips64, IsN64; + + bool HasMips64, IsN64, IsO32; // Lower Operand helpers SDValue LowerCallResult(SDValue Chain, SDValue InFlag, @@ -133,8 +128,10 @@ namespace llvm { 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; SDValue LowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerFABS(SDValue Op, SelectionDAG &DAG) const; SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; SDValue LowerMEMBARRIER(SDValue Op, SelectionDAG& DAG) const; SDValue LowerATOMIC_FENCE(SDValue Op, SelectionDAG& DAG) const; @@ -149,7 +146,7 @@ namespace llvm { virtual SDValue LowerCall(SDValue Chain, SDValue Callee, CallingConv::ID CallConv, bool isVarArg, - bool &isTailCall, + bool doesNotRet, bool &isTailCall, const SmallVectorImpl<ISD::OutputArg> &Outs, const SmallVectorImpl<SDValue> &OutVals, const SmallVectorImpl<ISD::InputArg> &Ins, @@ -186,6 +183,8 @@ namespace llvm { /// materialize the FP immediate as a load from a constant pool. virtual bool isFPImmLegal(const APFloat &Imm, EVT VT) const; + virtual unsigned getJumpTableEncoding() const; + MachineBasicBlock *EmitAtomicBinary(MachineInstr *MI, MachineBasicBlock *BB, unsigned Size, unsigned BinOpcode, bool Nand = false) const; MachineBasicBlock *EmitAtomicBinaryPartword(MachineInstr *MI, diff --git a/lib/Target/Mips/MipsInstrFPU.td b/lib/Target/Mips/MipsInstrFPU.td index 1fb779d6bec1..b6559452fecf 100644 --- a/lib/Target/Mips/MipsInstrFPU.td +++ b/lib/Target/Mips/MipsInstrFPU.td @@ -1,4 +1,4 @@ -//===- MipsInstrFPU.td - Mips FPU Instruction Information --*- tablegen -*-===// +//===-- MipsInstrFPU.td - Mips FPU Instruction Information -*- tablegen -*-===// // // The LLVM Compiler Infrastructure // @@ -59,6 +59,15 @@ def NotFP64bit : Predicate<"!Subtarget.isFP64bit()">; def IsSingleFloat : Predicate<"Subtarget.isSingleFloat()">; def IsNotSingleFloat : Predicate<"!Subtarget.isSingleFloat()">; +// FP immediate patterns. +def fpimm0 : PatLeaf<(fpimm), [{ + return N->isExactlyValue(+0.0); +}]>; + +def fpimm0neg : PatLeaf<(fpimm), [{ + return N->isExactlyValue(-0.0); +}]>; + //===----------------------------------------------------------------------===// // Instruction Class Templates // @@ -74,19 +83,35 @@ def IsNotSingleFloat : Predicate<"!Subtarget.isSingleFloat()">; //===----------------------------------------------------------------------===// // FP load. -class FPLoad<bits<6> op, string opstr, PatFrag FOp, RegisterClass RC, - Operand MemOpnd>: +class FPLoad<bits<6> op, string opstr, RegisterClass RC, Operand MemOpnd>: FMem<op, (outs RC:$ft), (ins MemOpnd:$addr), - !strconcat(opstr, "\t$ft, $addr"), [(set RC:$ft, (FOp addr:$addr))], + !strconcat(opstr, "\t$ft, $addr"), [(set RC:$ft, (load_a addr:$addr))], IILoad>; // FP store. -class FPStore<bits<6> op, string opstr, PatFrag FOp, RegisterClass RC, - Operand MemOpnd>: +class FPStore<bits<6> op, string opstr, RegisterClass RC, Operand MemOpnd>: FMem<op, (outs), (ins RC:$ft, MemOpnd:$addr), - !strconcat(opstr, "\t$ft, $addr"), [(store RC:$ft, addr:$addr)], + !strconcat(opstr, "\t$ft, $addr"), [(store_a RC:$ft, addr:$addr)], IIStore>; +// FP indexed load. +class FPIdxLoad<bits<6> funct, string opstr, RegisterClass DRC, + RegisterClass PRC, PatFrag FOp>: + FFMemIdx<funct, (outs DRC:$fd), (ins PRC:$base, PRC:$index), + !strconcat(opstr, "\t$fd, $index($base)"), + [(set DRC:$fd, (FOp (add PRC:$base, PRC:$index)))]> { + let fs = 0; +} + +// FP indexed store. +class FPIdxStore<bits<6> funct, string opstr, RegisterClass DRC, + RegisterClass PRC, PatFrag FOp>: + FFMemIdx<funct, (outs), (ins DRC:$fs, PRC:$base, PRC:$index), + !strconcat(opstr, "\t$fs, $index($base)"), + [(FOp DRC:$fs, (add PRC:$base, PRC:$index))]> { + let fd = 0; +} + // Instructions that convert an FP value to 32-bit fixed point. multiclass FFR1_W_M<bits<6> funct, string opstr> { def _S : FFR1<funct, 16, opstr, "w.s", FGR32, FGR32>; @@ -122,6 +147,19 @@ multiclass FFR2P_M<bits<6> funct, string opstr, SDNode OpNode, bit isComm = 0> { } } +// FP madd/msub/nmadd/nmsub instruction classes. +class FMADDSUB<bits<3> funct, bits<3> fmt, string opstr, string fmtstr, + SDNode OpNode, RegisterClass RC> : + FFMADDSUB<funct, fmt, (outs RC:$fd), (ins RC:$fr, RC:$fs, RC:$ft), + !strconcat(opstr, ".", fmtstr, "\t$fd, $fr, $fs, $ft"), + [(set RC:$fd, (OpNode (fmul RC:$fs, RC:$ft), RC:$fr))]>; + +class FNMADDSUB<bits<3> funct, bits<3> fmt, string opstr, string fmtstr, + SDNode OpNode, RegisterClass RC> : + FFMADDSUB<funct, fmt, (outs RC:$fd), (ins RC:$fr, RC:$fs, RC:$ft), + !strconcat(opstr, ".", fmtstr, "\t$fd, $fr, $fs, $ft"), + [(set RC:$fd, (fsub fpimm0, (OpNode (fmul RC:$fs, RC:$ft), RC:$fr)))]>; + //===----------------------------------------------------------------------===// // Floating Point Instructions //===----------------------------------------------------------------------===// @@ -152,8 +190,10 @@ let Predicates = [IsFP64bit] in { def CVT_D64_L : FFR1<0x21, 21, "cvt", "d.l", FGR64, FGR64>; } -defm FABS : FFR1P_M<0x5, "abs", fabs>; -defm FNEG : FFR1P_M<0x7, "neg", fneg>; +let Predicates = [NoNaNsFPMath] in { + defm FABS : FFR1P_M<0x5, "abs", fabs>; + defm FNEG : FFR1P_M<0x7, "neg", fneg>; +} defm FSQRT : FFR1P_M<0x4, "sqrt", fsqrt>; // The odd-numbered registers are only referenced when doing loads, @@ -183,6 +223,14 @@ def MTC1 : FFRGPR<0x04, (outs FGR32:$fs), (ins CPURegs:$rt), "mtc1\t$rt, $fs", [(set FGR32:$fs, (bitconvert CPURegs:$rt))]>; +def DMFC1 : FFRGPR<0x01, (outs CPU64Regs:$rt), (ins FGR64:$fs), + "dmfc1\t$rt, $fs", + [(set CPU64Regs:$rt, (bitconvert FGR64:$fs))]>; + +def DMTC1 : FFRGPR<0x05, (outs FGR64:$fs), (ins CPU64Regs:$rt), + "dmtc1\t$rt, $fs", + [(set FGR64:$fs, (bitconvert CPU64Regs:$rt))]>; + def FMOV_S : FFR1<0x6, 16, "mov", "s", FGR32, FGR32>; def FMOV_D32 : FFR1<0x6, 17, "mov", "d", AFGR64, AFGR64>, Requires<[NotFP64bit]>; @@ -191,23 +239,53 @@ def FMOV_D64 : FFR1<0x6, 17, "mov", "d", FGR64, FGR64>, /// Floating Point Memory Instructions let Predicates = [IsN64] in { - def LWC1_P8 : FPLoad<0x31, "lwc1", load, FGR32, mem64>; - def SWC1_P8 : FPStore<0x39, "swc1", store, FGR32, mem64>; - def LDC164_P8 : FPLoad<0x35, "ldc1", load, FGR64, mem64>; - def SDC164_P8 : FPStore<0x3d, "sdc1", store, FGR64, mem64>; + def LWC1_P8 : FPLoad<0x31, "lwc1", FGR32, mem64>; + def SWC1_P8 : FPStore<0x39, "swc1", FGR32, mem64>; + def LDC164_P8 : FPLoad<0x35, "ldc1", FGR64, mem64>; + def SDC164_P8 : FPStore<0x3d, "sdc1", FGR64, mem64>; } let Predicates = [NotN64] in { - def LWC1 : FPLoad<0x31, "lwc1", load, FGR32, mem>; - def SWC1 : FPStore<0x39, "swc1", store, FGR32, mem>; - let Predicates = [HasMips64] in { - def LDC164 : FPLoad<0x35, "ldc1", load, FGR64, mem>; - def SDC164 : FPStore<0x3d, "sdc1", store, FGR64, mem>; - } - let Predicates = [NotMips64] in { - def LDC1 : FPLoad<0x35, "ldc1", load, AFGR64, mem>; - def SDC1 : FPStore<0x3d, "sdc1", store, AFGR64, mem>; - } + def LWC1 : FPLoad<0x31, "lwc1", FGR32, mem>; + def SWC1 : FPStore<0x39, "swc1", FGR32, mem>; +} + +let Predicates = [NotN64, HasMips64] in { + def LDC164 : FPLoad<0x35, "ldc1", FGR64, mem>; + def SDC164 : FPStore<0x3d, "sdc1", FGR64, mem>; +} + +let Predicates = [NotN64, NotMips64] in { + def LDC1 : FPLoad<0x35, "ldc1", AFGR64, mem>; + def SDC1 : FPStore<0x3d, "sdc1", AFGR64, mem>; +} + +// Indexed loads and stores. +let Predicates = [HasMips32r2Or64] in { + def LWXC1 : FPIdxLoad<0x0, "lwxc1", FGR32, CPURegs, load_a>; + def LUXC1 : FPIdxLoad<0x5, "luxc1", FGR32, CPURegs, load_u>; + def SWXC1 : FPIdxStore<0x8, "swxc1", FGR32, CPURegs, store_a>; + def SUXC1 : FPIdxStore<0xd, "suxc1", FGR32, CPURegs, store_u>; +} + +let Predicates = [HasMips32r2, NotMips64] in { + def LDXC1 : FPIdxLoad<0x1, "ldxc1", AFGR64, CPURegs, load_a>; + def SDXC1 : FPIdxStore<0x9, "sdxc1", AFGR64, CPURegs, store_a>; +} + +let Predicates = [HasMips64, NotN64] in { + def LDXC164 : FPIdxLoad<0x1, "ldxc1", FGR64, CPURegs, load_a>; + def SDXC164 : FPIdxStore<0x9, "sdxc1", FGR64, CPURegs, store_a>; +} + +// n64 +let Predicates = [IsN64] in { + def LWXC1_P8 : FPIdxLoad<0x0, "lwxc1", FGR32, CPU64Regs, load_a>; + def LUXC1_P8 : FPIdxLoad<0x5, "luxc1", FGR32, CPU64Regs, load_u>; + def LDXC164_P8 : FPIdxLoad<0x1, "ldxc1", FGR64, CPU64Regs, load_a>; + def SWXC1_P8 : FPIdxStore<0x8, "swxc1", FGR32, CPU64Regs, store_a>; + def SUXC1_P8 : FPIdxStore<0xd, "suxc1", FGR32, CPU64Regs, store_u>; + def SDXC164_P8 : FPIdxStore<0x9, "sdxc1", FGR64, CPU64Regs, store_a>; } /// Floating-point Aritmetic @@ -216,6 +294,36 @@ defm FDIV : FFR2P_M<0x03, "div", fdiv>; defm FMUL : FFR2P_M<0x02, "mul", fmul, 1>; defm FSUB : FFR2P_M<0x01, "sub", fsub>; +let Predicates = [HasMips32r2] in { + def MADD_S : FMADDSUB<0x4, 0, "madd", "s", fadd, FGR32>; + def MSUB_S : FMADDSUB<0x5, 0, "msub", "s", fsub, FGR32>; +} + +let Predicates = [HasMips32r2, NoNaNsFPMath] in { + def NMADD_S : FNMADDSUB<0x6, 0, "nmadd", "s", fadd, FGR32>; + def NMSUB_S : FNMADDSUB<0x7, 0, "nmsub", "s", fsub, FGR32>; +} + +let Predicates = [HasMips32r2, NotFP64bit] in { + def MADD_D32 : FMADDSUB<0x4, 1, "madd", "d", fadd, AFGR64>; + def MSUB_D32 : FMADDSUB<0x5, 1, "msub", "d", fsub, AFGR64>; +} + +let Predicates = [HasMips32r2, NotFP64bit, NoNaNsFPMath] in { + def NMADD_D32 : FNMADDSUB<0x6, 1, "nmadd", "d", fadd, AFGR64>; + def NMSUB_D32 : FNMADDSUB<0x7, 1, "nmsub", "d", fsub, AFGR64>; +} + +let Predicates = [HasMips32r2, IsFP64bit] in { + def MADD_D64 : FMADDSUB<0x4, 1, "madd", "d", fadd, FGR64>; + def MSUB_D64 : FMADDSUB<0x5, 1, "msub", "d", fsub, FGR64>; +} + +let Predicates = [HasMips32r2, IsFP64bit, NoNaNsFPMath] in { + def NMADD_D64 : FNMADDSUB<0x6, 1, "nmadd", "d", fadd, FGR64>; + def NMSUB_D64 : FNMADDSUB<0x7, 1, "nmsub", "d", fsub, FGR64>; +} + //===----------------------------------------------------------------------===// // Floating Point Branch Codes //===----------------------------------------------------------------------===// @@ -259,71 +367,16 @@ def MIPS_FCOND_NGE : PatLeaf<(i32 13)>; def MIPS_FCOND_LE : PatLeaf<(i32 14)>; def MIPS_FCOND_NGT : PatLeaf<(i32 15)>; +class FCMP<bits<5> fmt, RegisterClass RC, string typestr> : + FCC<fmt, (outs), (ins RC:$fs, RC:$ft, condcode:$cc), + !strconcat("c.$cc.", typestr, "\t$fs, $ft"), + [(MipsFPCmp RC:$fs, RC:$ft, imm:$cc)]>; + /// Floating Point Compare let Defs=[FCR31] in { - def FCMP_S32 : FCC<0x10, (outs), (ins FGR32:$fs, FGR32:$ft, condcode:$cc), - "c.$cc.s\t$fs, $ft", - [(MipsFPCmp FGR32:$fs, FGR32:$ft, imm:$cc)]>; - - def FCMP_D32 : FCC<0x11, (outs), (ins AFGR64:$fs, AFGR64:$ft, condcode:$cc), - "c.$cc.d\t$fs, $ft", - [(MipsFPCmp AFGR64:$fs, AFGR64:$ft, imm:$cc)]>, - Requires<[NotFP64bit]>; -} - - -// Conditional moves: -// These instructions are expanded in -// MipsISelLowering::EmitInstrWithCustomInserter if target does not have -// conditional move instructions. -// flag:int, data:float -let usesCustomInserter = 1, Constraints = "$F = $dst" in -class CondMovIntFP<RegisterClass RC, bits<5> fmt, bits<6> func, - string instr_asm> : - FFR<0x11, func, fmt, (outs RC:$dst), (ins RC:$T, CPURegs:$cond, RC:$F), - !strconcat(instr_asm, "\t$dst, $T, $cond"), []>; - -def MOVZ_S : CondMovIntFP<FGR32, 16, 18, "movz.s">; -def MOVN_S : CondMovIntFP<FGR32, 16, 19, "movn.s">; - -let Predicates = [NotFP64bit] in { - def MOVZ_D : CondMovIntFP<AFGR64, 17, 18, "movz.d">; - def MOVN_D : CondMovIntFP<AFGR64, 17, 19, "movn.d">; -} - -defm : MovzPats<FGR32, MOVZ_S>; -defm : MovnPats<FGR32, MOVN_S>; - -let Predicates = [NotFP64bit] in { - defm : MovzPats<AFGR64, MOVZ_D>; - defm : MovnPats<AFGR64, MOVN_D>; -} - -let cc = 0, usesCustomInserter = 1, Uses = [FCR31], - Constraints = "$F = $dst" in { -// flag:float, data:int -class CondMovFPInt<SDNode cmov, bits<1> tf, string instr_asm> : - FCMOV<tf, (outs CPURegs:$dst), (ins CPURegs:$T, CPURegs:$F), - !strconcat(instr_asm, "\t$dst, $T, $$fcc0"), - [(set CPURegs:$dst, (cmov CPURegs:$T, CPURegs:$F))]>; - -// flag:float, data:float -let cc = 0 in -class CondMovFPFP<RegisterClass RC, SDNode cmov, bits<5> fmt, bits<1> tf, - string instr_asm> : - FFCMOV<fmt, tf, (outs RC:$dst), (ins RC:$T, RC:$F), - !strconcat(instr_asm, "\t$dst, $T, $$fcc0"), - [(set RC:$dst, (cmov RC:$T, RC:$F))]>; -} - -def MOVT : CondMovFPInt<MipsCMovFP_T, 1, "movt">; -def MOVF : CondMovFPInt<MipsCMovFP_F, 0, "movf">; -def MOVT_S : CondMovFPFP<FGR32, MipsCMovFP_T, 16, 1, "movt.s">; -def MOVF_S : CondMovFPFP<FGR32, MipsCMovFP_F, 16, 0, "movf.s">; - -let Predicates = [NotFP64bit] in { - def MOVT_D : CondMovFPFP<AFGR64, MipsCMovFP_T, 17, 1, "movt.d">; - def MOVF_D : CondMovFPFP<AFGR64, MipsCMovFP_F, 17, 0, "movf.d">; + def FCMP_S32 : FCMP<0x10, FGR32, "s">; + def FCMP_D32 : FCMP<0x11, AFGR64, "d">, Requires<[NotFP64bit]>; + def FCMP_D64 : FCMP<0x11, FGR64, "d">, Requires<[IsFP64bit]>; } //===----------------------------------------------------------------------===// @@ -352,25 +405,46 @@ def ExtractElementF64 : //===----------------------------------------------------------------------===// // 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_S (MTC1 ZERO))>; def : Pat<(f32 (sint_to_fp CPURegs:$src)), (CVT_S_W (MTC1 CPURegs:$src))>; -def : Pat<(f64 (sint_to_fp CPURegs:$src)), (CVT_D32_W (MTC1 CPURegs:$src))>; - def : Pat<(i32 (fp_to_sint FGR32:$src)), (MFC1 (TRUNC_W_S FGR32:$src))>; -def : Pat<(i32 (fp_to_sint AFGR64:$src)), (MFC1 (TRUNC_W_D32 AFGR64:$src))>; let Predicates = [NotFP64bit] in { + def : Pat<(f64 (sint_to_fp CPURegs:$src)), (CVT_D32_W (MTC1 CPURegs:$src))>; + def : Pat<(i32 (fp_to_sint AFGR64:$src)), (MFC1 (TRUNC_W_D32 AFGR64:$src))>; def : Pat<(f32 (fround AFGR64:$src)), (CVT_S_D32 AFGR64:$src)>; def : Pat<(f64 (fextend FGR32:$src)), (CVT_D32_S FGR32:$src)>; } +let Predicates = [IsFP64bit] in { + def : Pat<(f64 fpimm0), (DMTC1 ZERO_64)>; + def : Pat<(f64 fpimm0neg), (FNEG_D64 (DMTC1 ZERO_64))>; + + def : Pat<(f64 (sint_to_fp CPURegs:$src)), (CVT_D64_W (MTC1 CPURegs:$src))>; + def : Pat<(f32 (sint_to_fp CPU64Regs:$src)), + (CVT_S_L (DMTC1 CPU64Regs:$src))>; + def : Pat<(f64 (sint_to_fp CPU64Regs:$src)), + (CVT_D64_L (DMTC1 CPU64Regs:$src))>; + + def : Pat<(i32 (fp_to_sint FGR64:$src)), (MFC1 (TRUNC_W_D64 FGR64:$src))>; + def : Pat<(i64 (fp_to_sint FGR32:$src)), (DMFC1 (TRUNC_L_S FGR32:$src))>; + def : Pat<(i64 (fp_to_sint FGR64:$src)), (DMFC1 (TRUNC_L_D64 FGR64:$src))>; + + def : Pat<(f32 (fround FGR64:$src)), (CVT_S_D64 FGR64:$src)>; + def : Pat<(f64 (fextend FGR32:$src)), (CVT_D64_S FGR32:$src)>; +} + +// Patterns for unaligned floating point loads and stores. +let Predicates = [HasMips32r2Or64, NotN64] in { + def : Pat<(f32 (load_u CPURegs:$addr)), (LUXC1 CPURegs:$addr, ZERO)>; + def : Pat<(store_u FGR32:$src, CPURegs:$addr), + (SUXC1 FGR32:$src, CPURegs:$addr, ZERO)>; +} + +let Predicates = [IsN64] in { + def : Pat<(f32 (load_u CPU64Regs:$addr)), (LUXC1_P8 CPU64Regs:$addr, ZERO_64)>; + def : Pat<(store_u FGR32:$src, CPU64Regs:$addr), + (SUXC1_P8 FGR32:$src, CPU64Regs:$addr, ZERO_64)>; +} diff --git a/lib/Target/Mips/MipsInstrFormats.td b/lib/Target/Mips/MipsInstrFormats.td index e1725fa867f0..455530389eba 100644 --- a/lib/Target/Mips/MipsInstrFormats.td +++ b/lib/Target/Mips/MipsInstrFormats.td @@ -1,4 +1,4 @@ -//===- MipsInstrFormats.td - Mips Instruction Formats ------*- tablegen -*-===// +//===-- MipsInstrFormats.td - Mips Instruction Formats -----*- tablegen -*-===// // // The LLVM Compiler Infrastructure // @@ -115,7 +115,7 @@ class FI<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern, let Inst{15-0} = imm16; } -class CBranchBase<bits<6> op, dag outs, dag ins, string asmstr, +class BranchBase<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern, InstrItinClass itin>: MipsInst<outs, ins, asmstr, pattern, itin, FrmI> { @@ -290,3 +290,40 @@ class FFR2P<bits<6> funct, bits<5> fmt, string opstr, FFR<0x11, funct, fmt, (outs RC:$fd), (ins RC:$fs, RC:$ft), !strconcat(opstr, ".", fmtstr, "\t$fd, $fs, $ft"), [(set RC:$fd, (OpNode RC:$fs, RC:$ft))]>; + +// Floating point madd/msub/nmadd/nmsub. +class FFMADDSUB<bits<3> funct, bits<3> fmt, dag outs, dag ins, string asmstr, + list<dag> pattern> + : MipsInst<outs, ins, asmstr, pattern, NoItinerary, FrmOther> { + bits<5> fd; + bits<5> fr; + bits<5> fs; + bits<5> ft; + + let Opcode = 0x13; + let Inst{25-21} = fr; + let Inst{20-16} = ft; + let Inst{15-11} = fs; + let Inst{10-6} = fd; + let Inst{5-3} = funct; + let Inst{2-0} = fmt; +} + +// FP indexed load/store instructions. +class FFMemIdx<bits<6> funct, dag outs, dag ins, string asmstr, + list<dag> pattern> : + MipsInst<outs, ins, asmstr, pattern, NoItinerary, FrmOther> +{ + bits<5> base; + bits<5> index; + bits<5> fs; + bits<5> fd; + + let Opcode = 0x13; + + let Inst{25-21} = base; + let Inst{20-16} = index; + let Inst{15-11} = fs; + let Inst{10-6} = fd; + let Inst{5-0} = funct; +} diff --git a/lib/Target/Mips/MipsInstrInfo.cpp b/lib/Target/Mips/MipsInstrInfo.cpp index 559943a8dbae..a3a18bff6553 100644 --- a/lib/Target/Mips/MipsInstrInfo.cpp +++ b/lib/Target/Mips/MipsInstrInfo.cpp @@ -1,4 +1,4 @@ -//===- MipsInstrInfo.cpp - Mips Instruction Information ---------*- C++ -*-===// +//===-- MipsInstrInfo.cpp - Mips Instruction Information ------------------===// // // The LLVM Compiler Infrastructure // @@ -29,10 +29,10 @@ using namespace llvm; MipsInstrInfo::MipsInstrInfo(MipsTargetMachine &tm) : MipsGenInstrInfo(Mips::ADJCALLSTACKDOWN, Mips::ADJCALLSTACKUP), TM(tm), IsN64(TM.getSubtarget<MipsSubtarget>().isABI_N64()), - RI(*TM.getSubtargetImpl(), *this) {} + RI(*TM.getSubtargetImpl(), *this), + UncondBrOpc(TM.getRelocationModel() == Reloc::PIC_ ? Mips::B : Mips::J) {} - -const MipsRegisterInfo &MipsInstrInfo::getRegisterInfo() const { +const MipsRegisterInfo &MipsInstrInfo::getRegisterInfo() const { return RI; } @@ -131,6 +131,8 @@ copyPhysReg(MachineBasicBlock &MBB, Opc = Mips::FMOV_S; else if (Mips::AFGR64RegClass.contains(DestReg, SrcReg)) Opc = Mips::FMOV_D32; + else if (Mips::FGR64RegClass.contains(DestReg, SrcReg)) + Opc = Mips::FMOV_D64; else if (Mips::CCRRegClass.contains(DestReg, SrcReg)) Opc = Mips::MOVCCRToCCR; else if (Mips::CPU64RegsRegClass.contains(DestReg)) { // Copy to CPU64 Reg. @@ -140,18 +142,22 @@ copyPhysReg(MachineBasicBlock &MBB, Opc = Mips::MFHI64, SrcReg = 0; else if (SrcReg == Mips::LO64) Opc = Mips::MFLO64, SrcReg = 0; + else if (Mips::FGR64RegClass.contains(SrcReg)) + Opc = Mips::DMFC1; } else if (Mips::CPU64RegsRegClass.contains(SrcReg)) { // Copy from CPU64 Reg. if (DestReg == Mips::HI64) Opc = Mips::MTHI64, DestReg = 0; else if (DestReg == Mips::LO64) Opc = Mips::MTLO64, DestReg = 0; + else if (Mips::FGR64RegClass.contains(DestReg)) + Opc = Mips::DMTC1; } assert(Opc && "Cannot copy registers"); MachineInstrBuilder MIB = BuildMI(MBB, I, DL, get(Opc)); - + if (DestReg) MIB.addReg(DestReg, RegState::Define); @@ -162,6 +168,16 @@ copyPhysReg(MachineBasicBlock &MBB, MIB.addReg(SrcReg, getKillRegState(KillSrc)); } +static MachineMemOperand* GetMemOperand(MachineBasicBlock &MBB, int FI, + unsigned Flag) { + MachineFunction &MF = *MBB.getParent(); + MachineFrameInfo &MFI = *MF.getFrameInfo(); + unsigned Align = MFI.getObjectAlignment(FI); + + return MF.getMachineMemOperand(MachinePointerInfo::getFixedStack(FI), Flag, + MFI.getObjectSize(FI), Align); +} + void MipsInstrInfo:: storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, unsigned SrcReg, bool isKill, int FI, @@ -169,6 +185,8 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, const TargetRegisterInfo *TRI) const { DebugLoc DL; if (I != MBB.end()) DL = I->getDebugLoc(); + MachineMemOperand *MMO = GetMemOperand(MBB, FI, MachineMemOperand::MOStore); + unsigned Opc = 0; if (RC == Mips::CPURegsRegisterClass) @@ -184,7 +202,7 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, assert(Opc && "Register class not handled!"); BuildMI(MBB, I, DL, get(Opc)).addReg(SrcReg, getKillRegState(isKill)) - .addFrameIndex(FI).addImm(0); + .addFrameIndex(FI).addImm(0).addMemOperand(MMO); } void MipsInstrInfo:: @@ -195,6 +213,7 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, { DebugLoc DL; if (I != MBB.end()) DL = I->getDebugLoc(); + MachineMemOperand *MMO = GetMemOperand(MBB, FI, MachineMemOperand::MOLoad); unsigned Opc = 0; if (RC == Mips::CPURegsRegisterClass) @@ -209,7 +228,8 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Opc = IsN64 ? Mips::LDC164_P8 : Mips::LDC164; assert(Opc && "Register class not handled!"); - BuildMI(MBB, I, DL, get(Opc), DestReg).addFrameIndex(FI).addImm(0); + BuildMI(MBB, I, DL, get(Opc), DestReg).addFrameIndex(FI).addImm(0) + .addMemOperand(MMO); } MachineInstr* @@ -230,7 +250,8 @@ static unsigned GetAnalyzableBrOpc(unsigned Opc) { Opc == Mips::BGEZ || Opc == Mips::BLTZ || Opc == Mips::BLEZ || Opc == Mips::BEQ64 || Opc == Mips::BNE64 || Opc == Mips::BGTZ64 || Opc == Mips::BGEZ64 || Opc == Mips::BLTZ64 || Opc == Mips::BLEZ64 || - Opc == Mips::BC1T || Opc == Mips::BC1F || Opc == Mips::J) ? + Opc == Mips::BC1T || Opc == Mips::BC1F || Opc == Mips::B || + Opc == Mips::J) ? Opc : 0; } @@ -239,21 +260,21 @@ static unsigned GetAnalyzableBrOpc(unsigned Opc) { unsigned Mips::GetOppositeBranchOpc(unsigned Opc) { switch (Opc) { - default: llvm_unreachable("Illegal opcode!"); - case Mips::BEQ : return Mips::BNE; - case Mips::BNE : return Mips::BEQ; - case Mips::BGTZ : return Mips::BLEZ; - case Mips::BGEZ : return Mips::BLTZ; - case Mips::BLTZ : return Mips::BGEZ; - case Mips::BLEZ : return Mips::BGTZ; - case Mips::BEQ64 : return Mips::BNE64; - case Mips::BNE64 : return Mips::BEQ64; - case Mips::BGTZ64 : return Mips::BLEZ64; - case Mips::BGEZ64 : return Mips::BLTZ64; - case Mips::BLTZ64 : return Mips::BGEZ64; - case Mips::BLEZ64 : return Mips::BGTZ64; - case Mips::BC1T : return Mips::BC1F; - case Mips::BC1F : return Mips::BC1T; + default: llvm_unreachable("Illegal opcode!"); + case Mips::BEQ: return Mips::BNE; + case Mips::BNE: return Mips::BEQ; + case Mips::BGTZ: return Mips::BLEZ; + case Mips::BGEZ: return Mips::BLTZ; + case Mips::BLTZ: return Mips::BGEZ; + case Mips::BLEZ: return Mips::BGTZ; + case Mips::BEQ64: return Mips::BNE64; + case Mips::BNE64: return Mips::BEQ64; + case Mips::BGTZ64: return Mips::BLEZ64; + case Mips::BGEZ64: return Mips::BLTZ64; + case Mips::BLTZ64: return Mips::BGEZ64; + case Mips::BLEZ64: return Mips::BGTZ64; + case Mips::BC1T: return Mips::BC1F; + case Mips::BC1F: return Mips::BC1T; } } @@ -262,7 +283,7 @@ static void AnalyzeCondBr(const MachineInstr* Inst, unsigned Opc, SmallVectorImpl<MachineOperand>& Cond) { assert(GetAnalyzableBrOpc(Opc) && "Not an analyzable branch"); int NumOp = Inst->getNumExplicitOperands(); - + // for both int and fp branches, the last explicit operand is the // MBB. BB = Inst->getOperand(NumOp-1).getMBB(); @@ -314,7 +335,7 @@ bool MipsInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, // If there is only one terminator instruction, process it. if (!SecondLastOpc) { // Unconditional branch - if (LastOpc == Mips::J) { + if (LastOpc == UncondBrOpc) { TBB = LastInst->getOperand(0).getMBB(); return false; } @@ -331,7 +352,7 @@ bool MipsInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, // If second to last instruction is an unconditional branch, // analyze it and remove the last instruction. - if (SecondLastOpc == Mips::J) { + if (SecondLastOpc == UncondBrOpc) { // Return if the last instruction cannot be removed. if (!AllowModify) return true; @@ -343,15 +364,15 @@ bool MipsInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, // Conditional branch followed by an unconditional branch. // The last one must be unconditional. - if (LastOpc != Mips::J) + if (LastOpc != UncondBrOpc) return true; AnalyzeCondBr(SecondLastInst, SecondLastOpc, TBB, Cond); FBB = LastInst->getOperand(0).getMBB(); return false; -} - +} + void MipsInstrInfo::BuildCondBr(MachineBasicBlock &MBB, MachineBasicBlock *TBB, DebugLoc DL, const SmallVectorImpl<MachineOperand>& Cond) @@ -385,14 +406,14 @@ InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, // Two-way Conditional branch. if (FBB) { BuildCondBr(MBB, TBB, DL, Cond); - BuildMI(&MBB, DL, get(Mips::J)).addMBB(FBB); + BuildMI(&MBB, DL, get(UncondBrOpc)).addMBB(FBB); return 2; } // One way branch. // Unconditional branch. if (Cond.empty()) - BuildMI(&MBB, DL, get(Mips::J)).addMBB(TBB); + BuildMI(&MBB, DL, get(UncondBrOpc)).addMBB(TBB); else // Conditional branch. BuildCondBr(MBB, TBB, DL, Cond); return 1; @@ -433,27 +454,3 @@ ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const 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); - BuildMI(FirstMBB, MBBI, DebugLoc(), TII->get(TargetOpcode::COPY), - GlobalBaseReg).addReg(Mips::GP); - RegInfo.addLiveIn(Mips::GP); - - MipsFI->setGlobalBaseReg(GlobalBaseReg); - return GlobalBaseReg; -} diff --git a/lib/Target/Mips/MipsInstrInfo.h b/lib/Target/Mips/MipsInstrInfo.h index 271d2487ecfa..4be727dd8994 100644 --- a/lib/Target/Mips/MipsInstrInfo.h +++ b/lib/Target/Mips/MipsInstrInfo.h @@ -1,4 +1,4 @@ -//===- MipsInstrInfo.h - Mips Instruction Information -----------*- C++ -*-===// +//===-- MipsInstrInfo.h - Mips Instruction Information ----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,9 +15,9 @@ #define MIPSINSTRUCTIONINFO_H #include "Mips.h" +#include "MipsRegisterInfo.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Target/TargetInstrInfo.h" -#include "MipsRegisterInfo.h" #define GET_INSTRINFO_HEADER #include "MipsGenInstrInfo.inc" @@ -30,90 +30,11 @@ namespace Mips { unsigned GetOppositeBranchOpc(unsigned Opc); } -/// 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_HI/LO - Represents the hi or low part of an absolute symbol - /// address. - MO_ABS_HI, - MO_ABS_LO, - - /// MO_TLSGD - Represents the offset into the global offset table at which - // the module ID and TSL block offset reside during execution (General - // Dynamic TLS). - MO_TLSGD, - - /// MO_GOTTPREL - Represents the offset from the thread pointer (Initial - // Exec TLS). - MO_GOTTPREL, - - /// MO_TPREL_HI/LO - Represents the hi and low part of the offset from - // the thread pointer (Local Exec TLS). - MO_TPREL_HI, - MO_TPREL_LO, - - // N32/64 Flags. - MO_GPOFF_HI, - MO_GPOFF_LO, - MO_GOT_DISP, - MO_GOT_PAGE, - MO_GOT_OFST - }; - - enum { - //===------------------------------------------------------------------===// - // Instruction encodings. These are the standard/most common forms for - // Mips instructions. - // - - // Pseudo - This represents an instruction that is a pseudo instruction - // or one that has not been implemented yet. It is illegal to code generate - // it, but tolerated for intermediate implementation stages. - Pseudo = 0, - - /// FrmR - This form is for instructions of the format R. - FrmR = 1, - /// FrmI - This form is for instructions of the format I. - FrmI = 2, - /// FrmJ - This form is for instructions of the format J. - FrmJ = 3, - /// FrmFR - This form is for instructions of the format FR. - FrmFR = 4, - /// FrmFI - This form is for instructions of the format FI. - FrmFI = 5, - /// FrmOther - This form is for instructions that have no specific format. - FrmOther = 6, - - FormMask = 15 - }; -} - class MipsInstrInfo : public MipsGenInstrInfo { MipsTargetMachine &TM; bool IsN64; const MipsRegisterInfo RI; + unsigned UncondBrOpc; public: explicit MipsInstrInfo(MipsTargetMachine &TM); @@ -182,12 +103,6 @@ public: /// 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; }; } diff --git a/lib/Target/Mips/MipsInstrInfo.td b/lib/Target/Mips/MipsInstrInfo.td index 3fbd41ef6a3b..be74f8e5230c 100644 --- a/lib/Target/Mips/MipsInstrInfo.td +++ b/lib/Target/Mips/MipsInstrInfo.td @@ -39,8 +39,8 @@ def SDT_MipsDivRem : SDTypeProfile<0, 2, def SDT_MipsThreadPointer : SDTypeProfile<1, 0, [SDTCisPtrTy<0>]>; -def SDT_MipsDynAlloc : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, - SDTCisVT<1, iPTR>]>; +def SDT_MipsDynAlloc : SDTypeProfile<1, 1, [SDTCisVT<0, iPTR>, + SDTCisSameAs<0, 1>]>; def SDT_Sync : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>; def SDT_Ext : SDTypeProfile<1, 3, [SDTCisInt<0>, SDTCisSameAs<0, 1>, @@ -103,11 +103,11 @@ def MipsDivRemU : SDNode<"MipsISD::DivRemU", SDT_MipsDivRem, // target constant nodes that would otherwise remain unchanged with ADDiu // nodes. Without these wrapper node patterns, the following conditional move // instrucion is emitted when function cmov2 in test/CodeGen/Mips/cmov.ll is -// compiled: +// compiled: // movn %got(d)($gp), %got(c)($gp), $4 // This instruction is illegal since movn can take only register operands. -def MipsWrapperPIC : SDNode<"MipsISD::WrapperPIC", SDTIntUnaryOp>; +def MipsWrapper : SDNode<"MipsISD::Wrapper", SDTIntBinOp>; // Pointer to dynamically allocated stack area. def MipsDynAlloc : SDNode<"MipsISD::DynAlloc", SDT_MipsDynAlloc, @@ -128,18 +128,31 @@ def HasCondMov : Predicate<"Subtarget.hasCondMov()">; def HasMips32 : Predicate<"Subtarget.hasMips32()">; def HasMips32r2 : Predicate<"Subtarget.hasMips32r2()">; def HasMips64 : Predicate<"Subtarget.hasMips64()">; +def HasMips32r2Or64 : Predicate<"Subtarget.hasMips32r2Or64()">; def NotMips64 : Predicate<"!Subtarget.hasMips64()">; def HasMips64r2 : Predicate<"Subtarget.hasMips64r2()">; def IsN64 : Predicate<"Subtarget.isABI_N64()">; def NotN64 : Predicate<"!Subtarget.isABI_N64()">; +def RelocStatic : Predicate<"TM.getRelocationModel() == Reloc::Static">; +def RelocPIC : Predicate<"TM.getRelocationModel() == Reloc::PIC_">; +def NoNaNsFPMath : Predicate<"TM.Options.NoNaNsFPMath">; //===----------------------------------------------------------------------===// // Mips Operand, Complex Patterns and Transformations Definitions. //===----------------------------------------------------------------------===// // Instruction operand types -def brtarget : Operand<OtherVT>; -def calltarget : Operand<i32>; +def jmptarget : Operand<OtherVT> { + let EncoderMethod = "getJumpTargetOpValue"; +} +def brtarget : Operand<OtherVT> { + let EncoderMethod = "getBranchTargetOpValue"; + let OperandType = "OPERAND_PCREL"; +} +def calltarget : Operand<iPTR> { + let EncoderMethod = "getJumpTargetOpValue"; +} +def calltarget64: Operand<i64>; def simm16 : Operand<i32>; def simm16_64 : Operand<i64>; def shamt : Operand<i32>; @@ -167,6 +180,12 @@ def mem_ea : Operand<i32> { let EncoderMethod = "getMemEncoding"; } +def mem_ea_64 : Operand<i64> { + let PrintMethod = "printMemOperandEA"; + let MIOperandInfo = (ops CPU64Regs, simm16_64); + let EncoderMethod = "getMemEncoding"; +} + // size operand of ext instruction def size_ext : Operand<i32> { let EncoderMethod = "getSizeExtEncoding"; @@ -179,12 +198,12 @@ def size_ins : Operand<i32> { // Transformation Function - get the lower 16 bits. def LO16 : SDNodeXForm<imm, [{ - return getI32Imm((unsigned)N->getZExtValue() & 0xFFFF); + return getImm(N, N->getZExtValue() & 0xFFFF); }]>; // Transformation Function - get the higher 16 bits. def HI16 : SDNodeXForm<imm, [{ - return getI32Imm((unsigned)N->getZExtValue() >> 16); + return getImm(N, (N->getZExtValue() >> 16) & 0xFFFF); }]>; // Node immediate fits as 16-bit sign extended on target immediate. @@ -202,36 +221,42 @@ def immZExt16 : PatLeaf<(imm), [{ 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) ; +// Immediate can be loaded with LUi (32-bit int with lower 16-bit cleared). +def immLow16Zero : PatLeaf<(imm), [{ + int64_t Val = N->getSExtValue(); + return isInt<32>(Val) && !(Val & 0xffff); }]>; +// shamt field must fit in 5 bits. +def immZExt5 : ImmLeaf<i32, [{return Imm == (Imm & 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], []>; +def addr : ComplexPattern<iPTR, 2, "SelectAddr", [frameindex], [SDNPWantParent]>; //===----------------------------------------------------------------------===// // Pattern fragment for load/store //===----------------------------------------------------------------------===// -class UnalignedLoad<PatFrag Node> : PatFrag<(ops node:$ptr), (Node node:$ptr), [{ +class UnalignedLoad<PatFrag Node> : + PatFrag<(ops node:$ptr), (Node node:$ptr), [{ LoadSDNode *LD = cast<LoadSDNode>(N); return LD->getMemoryVT().getSizeInBits()/8 > LD->getAlignment(); }]>; -class AlignedLoad<PatFrag Node> : PatFrag<(ops node:$ptr), (Node node:$ptr), [{ +class AlignedLoad<PatFrag Node> : + PatFrag<(ops node:$ptr), (Node node:$ptr), [{ LoadSDNode *LD = cast<LoadSDNode>(N); return LD->getMemoryVT().getSizeInBits()/8 <= LD->getAlignment(); }]>; -class UnalignedStore<PatFrag Node> : PatFrag<(ops node:$val, node:$ptr), - (Node node:$val, node:$ptr), [{ +class UnalignedStore<PatFrag Node> : + PatFrag<(ops node:$val, node:$ptr), (Node node:$val, node:$ptr), [{ StoreSDNode *SD = cast<StoreSDNode>(N); return SD->getMemoryVT().getSizeInBits()/8 > SD->getAlignment(); }]>; -class AlignedStore<PatFrag Node> : PatFrag<(ops node:$val, node:$ptr), - (Node node:$val, node:$ptr), [{ +class AlignedStore<PatFrag Node> : + PatFrag<(ops node:$val, node:$ptr), (Node node:$val, node:$ptr), [{ StoreSDNode *SD = cast<StoreSDNode>(N); return SD->getMemoryVT().getSizeInBits()/8 <= SD->getAlignment(); }]>; @@ -313,27 +338,34 @@ class LogicNOR<bits<6> op, bits<6> func, string instr_asm, RegisterClass RC>: } // Shifts -class LogicR_shift_rotate_imm<bits<6> func, bits<5> _rs, string instr_asm, - SDNode OpNode>: - FR<0x00, func, (outs CPURegs:$rd), (ins CPURegs:$rt, shamt:$shamt), +class shift_rotate_imm<bits<6> func, bits<5> isRotate, string instr_asm, + SDNode OpNode, PatFrag PF, Operand ImmOpnd, + RegisterClass RC>: + FR<0x00, func, (outs RC:$rd), (ins RC:$rt, ImmOpnd:$shamt), !strconcat(instr_asm, "\t$rd, $rt, $shamt"), - [(set CPURegs:$rd, (OpNode CPURegs:$rt, (i32 immZExt5:$shamt)))], IIAlu> { - let rs = _rs; + [(set RC:$rd, (OpNode RC:$rt, PF:$shamt))], IIAlu> { + let rs = isRotate; } -class LogicR_shift_rotate_reg<bits<6> func, bits<5> isRotate, string instr_asm, - SDNode OpNode>: - FR<0x00, func, (outs CPURegs:$rd), (ins CPURegs:$rs, CPURegs:$rt), +// 32-bit shift instructions. +class shift_rotate_imm32<bits<6> func, bits<5> isRotate, string instr_asm, + SDNode OpNode>: + shift_rotate_imm<func, isRotate, instr_asm, OpNode, immZExt5, shamt, CPURegs>; + +class shift_rotate_reg<bits<6> func, bits<5> isRotate, string instr_asm, + SDNode OpNode, RegisterClass RC>: + FR<0x00, func, (outs RC:$rd), (ins CPURegs:$rs, RC:$rt), !strconcat(instr_asm, "\t$rd, $rt, $rs"), - [(set CPURegs:$rd, (OpNode CPURegs:$rt, CPURegs:$rs))], IIAlu> { + [(set RC:$rd, (OpNode RC:$rt, CPURegs:$rs))], IIAlu> { let shamt = isRotate; } // Load Upper Imediate -class LoadUpper<bits<6> op, string instr_asm>: - FI<op, (outs CPURegs:$rt), (ins uimm16:$imm16), +class LoadUpper<bits<6> op, string instr_asm, RegisterClass RC, Operand Imm>: + FI<op, (outs RC:$rt), (ins Imm:$imm16), !strconcat(instr_asm, "\t$rt, $imm16"), [], IIAlu> { let rs = 0; + let neverHasSideEffects = 1; } class FMem<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern, @@ -361,6 +393,14 @@ class StoreM<bits<6> op, string instr_asm, PatFrag OpNode, RegisterClass RC, let isPseudo = Pseudo; } +// Unaligned Memory Load/Store +let canFoldAsLoad = 1 in +class LoadUnAlign<bits<6> op, RegisterClass RC, Operand MemOpnd>: + FMem<op, (outs RC:$rt), (ins MemOpnd:$addr), "", [], IILoad> {} + +class StoreUnAlign<bits<6> op, RegisterClass RC, Operand MemOpnd>: + FMem<op, (outs), (ins RC:$rt, MemOpnd:$addr), "", [], IIStore> {} + // 32-bit load. multiclass LoadM32<bits<6> op, string instr_asm, PatFrag OpNode, bit Pseudo = 0> { @@ -368,7 +408,7 @@ multiclass LoadM32<bits<6> op, string instr_asm, PatFrag OpNode, Requires<[NotN64]>; def _P8 : LoadM<op, instr_asm, OpNode, CPURegs, mem64, Pseudo>, Requires<[IsN64]>; -} +} // 64-bit load. multiclass LoadM64<bits<6> op, string instr_asm, PatFrag OpNode, @@ -377,8 +417,15 @@ multiclass LoadM64<bits<6> op, string instr_asm, PatFrag OpNode, Requires<[NotN64]>; def _P8 : LoadM<op, instr_asm, OpNode, CPU64Regs, mem64, Pseudo>, Requires<[IsN64]>; -} +} +// 32-bit load. +multiclass LoadUnAlign32<bits<6> op> { + def #NAME# : LoadUnAlign<op, CPURegs, mem>, + Requires<[NotN64]>; + def _P8 : LoadUnAlign<op, CPURegs, mem64>, + Requires<[IsN64]>; +} // 32-bit store. multiclass StoreM32<bits<6> op, string instr_asm, PatFrag OpNode, bit Pseudo = 0> { @@ -397,11 +444,19 @@ multiclass StoreM64<bits<6> op, string instr_asm, PatFrag OpNode, Requires<[IsN64]>; } +// 32-bit store. +multiclass StoreUnAlign32<bits<6> op> { + def #NAME# : StoreUnAlign<op, CPURegs, mem>, + Requires<[NotN64]>; + def _P8 : StoreUnAlign<op, CPURegs, mem64>, + Requires<[IsN64]>; +} + // Conditional Branch class CBranch<bits<6> op, string instr_asm, PatFrag cond_op, RegisterClass RC>: - CBranchBase<op, (outs), (ins RC:$rs, RC:$rt, brtarget:$imm16), - !strconcat(instr_asm, "\t$rs, $rt, $imm16"), - [(brcond (i32 (cond_op RC:$rs, RC:$rt)), bb:$imm16)], IIBranch> { + BranchBase<op, (outs), (ins RC:$rs, RC:$rt, brtarget:$imm16), + !strconcat(instr_asm, "\t$rs, $rt, $imm16"), + [(brcond (i32 (cond_op RC:$rs, RC:$rt)), bb:$imm16)], IIBranch> { let isBranch = 1; let isTerminator = 1; let hasDelaySlot = 1; @@ -409,9 +464,9 @@ class CBranch<bits<6> op, string instr_asm, PatFrag cond_op, RegisterClass RC>: class CBranchZero<bits<6> op, bits<5> _rt, string instr_asm, PatFrag cond_op, RegisterClass RC>: - CBranchBase<op, (outs), (ins RC:$rs, brtarget:$imm16), - !strconcat(instr_asm, "\t$rs, $imm16"), - [(brcond (i32 (cond_op RC:$rs, 0)), bb:$imm16)], IIBranch> { + BranchBase<op, (outs), (ins RC:$rs, brtarget:$imm16), + !strconcat(instr_asm, "\t$rs, $imm16"), + [(brcond (i32 (cond_op RC:$rs, 0)), bb:$imm16)], IIBranch> { let rt = _rt; let isBranch = 1; let isTerminator = 1; @@ -435,146 +490,228 @@ class SetCC_I<bits<6> op, string instr_asm, PatFrag cond_op, Operand Od, [(set CPURegs:$rt, (cond_op RC:$rs, imm_type:$imm16))], IIAlu>; -// Unconditional branch -let isBranch=1, isTerminator=1, isBarrier=1, hasDelaySlot = 1 in +// Jump class JumpFJ<bits<6> op, string instr_asm>: - FJ<op, (outs), (ins brtarget:$target), - !strconcat(instr_asm, "\t$target"), [(br bb:$target)], IIBranch>; + FJ<op, (outs), (ins jmptarget:$target), + !strconcat(instr_asm, "\t$target"), [(br bb:$target)], IIBranch> { + let isBranch=1; + let isTerminator=1; + let isBarrier=1; + let hasDelaySlot = 1; + let Predicates = [RelocStatic]; +} + +// Unconditional branch +class UncondBranch<bits<6> op, string instr_asm>: + BranchBase<op, (outs), (ins brtarget:$imm16), + !strconcat(instr_asm, "\t$imm16"), [(br bb:$imm16)], IIBranch> { + let rs = 0; + let rt = 0; + let isBranch = 1; + let isTerminator = 1; + let isBarrier = 1; + let hasDelaySlot = 1; + let Predicates = [RelocPIC]; +} -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:$rs), - !strconcat(instr_asm, "\t$rs"), [(brind CPURegs:$rs)], IIBranch> { +let isBranch=1, isTerminator=1, isBarrier=1, rd=0, hasDelaySlot = 1, + isIndirectBranch = 1 in +class JumpFR<bits<6> op, bits<6> func, string instr_asm, RegisterClass RC>: + FR<op, func, (outs), (ins RC:$rs), + !strconcat(instr_asm, "\t$rs"), [(brind RC:$rs)], IIBranch> { let rt = 0; let rd = 0; let shamt = 0; } // 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 { +let isCall=1, hasDelaySlot=1 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>; - 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 JumpLinkReg<bits<6> op, bits<6> func, string instr_asm, + RegisterClass RC>: + FR<op, func, (outs), (ins RC:$rs, variable_ops), + !strconcat(instr_asm, "\t$rs"), [(MipsJmpLink RC:$rs)], IIBranch> { let rt = 0; let rd = 31; let shamt = 0; } - class BranchLink<string instr_asm>: - FI<0x1, (outs), (ins CPURegs:$rs, brtarget:$imm16, variable_ops), - !strconcat(instr_asm, "\t$rs, $imm16"), [], IIBranch>; + class BranchLink<string instr_asm, bits<5> _rt, RegisterClass RC>: + FI<0x1, (outs), (ins RC:$rs, brtarget:$imm16, variable_ops), + !strconcat(instr_asm, "\t$rs, $imm16"), [], IIBranch> { + let rt = _rt; + } } // Mul, Div -class Mul<bits<6> func, string instr_asm, InstrItinClass itin>: - FR<0x00, func, (outs), (ins CPURegs:$rs, CPURegs:$rt), +class Mult<bits<6> func, string instr_asm, InstrItinClass itin, + RegisterClass RC, list<Register> DefRegs>: + FR<0x00, func, (outs), (ins RC:$rs, RC:$rt), !strconcat(instr_asm, "\t$rs, $rt"), [], itin> { let rd = 0; let shamt = 0; let isCommutable = 1; - let Defs = [HI, LO]; + let Defs = DefRegs; + let neverHasSideEffects = 1; } -class Div<SDNode op, bits<6> func, string instr_asm, InstrItinClass itin>: - FR<0x00, func, (outs), (ins CPURegs:$rs, CPURegs:$rt), - !strconcat(instr_asm, "\t$$zero, $rs, $rt"), - [(op CPURegs:$rs, CPURegs:$rt)], itin> { +class Mult32<bits<6> func, string instr_asm, InstrItinClass itin>: + Mult<func, instr_asm, itin, CPURegs, [HI, LO]>; + +class Div<SDNode op, bits<6> func, string instr_asm, InstrItinClass itin, + RegisterClass RC, list<Register> DefRegs>: + FR<0x00, func, (outs), (ins RC:$rs, RC:$rt), + !strconcat(instr_asm, "\t$$zero, $rs, $rt"), + [(op RC:$rs, RC:$rt)], itin> { let rd = 0; let shamt = 0; - let Defs = [HI, LO]; + let Defs = DefRegs; } +class Div32<SDNode op, bits<6> func, string instr_asm, InstrItinClass itin>: + Div<op, func, instr_asm, itin, CPURegs, [HI, LO]>; + // Move from Hi/Lo -class MoveFromLOHI<bits<6> func, string instr_asm>: - FR<0x00, func, (outs CPURegs:$rd), (ins), +class MoveFromLOHI<bits<6> func, string instr_asm, RegisterClass RC, + list<Register> UseRegs>: + FR<0x00, func, (outs RC:$rd), (ins), !strconcat(instr_asm, "\t$rd"), [], IIHiLo> { let rs = 0; let rt = 0; let shamt = 0; + let Uses = UseRegs; + let neverHasSideEffects = 1; } -class MoveToLOHI<bits<6> func, string instr_asm>: - FR<0x00, func, (outs), (ins CPURegs:$rs), +class MoveToLOHI<bits<6> func, string instr_asm, RegisterClass RC, + list<Register> DefRegs>: + FR<0x00, func, (outs), (ins RC:$rs), !strconcat(instr_asm, "\t$rs"), [], IIHiLo> { let rt = 0; let rd = 0; let shamt = 0; + let Defs = DefRegs; + let neverHasSideEffects = 1; } -class EffectiveAddress<string instr_asm> : - FMem<0x09, (outs CPURegs:$rt), (ins mem_ea:$addr), - instr_asm, [(set CPURegs:$rt, addr:$addr)], IIAlu>; +class EffectiveAddress<string instr_asm, RegisterClass RC, Operand Mem> : + FMem<0x09, (outs RC:$rt), (ins Mem:$addr), + instr_asm, [(set RC:$rt, addr:$addr)], IIAlu>; // Count Leading Ones/Zeros in Word -class CountLeading<bits<6> func, string instr_asm, list<dag> pattern>: - FR<0x1c, func, (outs CPURegs:$rd), (ins CPURegs:$rs), - !strconcat(instr_asm, "\t$rd, $rs"), pattern, IIAlu>, +class CountLeading0<bits<6> func, string instr_asm, RegisterClass RC>: + FR<0x1c, func, (outs RC:$rd), (ins RC:$rs), + !strconcat(instr_asm, "\t$rd, $rs"), + [(set RC:$rd, (ctlz RC:$rs))], IIAlu>, + Requires<[HasBitCount]> { + let shamt = 0; + let rt = rd; +} + +class CountLeading1<bits<6> func, string instr_asm, RegisterClass RC>: + FR<0x1c, func, (outs RC:$rd), (ins RC:$rs), + !strconcat(instr_asm, "\t$rd, $rs"), + [(set RC:$rd, (ctlz (not RC:$rs)))], IIAlu>, Requires<[HasBitCount]> { let shamt = 0; let rt = rd; } // Sign Extend in Register. -class SignExtInReg<bits<5> sa, string instr_asm, ValueType vt>: - FR<0x1f, 0x20, (outs CPURegs:$rd), (ins CPURegs:$rt), +class SignExtInReg<bits<5> sa, string instr_asm, ValueType vt, + RegisterClass RC>: + FR<0x1f, 0x20, (outs RC:$rd), (ins RC:$rt), !strconcat(instr_asm, "\t$rd, $rt"), - [(set CPURegs:$rd, (sext_inreg CPURegs:$rt, vt))], NoItinerary> { + [(set RC:$rd, (sext_inreg RC:$rt, vt))], NoItinerary> { let rs = 0; let shamt = sa; let Predicates = [HasSEInReg]; } -// Byte Swap -class ByteSwap<bits<6> func, bits<5> sa, string instr_asm>: - FR<0x1f, func, (outs CPURegs:$rd), (ins CPURegs:$rt), - !strconcat(instr_asm, "\t$rd, $rt"), - [(set CPURegs:$rd, (bswap CPURegs:$rt))], NoItinerary> { +// Subword Swap +class SubwordSwap<bits<6> func, bits<5> sa, string instr_asm, RegisterClass RC>: + FR<0x1f, func, (outs RC:$rd), (ins RC:$rt), + !strconcat(instr_asm, "\t$rd, $rt"), [], NoItinerary> { let rs = 0; let shamt = sa; let Predicates = [HasSwap]; + let neverHasSideEffects = 1; } // Read Hardware -class ReadHardware: FR<0x1f, 0x3b, (outs CPURegs:$rt), (ins HWRegs:$rd), - "rdhwr\t$rt, $rd", [], IIAlu> { +class ReadHardware<RegisterClass CPURegClass, RegisterClass HWRegClass> + : FR<0x1f, 0x3b, (outs CPURegClass:$rt), (ins HWRegClass:$rd), + "rdhwr\t$rt, $rd", [], IIAlu> { let rs = 0; let shamt = 0; } // Ext and Ins -class ExtIns<bits<6> _funct, string instr_asm, dag outs, dag ins, - list<dag> pattern, InstrItinClass itin>: - FR<0x1f, _funct, outs, ins, !strconcat(instr_asm, " $rt, $rs, $pos, $sz"), - pattern, itin>, Requires<[HasMips32r2]> { +class ExtBase<bits<6> _funct, string instr_asm, RegisterClass RC>: + FR<0x1f, _funct, (outs RC:$rt), (ins RC:$rs, uimm16:$pos, size_ext:$sz), + !strconcat(instr_asm, " $rt, $rs, $pos, $sz"), + [(set RC:$rt, (MipsExt RC:$rs, imm:$pos, imm:$sz))], NoItinerary> { + bits<5> pos; + bits<5> sz; + let rd = sz; + let shamt = pos; + let Predicates = [HasMips32r2]; +} + +class InsBase<bits<6> _funct, string instr_asm, RegisterClass RC>: + FR<0x1f, _funct, (outs RC:$rt), + (ins RC:$rs, uimm16:$pos, size_ins:$sz, RC:$src), + !strconcat(instr_asm, " $rt, $rs, $pos, $sz"), + [(set RC:$rt, (MipsIns RC:$rs, imm:$pos, imm:$sz, RC:$src))], + NoItinerary> { bits<5> pos; bits<5> sz; let rd = sz; let shamt = pos; + let Predicates = [HasMips32r2]; + let Constraints = "$src = $rt"; } // Atomic instructions with 2 source operands (ATOMIC_SWAP & ATOMIC_LOAD_*). -class Atomic2Ops<PatFrag Op, string Opstr> : - MipsPseudo<(outs CPURegs:$dst), (ins CPURegs:$ptr, CPURegs:$incr), +class Atomic2Ops<PatFrag Op, string Opstr, RegisterClass DRC, + RegisterClass PRC> : + MipsPseudo<(outs DRC:$dst), (ins PRC:$ptr, DRC:$incr), !strconcat("atomic_", Opstr, "\t$dst, $ptr, $incr"), - [(set CPURegs:$dst, - (Op CPURegs:$ptr, CPURegs:$incr))]>; + [(set DRC:$dst, (Op PRC:$ptr, DRC:$incr))]>; + +multiclass Atomic2Ops32<PatFrag Op, string Opstr> { + def #NAME# : Atomic2Ops<Op, Opstr, CPURegs, CPURegs>, Requires<[NotN64]>; + def _P8 : Atomic2Ops<Op, Opstr, CPURegs, CPU64Regs>, Requires<[IsN64]>; +} // Atomic Compare & Swap. -class AtomicCmpSwap<PatFrag Op, string Width> : - MipsPseudo<(outs CPURegs:$dst), - (ins CPURegs:$ptr, CPURegs:$cmp, CPURegs:$swap), - !strconcat("atomic_cmp_swap_", Width, - "\t$dst, $ptr, $cmp, $swap"), - [(set CPURegs:$dst, - (Op CPURegs:$ptr, CPURegs:$cmp, CPURegs:$swap))]>; +class AtomicCmpSwap<PatFrag Op, string Width, RegisterClass DRC, + RegisterClass PRC> : + MipsPseudo<(outs DRC:$dst), (ins PRC:$ptr, DRC:$cmp, DRC:$swap), + !strconcat("atomic_cmp_swap_", Width, "\t$dst, $ptr, $cmp, $swap"), + [(set DRC:$dst, (Op PRC:$ptr, DRC:$cmp, DRC:$swap))]>; + +multiclass AtomicCmpSwap32<PatFrag Op, string Width> { + def #NAME# : AtomicCmpSwap<Op, Width, CPURegs, CPURegs>, Requires<[NotN64]>; + def _P8 : AtomicCmpSwap<Op, Width, CPURegs, CPU64Regs>, Requires<[IsN64]>; +} + +class LLBase<bits<6> Opc, string opstring, RegisterClass RC, Operand Mem> : + FMem<Opc, (outs RC:$rt), (ins Mem:$addr), + !strconcat(opstring, "\t$rt, $addr"), [], IILoad> { + let mayLoad = 1; +} + +class SCBase<bits<6> Opc, string opstring, RegisterClass RC, Operand Mem> : + FMem<Opc, (outs RC:$dst), (ins RC:$rt, Mem:$addr), + !strconcat(opstring, "\t$rt, $addr"), [], IIStore> { + let mayStore = 1; + let Constraints = "$rt = $dst"; +} //===----------------------------------------------------------------------===// // Pseudo instructions @@ -590,52 +727,64 @@ def ADJCALLSTACKUP : MipsPseudo<(outs), (ins uimm16:$amt1, uimm16:$amt2), [(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", []>; - -// These macros are inserted to prevent GAS from complaining -// when using the AT register. -def NOAT : MipsPseudo<(outs), (ins), ".set\tnoat", []>; -def ATMACRO : MipsPseudo<(outs), (ins), ".set\tat", []>; - // 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 i32imm:$loc), ".cprestore\t$loc", []>; +let neverHasSideEffects = 1 in +def CPRESTORE : MipsPseudo<(outs), (ins i32imm:$loc, CPURegs:$gp), + ".cprestore\t$loc", []>; + +// For O32 ABI & PIC & non-fixed global base register, the following instruction +// seqeunce is emitted to set the global base register: +// +// 0. lui $2, %hi(_gp_disp) +// 1. addiu $2, $2, %lo(_gp_disp) +// 2. addu $globalbasereg, $2, $t9 +// +// SETGP01 is emitted during Prologue/Epilogue insertion and then converted to +// instructions 0 and 1 in the sequence above during MC lowering. +// SETGP2 is emitted just before register allocation and converted to +// instruction 2 just prior to post-RA scheduling. +// +// These pseudo instructions are needed to ensure no instructions are inserted +// before or between instructions 0 and 1, which is a limitation imposed by +// GNU linker. + +let isTerminator = 1, isBarrier = 1 in +def SETGP01 : MipsPseudo<(outs CPURegs:$dst), (ins), "", []>; + +let neverHasSideEffects = 1 in +def SETGP2 : MipsPseudo<(outs CPURegs:$globalreg), (ins CPURegs:$picreg), "", + []>; let usesCustomInserter = 1 in { - def ATOMIC_LOAD_ADD_I8 : Atomic2Ops<atomic_load_add_8, "load_add_8">; - def ATOMIC_LOAD_ADD_I16 : Atomic2Ops<atomic_load_add_16, "load_add_16">; - def ATOMIC_LOAD_ADD_I32 : Atomic2Ops<atomic_load_add_32, "load_add_32">; - def ATOMIC_LOAD_SUB_I8 : Atomic2Ops<atomic_load_sub_8, "load_sub_8">; - def ATOMIC_LOAD_SUB_I16 : Atomic2Ops<atomic_load_sub_16, "load_sub_16">; - def ATOMIC_LOAD_SUB_I32 : Atomic2Ops<atomic_load_sub_32, "load_sub_32">; - def ATOMIC_LOAD_AND_I8 : Atomic2Ops<atomic_load_and_8, "load_and_8">; - def ATOMIC_LOAD_AND_I16 : Atomic2Ops<atomic_load_and_16, "load_and_16">; - def ATOMIC_LOAD_AND_I32 : Atomic2Ops<atomic_load_and_32, "load_and_32">; - def ATOMIC_LOAD_OR_I8 : Atomic2Ops<atomic_load_or_8, "load_or_8">; - def ATOMIC_LOAD_OR_I16 : Atomic2Ops<atomic_load_or_16, "load_or_16">; - def ATOMIC_LOAD_OR_I32 : Atomic2Ops<atomic_load_or_32, "load_or_32">; - def ATOMIC_LOAD_XOR_I8 : Atomic2Ops<atomic_load_xor_8, "load_xor_8">; - def ATOMIC_LOAD_XOR_I16 : Atomic2Ops<atomic_load_xor_16, "load_xor_16">; - def ATOMIC_LOAD_XOR_I32 : Atomic2Ops<atomic_load_xor_32, "load_xor_32">; - def ATOMIC_LOAD_NAND_I8 : Atomic2Ops<atomic_load_nand_8, "load_nand_8">; - def ATOMIC_LOAD_NAND_I16 : Atomic2Ops<atomic_load_nand_16, "load_nand_16">; - def ATOMIC_LOAD_NAND_I32 : Atomic2Ops<atomic_load_nand_32, "load_nand_32">; - - def ATOMIC_SWAP_I8 : Atomic2Ops<atomic_swap_8, "swap_8">; - def ATOMIC_SWAP_I16 : Atomic2Ops<atomic_swap_16, "swap_16">; - def ATOMIC_SWAP_I32 : Atomic2Ops<atomic_swap_32, "swap_32">; - - def ATOMIC_CMP_SWAP_I8 : AtomicCmpSwap<atomic_cmp_swap_8, "8">; - def ATOMIC_CMP_SWAP_I16 : AtomicCmpSwap<atomic_cmp_swap_16, "16">; - def ATOMIC_CMP_SWAP_I32 : AtomicCmpSwap<atomic_cmp_swap_32, "32">; + defm ATOMIC_LOAD_ADD_I8 : Atomic2Ops32<atomic_load_add_8, "load_add_8">; + defm ATOMIC_LOAD_ADD_I16 : Atomic2Ops32<atomic_load_add_16, "load_add_16">; + defm ATOMIC_LOAD_ADD_I32 : Atomic2Ops32<atomic_load_add_32, "load_add_32">; + defm ATOMIC_LOAD_SUB_I8 : Atomic2Ops32<atomic_load_sub_8, "load_sub_8">; + defm ATOMIC_LOAD_SUB_I16 : Atomic2Ops32<atomic_load_sub_16, "load_sub_16">; + defm ATOMIC_LOAD_SUB_I32 : Atomic2Ops32<atomic_load_sub_32, "load_sub_32">; + defm ATOMIC_LOAD_AND_I8 : Atomic2Ops32<atomic_load_and_8, "load_and_8">; + defm ATOMIC_LOAD_AND_I16 : Atomic2Ops32<atomic_load_and_16, "load_and_16">; + defm ATOMIC_LOAD_AND_I32 : Atomic2Ops32<atomic_load_and_32, "load_and_32">; + defm ATOMIC_LOAD_OR_I8 : Atomic2Ops32<atomic_load_or_8, "load_or_8">; + defm ATOMIC_LOAD_OR_I16 : Atomic2Ops32<atomic_load_or_16, "load_or_16">; + defm ATOMIC_LOAD_OR_I32 : Atomic2Ops32<atomic_load_or_32, "load_or_32">; + defm ATOMIC_LOAD_XOR_I8 : Atomic2Ops32<atomic_load_xor_8, "load_xor_8">; + defm ATOMIC_LOAD_XOR_I16 : Atomic2Ops32<atomic_load_xor_16, "load_xor_16">; + defm ATOMIC_LOAD_XOR_I32 : Atomic2Ops32<atomic_load_xor_32, "load_xor_32">; + defm ATOMIC_LOAD_NAND_I8 : Atomic2Ops32<atomic_load_nand_8, "load_nand_8">; + defm ATOMIC_LOAD_NAND_I16 : Atomic2Ops32<atomic_load_nand_16, "load_nand_16">; + defm ATOMIC_LOAD_NAND_I32 : Atomic2Ops32<atomic_load_nand_32, "load_nand_32">; + + defm ATOMIC_SWAP_I8 : Atomic2Ops32<atomic_swap_8, "swap_8">; + defm ATOMIC_SWAP_I16 : Atomic2Ops32<atomic_swap_16, "swap_16">; + defm ATOMIC_SWAP_I32 : Atomic2Ops32<atomic_swap_32, "swap_32">; + + defm ATOMIC_CMP_SWAP_I8 : AtomicCmpSwap32<atomic_cmp_swap_8, "8">; + defm ATOMIC_CMP_SWAP_I16 : AtomicCmpSwap32<atomic_cmp_swap_16, "16">; + defm ATOMIC_CMP_SWAP_I32 : AtomicCmpSwap32<atomic_cmp_swap_32, "32">; } //===----------------------------------------------------------------------===// @@ -654,7 +803,7 @@ def SLTiu : SetCC_I<0x0b, "sltiu", setult, simm16, immSExt16, CPURegs>; def ANDi : ArithLogicI<0x0c, "andi", and, uimm16, immZExt16, CPURegs>; def ORi : ArithLogicI<0x0d, "ori", or, uimm16, immZExt16, CPURegs>; def XORi : ArithLogicI<0x0e, "xori", xor, uimm16, immZExt16, CPURegs>; -def LUi : LoadUpper<0x0f, "lui">; +def LUi : LoadUpper<0x0f, "lui", CPURegs, uimm16>; /// Arithmetic Instructions (3-Operand, R-Type) def ADDu : ArithLogicR<0x00, 0x21, "addu", add, IIAlu, CPURegs, 1>; @@ -669,17 +818,17 @@ def XOR : ArithLogicR<0x00, 0x26, "xor", xor, IIAlu, CPURegs, 1>; def NOR : LogicNOR<0x00, 0x27, "nor", CPURegs>; /// Shift Instructions -def SLL : LogicR_shift_rotate_imm<0x00, 0x00, "sll", shl>; -def SRL : LogicR_shift_rotate_imm<0x02, 0x00, "srl", srl>; -def SRA : LogicR_shift_rotate_imm<0x03, 0x00, "sra", sra>; -def SLLV : LogicR_shift_rotate_reg<0x04, 0x00, "sllv", shl>; -def SRLV : LogicR_shift_rotate_reg<0x06, 0x00, "srlv", srl>; -def SRAV : LogicR_shift_rotate_reg<0x07, 0x00, "srav", sra>; +def SLL : shift_rotate_imm32<0x00, 0x00, "sll", shl>; +def SRL : shift_rotate_imm32<0x02, 0x00, "srl", srl>; +def SRA : shift_rotate_imm32<0x03, 0x00, "sra", sra>; +def SLLV : shift_rotate_reg<0x04, 0x00, "sllv", shl, CPURegs>; +def SRLV : shift_rotate_reg<0x06, 0x00, "srlv", srl, CPURegs>; +def SRAV : shift_rotate_reg<0x07, 0x00, "srav", sra, CPURegs>; // Rotate Instructions let Predicates = [HasMips32r2] in { - def ROTR : LogicR_shift_rotate_imm<0x02, 0x01, "rotr", rotr>; - def ROTRV : LogicR_shift_rotate_reg<0x06, 0x01, "rotrv", rotr>; + def ROTR : shift_rotate_imm32<0x02, 0x01, "rotr", rotr>; + def ROTRV : shift_rotate_reg<0x06, 0x01, "rotrv", rotr, CPURegs>; } /// Load and Store Instructions @@ -700,6 +849,12 @@ defm ULW : LoadM32<0x23, "ulw", load_u, 1>; defm USH : StoreM32<0x29, "ush", truncstorei16_u, 1>; defm USW : StoreM32<0x2b, "usw", store_u, 1>; +/// Primitives for unaligned +defm LWL : LoadUnAlign32<0x22>; +defm LWR : LoadUnAlign32<0x26>; +defm SWL : StoreUnAlign32<0x2A>; +defm SWR : StoreUnAlign32<0x2E>; + let hasSideEffects = 1 in def SYNC : MipsInst<(outs), (ins i32imm:$stype), "sync $stype", [(MipsSync imm:$stype)], NoItinerary, FrmOther> @@ -712,19 +867,15 @@ def SYNC : MipsInst<(outs), (ins i32imm:$stype), "sync $stype", } /// Load-linked, Store-conditional -let mayLoad = 1 in - def LL : FMem<0x30, (outs CPURegs:$rt), (ins mem:$addr), - "ll\t$rt, $addr", [], IILoad>; -let mayStore = 1, Constraints = "$rt = $dst" in - def SC : FMem<0x38, (outs CPURegs:$dst), (ins CPURegs:$rt, mem:$addr), - "sc\t$rt, $addr", [], IIStore>; +def LL : LLBase<0x30, "ll", CPURegs, mem>, Requires<[NotN64]>; +def LL_P8 : LLBase<0x30, "ll", CPURegs, mem64>, Requires<[IsN64]>; +def SC : SCBase<0x38, "sc", CPURegs, mem>, Requires<[NotN64]>; +def SC_P8 : SCBase<0x38, "sc", CPURegs, mem64>, Requires<[IsN64]>; /// Jump and Branch Instructions def J : JumpFJ<0x02, "j">; -let isIndirectBranch = 1 in - def JR : JumpFR<0x00, 0x08, "jr">; -def JAL : JumpLink<0x03, "jal">; -def JALR : JumpLinkReg<0x00, 0x09, "jalr">; +def JR : JumpFR<0x00, 0x08, "jr", CPURegs>; +def B : UncondBranch<0x04, "b">; def BEQ : CBranch<0x04, "beq", seteq, CPURegs>; def BNE : CBranch<0x05, "bne", setne, CPURegs>; def BGEZ : CBranchZero<0x01, 1, "bgez", setge, CPURegs>; @@ -732,10 +883,10 @@ def BGTZ : CBranchZero<0x07, 0, "bgtz", setgt, CPURegs>; def BLEZ : CBranchZero<0x06, 0, "blez", setle, CPURegs>; def BLTZ : CBranchZero<0x01, 0, "bltz", setlt, CPURegs>; -let rt=0x11 in - def BGEZAL : BranchLink<"bgezal">; -let rt=0x10 in - def BLTZAL : BranchLink<"bltzal">; +def JAL : JumpLink<0x03, "jal">; +def JALR : JumpLinkReg<0x00, 0x09, "jalr", CPURegs>; +def BGEZAL : BranchLink<"bgezal", 0x11, CPURegs>; +def BLTZAL : BranchLink<"bltzal", 0x10, CPURegs>; let isReturn=1, isTerminator=1, hasDelaySlot=1, isBarrier=1, hasCtrlDep=1, rd=0, rt=0, shamt=0 in @@ -743,50 +894,26 @@ let isReturn=1, isTerminator=1, hasDelaySlot=1, "jr\t$target", [(MipsRet CPURegs:$target)], IIBranch>; /// Multiply and Divide Instructions. -def MULT : Mul<0x18, "mult", IIImul>; -def MULTu : Mul<0x19, "multu", IIImul>; -def SDIV : Div<MipsDivRem, 0x1a, "div", IIIdiv>; -def UDIV : Div<MipsDivRemU, 0x1b, "divu", IIIdiv>; +def MULT : Mult32<0x18, "mult", IIImul>; +def MULTu : Mult32<0x19, "multu", IIImul>; +def SDIV : Div32<MipsDivRem, 0x1a, "div", IIIdiv>; +def UDIV : Div32<MipsDivRemU, 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">; +def MTHI : MoveToLOHI<0x11, "mthi", CPURegs, [HI]>; +def MTLO : MoveToLOHI<0x13, "mtlo", CPURegs, [LO]>; +def MFHI : MoveFromLOHI<0x10, "mfhi", CPURegs, [HI]>; +def MFLO : MoveFromLOHI<0x12, "mflo", CPURegs, [LO]>; /// Sign Ext In Register Instructions. -def SEB : SignExtInReg<0x10, "seb", i8>; -def SEH : SignExtInReg<0x18, "seh", i16>; +def SEB : SignExtInReg<0x10, "seb", i8, CPURegs>; +def SEH : SignExtInReg<0x18, "seh", i16, CPURegs>; /// Count Leading -def CLZ : CountLeading<0x20, "clz", - [(set CPURegs:$rd, (ctlz CPURegs:$rs))]>; -def CLO : CountLeading<0x21, "clo", - [(set CPURegs:$rd, (ctlz (not CPURegs:$rs)))]>; - -/// Byte Swap -def WSBW : ByteSwap<0x20, 0x2, "wsbw">; - -// Conditional moves: -// These instructions are expanded in -// MipsISelLowering::EmitInstrWithCustomInserter if target does not have -// conditional move instructions. -// flag:int, data:int -class CondMovIntInt<bits<6> funct, string instr_asm> : - FR<0, funct, (outs CPURegs:$rd), - (ins CPURegs:$rs, CPURegs:$rt, CPURegs:$F), - !strconcat(instr_asm, "\t$rd, $rs, $rt"), [], NoItinerary> { - let shamt = 0; - let usesCustomInserter = 1; - let Constraints = "$F = $rd"; -} +def CLZ : CountLeading0<0x20, "clz", CPURegs>; +def CLO : CountLeading1<0x21, "clo", CPURegs>; -def MOVZ_I : CondMovIntInt<0x0a, "movz">; -def MOVN_I : CondMovIntInt<0x0b, "movn">; +/// Word Swap Bytes Within Halfwords +def WSBH : SubwordSwap<0x20, 0x2, "wsbh", CPURegs>; /// No operation let addr=0 in @@ -796,13 +923,13 @@ let addr=0 in // 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$rt, $addr">; +def LEA_ADDiu : EffectiveAddress<"addiu\t$rt, $addr", CPURegs, mem_ea>; // DynAlloc node points to dynamically allocated stack space. // $sp is added to the list of implicitly used registers to prevent dead code // elimination from removing instructions that modify $sp. let Uses = [SP] in -def DynAlloc : EffectiveAddress<"addiu\t$rt, $addr">; +def DynAlloc : EffectiveAddress<"addiu\t$rt, $addr", CPURegs, mem_ea>; // MADD*/MSUB* def MADD : MArithR<0, "madd", MipsMAdd, 1>; @@ -815,21 +942,10 @@ def MSUBU : MArithR<5, "msubu", MipsMSubu>; def MUL : ArithLogicR<0x1c, 0x02, "mul", mul, IIImul, CPURegs, 1>, Requires<[HasMips32]>; -def RDHWR : ReadHardware; +def RDHWR : ReadHardware<CPURegs, HWRegs>; -def EXT : ExtIns<0, "ext", (outs CPURegs:$rt), - (ins CPURegs:$rs, uimm16:$pos, size_ext:$sz), - [(set CPURegs:$rt, - (MipsExt CPURegs:$rs, immZExt5:$pos, immZExt5:$sz))], - NoItinerary>; - -let Constraints = "$src = $rt" in -def INS : ExtIns<4, "ins", (outs CPURegs:$rt), - (ins CPURegs:$rs, uimm16:$pos, size_ins:$sz, CPURegs:$src), - [(set CPURegs:$rt, - (MipsIns CPURegs:$rs, immZExt5:$pos, immZExt5:$sz, - CPURegs:$src))], - NoItinerary>; +def EXT : ExtBase<0, "ext", CPURegs>; +def INS : InsBase<4, "ins", CPURegs>; //===----------------------------------------------------------------------===// // Arbitrary patterns that map to one or more instructions @@ -840,6 +956,8 @@ def : Pat<(i32 immSExt16:$in), (ADDiu ZERO, imm:$in)>; def : Pat<(i32 immZExt16:$in), (ORi ZERO, imm:$in)>; +def : Pat<(i32 immLow16Zero:$in), + (LUi (HI16 imm:$in))>; // Arbitrary immediates def : Pat<(i32 imm:$imm), @@ -864,22 +982,26 @@ def : Pat<(MipsJmpLink (i32 texternalsym:$dst)), // hi/lo relocs def : Pat<(MipsHi tglobaladdr:$in), (LUi tglobaladdr:$in)>; def : Pat<(MipsHi tblockaddress:$in), (LUi tblockaddress:$in)>; +def : Pat<(MipsHi tjumptable:$in), (LUi tjumptable:$in)>; +def : Pat<(MipsHi tconstpool:$in), (LUi tconstpool:$in)>; +def : Pat<(MipsHi tglobaltlsaddr:$in), (LUi tglobaltlsaddr:$in)>; + def : Pat<(MipsLo tglobaladdr:$in), (ADDiu ZERO, tglobaladdr:$in)>; def : Pat<(MipsLo tblockaddress:$in), (ADDiu ZERO, tblockaddress:$in)>; +def : Pat<(MipsLo tjumptable:$in), (ADDiu ZERO, tjumptable:$in)>; +def : Pat<(MipsLo tconstpool:$in), (ADDiu ZERO, tconstpool:$in)>; +def : Pat<(MipsLo tglobaltlsaddr:$in), (ADDiu ZERO, tglobaltlsaddr:$in)>; + def : Pat<(add CPURegs:$hi, (MipsLo tglobaladdr:$lo)), (ADDiu CPURegs:$hi, tglobaladdr:$lo)>; def : Pat<(add CPURegs:$hi, (MipsLo tblockaddress:$lo)), (ADDiu CPURegs:$hi, tblockaddress:$lo)>; - -def : Pat<(MipsHi tjumptable:$in), (LUi tjumptable:$in)>; -def : Pat<(MipsLo tjumptable:$in), (ADDiu ZERO, 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<(MipsLo tconstpool:$in), (ADDiu ZERO, tconstpool:$in)>; def : Pat<(add CPURegs:$hi, (MipsLo tconstpool:$lo)), (ADDiu CPURegs:$hi, tconstpool:$lo)>; +def : Pat<(add CPURegs:$hi, (MipsLo tglobaltlsaddr:$lo)), + (ADDiu CPURegs:$hi, tglobaltlsaddr:$lo)>; // gp_rel relocs def : Pat<(add CPURegs:$gp, (MipsGPRel tglobaladdr:$in)), @@ -887,39 +1009,45 @@ def : Pat<(add CPURegs:$gp, (MipsGPRel tglobaladdr:$in)), def : Pat<(add CPURegs:$gp, (MipsGPRel tconstpool:$in)), (ADDiu CPURegs:$gp, tconstpool:$in)>; -// tlsgd -def : Pat<(add CPURegs:$gp, (MipsTlsGd tglobaltlsaddr:$in)), - (ADDiu CPURegs:$gp, tglobaltlsaddr:$in)>; - -// tprel hi/lo -def : Pat<(MipsTprelHi tglobaltlsaddr:$in), (LUi tglobaltlsaddr:$in)>; -def : Pat<(MipsTprelLo tglobaltlsaddr:$in), (ADDiu ZERO, tglobaltlsaddr:$in)>; -def : Pat<(add CPURegs:$hi, (MipsTprelLo tglobaltlsaddr:$lo)), - (ADDiu CPURegs:$hi, tglobaltlsaddr:$lo)>; - // wrapper_pic -class WrapperPICPat<SDNode node>: - Pat<(MipsWrapperPIC node:$in), - (ADDiu GP, node:$in)>; +class WrapperPat<SDNode node, Instruction ADDiuOp, RegisterClass RC>: + Pat<(MipsWrapper RC:$gp, node:$in), + (ADDiuOp RC:$gp, node:$in)>; -def : WrapperPICPat<tglobaladdr>; -def : WrapperPICPat<tconstpool>; -def : WrapperPICPat<texternalsym>; -def : WrapperPICPat<tblockaddress>; -def : WrapperPICPat<tjumptable>; +def : WrapperPat<tglobaladdr, ADDiu, CPURegs>; +def : WrapperPat<tconstpool, ADDiu, CPURegs>; +def : WrapperPat<texternalsym, ADDiu, CPURegs>; +def : WrapperPat<tblockaddress, ADDiu, CPURegs>; +def : WrapperPat<tjumptable, ADDiu, CPURegs>; +def : WrapperPat<tglobaltlsaddr, ADDiu, CPURegs>; // 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_a addr:$src), (LHu addr:$src)>; -def : Pat<(extloadi16_u addr:$src), (ULHu addr:$src)>; +// extended loads +let Predicates = [NotN64] in { + def : Pat<(i32 (extloadi1 addr:$src)), (LBu addr:$src)>; + def : Pat<(i32 (extloadi8 addr:$src)), (LBu addr:$src)>; + def : Pat<(i32 (extloadi16_a addr:$src)), (LHu addr:$src)>; + def : Pat<(i32 (extloadi16_u addr:$src)), (ULHu addr:$src)>; +} +let Predicates = [IsN64] in { + def : Pat<(i32 (extloadi1 addr:$src)), (LBu_P8 addr:$src)>; + def : Pat<(i32 (extloadi8 addr:$src)), (LBu_P8 addr:$src)>; + def : Pat<(i32 (extloadi16_a addr:$src)), (LHu_P8 addr:$src)>; + def : Pat<(i32 (extloadi16_u addr:$src)), (ULHu_P8 addr:$src)>; +} // peepholes -def : Pat<(store (i32 0), addr:$dst), (SW ZERO, addr:$dst)>; +let Predicates = [NotN64] in { + def : Pat<(store_a (i32 0), addr:$dst), (SW ZERO, addr:$dst)>; + def : Pat<(store_u (i32 0), addr:$dst), (USW ZERO, addr:$dst)>; +} +let Predicates = [IsN64] in { + def : Pat<(store_a (i32 0), addr:$dst), (SW_P8 ZERO, addr:$dst)>; + def : Pat<(store_u (i32 0), addr:$dst), (USW_P8 ZERO, addr:$dst)>; +} // brcond patterns multiclass BrcondPats<RegisterClass RC, Instruction BEQOp, Instruction BNEOp, @@ -950,38 +1078,6 @@ def : Pat<(brcond RC:$cond, bb:$dst), defm : BrcondPats<CPURegs, BEQ, BNE, SLT, SLTu, SLTi, SLTiu, ZERO>; -// select patterns -multiclass MovzPats<RegisterClass RC, Instruction MOVZInst> { - def : Pat<(select (i32 (setge CPURegs:$lhs, CPURegs:$rhs)), RC:$T, RC:$F), - (MOVZInst RC:$T, (SLT CPURegs:$lhs, CPURegs:$rhs), RC:$F)>; - def : Pat<(select (i32 (setuge CPURegs:$lhs, CPURegs:$rhs)), RC:$T, RC:$F), - (MOVZInst RC:$T, (SLTu CPURegs:$lhs, CPURegs:$rhs), RC:$F)>; - def : Pat<(select (i32 (setge CPURegs:$lhs, immSExt16:$rhs)), RC:$T, RC:$F), - (MOVZInst RC:$T, (SLTi CPURegs:$lhs, immSExt16:$rhs), RC:$F)>; - def : Pat<(select (i32 (setuge CPURegs:$lh, immSExt16:$rh)), RC:$T, RC:$F), - (MOVZInst RC:$T, (SLTiu CPURegs:$lh, immSExt16:$rh), RC:$F)>; - def : Pat<(select (i32 (setle CPURegs:$lhs, CPURegs:$rhs)), RC:$T, RC:$F), - (MOVZInst RC:$T, (SLT CPURegs:$rhs, CPURegs:$lhs), RC:$F)>; - def : Pat<(select (i32 (setule CPURegs:$lhs, CPURegs:$rhs)), RC:$T, RC:$F), - (MOVZInst RC:$T, (SLTu CPURegs:$rhs, CPURegs:$lhs), RC:$F)>; - def : Pat<(select (i32 (seteq CPURegs:$lhs, CPURegs:$rhs)), RC:$T, RC:$F), - (MOVZInst RC:$T, (XOR CPURegs:$lhs, CPURegs:$rhs), RC:$F)>; - def : Pat<(select (i32 (seteq CPURegs:$lhs, 0)), RC:$T, RC:$F), - (MOVZInst RC:$T, CPURegs:$lhs, RC:$F)>; -} - -multiclass MovnPats<RegisterClass RC, Instruction MOVNInst> { - def : Pat<(select (i32 (setne CPURegs:$lhs, CPURegs:$rhs)), RC:$T, RC:$F), - (MOVNInst RC:$T, (XOR CPURegs:$lhs, CPURegs:$rhs), RC:$F)>; - def : Pat<(select CPURegs:$cond, RC:$T, RC:$F), - (MOVNInst RC:$T, CPURegs:$cond, RC:$F)>; - def : Pat<(select (i32 (setne CPURegs:$lhs, 0)), RC:$T, RC:$F), - (MOVNInst RC:$T, CPURegs:$lhs, RC:$F)>; -} - -defm : MovzPats<CPURegs, MOVZ_I>; -defm : MovnPats<CPURegs, MOVN_I>; - // setcc patterns multiclass SeteqPats<RegisterClass RC, Instruction SLTiuOp, Instruction XOROp, Instruction SLTuOp, Register ZEROReg> { @@ -1029,10 +1125,14 @@ defm : SetgeImmPats<CPURegs, SLTi, SLTiu>; // select MipsDynAlloc def : Pat<(MipsDynAlloc addr:$f), (DynAlloc addr:$f)>; +// bswap pattern +def : Pat<(bswap CPURegs:$rt), (ROTR (WSBH CPURegs:$rt), 16)>; + //===----------------------------------------------------------------------===// // Floating Point Support //===----------------------------------------------------------------------===// include "MipsInstrFPU.td" include "Mips64InstrInfo.td" +include "MipsCondMov.td" diff --git a/lib/Target/Mips/MipsJITInfo.cpp b/lib/Target/Mips/MipsJITInfo.cpp index e3f6a753c406..76ca3e176727 100644 --- a/lib/Target/Mips/MipsJITInfo.cpp +++ b/lib/Target/Mips/MipsJITInfo.cpp @@ -1,4 +1,4 @@ -//===- MipsJITInfo.cpp - Implement the JIT interfaces for the Mips target -===// +//===-- MipsJITInfo.cpp - Implement the Mips JIT Interface ----------------===// // // The LLVM Compiler Infrastructure // @@ -200,7 +200,7 @@ void MipsJITInfo::relocate(void *Function, MachineRelocation *MR, intptr_t ResultPtr = (intptr_t) MR->getResultPointer(); switch ((Mips::RelocationType) MR->getRelocationType()) { - case Mips::reloc_mips_branch: + case Mips::reloc_mips_pc16: ResultPtr = (((ResultPtr - (intptr_t) RelocPos) - 4) >> 2) & 0xffff; *((unsigned*) RelocPos) |= (unsigned) ResultPtr; break; @@ -218,13 +218,16 @@ void MipsJITInfo::relocate(void *Function, MachineRelocation *MR, *((unsigned*) RelocPos) |= (unsigned) ResultPtr; break; - case Mips::reloc_mips_lo: - ResultPtr = ResultPtr & 0xffff; + case Mips::reloc_mips_lo: { + // Addend is needed for unaligned load/store instructions, where offset + // for the second load/store in the expanded instruction sequence must + // be modified by +1 or +3. Otherwise, Addend is 0. + int Addend = *((unsigned*) RelocPos) & 0xffff; + ResultPtr = (ResultPtr + Addend) & 0xffff; + *((unsigned*) RelocPos) &= 0xffff0000; *((unsigned*) RelocPos) |= (unsigned) ResultPtr; break; - - default: - llvm_unreachable("ERROR: Unknown Mips relocation."); + } } } } diff --git a/lib/Target/Mips/MipsJITInfo.h b/lib/Target/Mips/MipsJITInfo.h index 41f32a35f1b0..f4c4ae86d38d 100644 --- a/lib/Target/Mips/MipsJITInfo.h +++ b/lib/Target/Mips/MipsJITInfo.h @@ -1,4 +1,4 @@ -//===- MipsJITInfo.h - Mips implementation of the JIT interface -*- C++ -*-===// +//===- MipsJITInfo.h - Mips Implementation of the JIT Interface -*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -19,8 +19,6 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/Target/TargetJITInfo.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallVector.h" namespace llvm { class MipsTargetMachine; diff --git a/lib/Target/Mips/MipsMCInstLower.cpp b/lib/Target/Mips/MipsMCInstLower.cpp index 608a7d21a4f9..1597b9334450 100644 --- a/lib/Target/Mips/MipsMCInstLower.cpp +++ b/lib/Target/Mips/MipsMCInstLower.cpp @@ -15,99 +15,179 @@ #include "MipsMCInstLower.h" #include "MipsAsmPrinter.h" #include "MipsInstrInfo.h" -#include "MipsMCSymbolRefExpr.h" +#include "MCTargetDesc/MipsBaseInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/Target/Mangler.h" + using namespace llvm; -MipsMCInstLower::MipsMCInstLower(Mangler *mang, const MachineFunction &mf, - MipsAsmPrinter &asmprinter) - : Ctx(mf.getContext()), Mang(mang), AsmPrinter(asmprinter) {} +MipsMCInstLower::MipsMCInstLower(MipsAsmPrinter &asmprinter) + : AsmPrinter(asmprinter) {} + +void MipsMCInstLower::Initialize(Mangler *M, MCContext* C) { + Mang = M; + Ctx = C; +} MCOperand MipsMCInstLower::LowerSymbolOperand(const MachineOperand &MO, MachineOperandType MOTy, unsigned Offset) const { - MipsMCSymbolRefExpr::VariantKind Kind; + MCSymbolRefExpr::VariantKind Kind; const MCSymbol *Symbol; switch(MO.getTargetFlags()) { - default: assert(0 && "Invalid target flag!"); - case MipsII::MO_NO_FLAG: Kind = MipsMCSymbolRefExpr::VK_Mips_None; break; - case MipsII::MO_GPREL: Kind = MipsMCSymbolRefExpr::VK_Mips_GPREL; break; - case MipsII::MO_GOT_CALL: Kind = MipsMCSymbolRefExpr::VK_Mips_GOT_CALL; break; - case MipsII::MO_GOT: Kind = MipsMCSymbolRefExpr::VK_Mips_GOT; break; - case MipsII::MO_ABS_HI: Kind = MipsMCSymbolRefExpr::VK_Mips_ABS_HI; break; - case MipsII::MO_ABS_LO: Kind = MipsMCSymbolRefExpr::VK_Mips_ABS_LO; break; - case MipsII::MO_TLSGD: Kind = MipsMCSymbolRefExpr::VK_Mips_TLSGD; break; - case MipsII::MO_GOTTPREL: Kind = MipsMCSymbolRefExpr::VK_Mips_GOTTPREL; break; - case MipsII::MO_TPREL_HI: Kind = MipsMCSymbolRefExpr::VK_Mips_TPREL_HI; break; - case MipsII::MO_TPREL_LO: Kind = MipsMCSymbolRefExpr::VK_Mips_TPREL_LO; break; - case MipsII::MO_GPOFF_HI: Kind = MipsMCSymbolRefExpr::VK_Mips_GPOFF_HI; break; - case MipsII::MO_GPOFF_LO: Kind = MipsMCSymbolRefExpr::VK_Mips_GPOFF_LO; break; - case MipsII::MO_GOT_DISP: Kind = MipsMCSymbolRefExpr::VK_Mips_GOT_DISP; break; - case MipsII::MO_GOT_PAGE: Kind = MipsMCSymbolRefExpr::VK_Mips_GOT_PAGE; break; - case MipsII::MO_GOT_OFST: Kind = MipsMCSymbolRefExpr::VK_Mips_GOT_OFST; break; + default: llvm_unreachable("Invalid target flag!"); + case MipsII::MO_NO_FLAG: Kind = MCSymbolRefExpr::VK_None; break; + case MipsII::MO_GPREL: Kind = MCSymbolRefExpr::VK_Mips_GPREL; break; + case MipsII::MO_GOT_CALL: Kind = MCSymbolRefExpr::VK_Mips_GOT_CALL; break; + case MipsII::MO_GOT16: Kind = MCSymbolRefExpr::VK_Mips_GOT16; break; + case MipsII::MO_GOT: Kind = MCSymbolRefExpr::VK_Mips_GOT; break; + case MipsII::MO_ABS_HI: Kind = MCSymbolRefExpr::VK_Mips_ABS_HI; break; + case MipsII::MO_ABS_LO: Kind = MCSymbolRefExpr::VK_Mips_ABS_LO; break; + case MipsII::MO_TLSGD: Kind = MCSymbolRefExpr::VK_Mips_TLSGD; break; + case MipsII::MO_TLSLDM: Kind = MCSymbolRefExpr::VK_Mips_TLSLDM; break; + case MipsII::MO_DTPREL_HI: Kind = MCSymbolRefExpr::VK_Mips_DTPREL_HI; break; + case MipsII::MO_DTPREL_LO: Kind = MCSymbolRefExpr::VK_Mips_DTPREL_LO; break; + case MipsII::MO_GOTTPREL: Kind = MCSymbolRefExpr::VK_Mips_GOTTPREL; break; + case MipsII::MO_TPREL_HI: Kind = MCSymbolRefExpr::VK_Mips_TPREL_HI; break; + case MipsII::MO_TPREL_LO: Kind = MCSymbolRefExpr::VK_Mips_TPREL_LO; break; + case MipsII::MO_GPOFF_HI: Kind = MCSymbolRefExpr::VK_Mips_GPOFF_HI; break; + case MipsII::MO_GPOFF_LO: Kind = MCSymbolRefExpr::VK_Mips_GPOFF_LO; break; + case MipsII::MO_GOT_DISP: Kind = MCSymbolRefExpr::VK_Mips_GOT_DISP; break; + case MipsII::MO_GOT_PAGE: Kind = MCSymbolRefExpr::VK_Mips_GOT_PAGE; break; + case MipsII::MO_GOT_OFST: Kind = MCSymbolRefExpr::VK_Mips_GOT_OFST; break; } switch (MOTy) { - case MachineOperand::MO_MachineBasicBlock: - Symbol = MO.getMBB()->getSymbol(); - break; - - case MachineOperand::MO_GlobalAddress: - Symbol = Mang->getSymbol(MO.getGlobal()); - break; - - case MachineOperand::MO_BlockAddress: - Symbol = AsmPrinter.GetBlockAddressSymbol(MO.getBlockAddress()); - break; - - case MachineOperand::MO_ExternalSymbol: - Symbol = AsmPrinter.GetExternalSymbolSymbol(MO.getSymbolName()); - break; - - case MachineOperand::MO_JumpTableIndex: - Symbol = AsmPrinter.GetJTISymbol(MO.getIndex()); - break; - - case MachineOperand::MO_ConstantPoolIndex: - Symbol = AsmPrinter.GetCPISymbol(MO.getIndex()); - if (MO.getOffset()) - Offset += MO.getOffset(); - break; - - default: - llvm_unreachable("<unknown operand type>"); + case MachineOperand::MO_MachineBasicBlock: + Symbol = MO.getMBB()->getSymbol(); + break; + + case MachineOperand::MO_GlobalAddress: + Symbol = Mang->getSymbol(MO.getGlobal()); + break; + + case MachineOperand::MO_BlockAddress: + Symbol = AsmPrinter.GetBlockAddressSymbol(MO.getBlockAddress()); + break; + + case MachineOperand::MO_ExternalSymbol: + Symbol = AsmPrinter.GetExternalSymbolSymbol(MO.getSymbolName()); + break; + + case MachineOperand::MO_JumpTableIndex: + Symbol = AsmPrinter.GetJTISymbol(MO.getIndex()); + break; + + case MachineOperand::MO_ConstantPoolIndex: + Symbol = AsmPrinter.GetCPISymbol(MO.getIndex()); + if (MO.getOffset()) + Offset += MO.getOffset(); + break; + + default: + llvm_unreachable("<unknown operand type>"); + } + + const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::Create(Symbol, Kind, *Ctx); + + if (!Offset) + return MCOperand::CreateExpr(MCSym); + + // Assume offset is never negative. + assert(Offset > 0); + + const MCConstantExpr *OffsetExpr = MCConstantExpr::Create(Offset, *Ctx); + const MCBinaryExpr *AddExpr = MCBinaryExpr::CreateAdd(MCSym, OffsetExpr, *Ctx); + return MCOperand::CreateExpr(AddExpr); +} + +static void CreateMCInst(MCInst& Inst, unsigned Opc, const MCOperand& Opnd0, + const MCOperand& Opnd1, + const MCOperand& Opnd2 = MCOperand()) { + Inst.setOpcode(Opc); + Inst.addOperand(Opnd0); + Inst.addOperand(Opnd1); + if (Opnd2.isValid()) + Inst.addOperand(Opnd2); +} + +// Lower ".cpload $reg" to +// "lui $gp, %hi(_gp_disp)" +// "addiu $gp, $gp, %lo(_gp_disp)" +// "addu $gp, $gp, $t9" +void MipsMCInstLower::LowerCPLOAD(SmallVector<MCInst, 4>& MCInsts) { + MCOperand GPReg = MCOperand::CreateReg(Mips::GP); + MCOperand T9Reg = MCOperand::CreateReg(Mips::T9); + StringRef SymName("_gp_disp"); + const MCSymbol *Sym = Ctx->GetOrCreateSymbol(SymName); + const MCSymbolRefExpr *MCSym; + + MCSym = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_Mips_ABS_HI, *Ctx); + MCOperand SymHi = MCOperand::CreateExpr(MCSym); + MCSym = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_Mips_ABS_LO, *Ctx); + MCOperand SymLo = MCOperand::CreateExpr(MCSym); + + MCInsts.resize(3); + + CreateMCInst(MCInsts[0], Mips::LUi, GPReg, SymHi); + CreateMCInst(MCInsts[1], Mips::ADDiu, GPReg, GPReg, SymLo); + CreateMCInst(MCInsts[2], Mips::ADDu, GPReg, GPReg, T9Reg); +} + +// Lower ".cprestore offset" to "sw $gp, offset($sp)". +void MipsMCInstLower::LowerCPRESTORE(int64_t Offset, + SmallVector<MCInst, 4>& MCInsts) { + assert(isInt<32>(Offset) && (Offset >= 0) && + "Imm operand of .cprestore must be a non-negative 32-bit value."); + + MCOperand SPReg = MCOperand::CreateReg(Mips::SP), BaseReg = SPReg; + MCOperand GPReg = MCOperand::CreateReg(Mips::GP); + + if (!isInt<16>(Offset)) { + unsigned Hi = ((Offset + 0x8000) >> 16) & 0xffff; + Offset &= 0xffff; + MCOperand ATReg = MCOperand::CreateReg(Mips::AT); + BaseReg = ATReg; + + // lui at,hi + // addu at,at,sp + MCInsts.resize(2); + CreateMCInst(MCInsts[0], Mips::LUi, ATReg, MCOperand::CreateImm(Hi)); + CreateMCInst(MCInsts[1], Mips::ADDu, ATReg, ATReg, SPReg); } - - return MCOperand::CreateExpr(MipsMCSymbolRefExpr::Create(Kind, Symbol, Offset, - Ctx)); + + MCInst Sw; + CreateMCInst(Sw, Mips::SW, GPReg, BaseReg, MCOperand::CreateImm(Offset)); + MCInsts.push_back(Sw); } -MCOperand MipsMCInstLower::LowerOperand(const MachineOperand& MO) const { +MCOperand MipsMCInstLower::LowerOperand(const MachineOperand& MO, + unsigned offset) const { MachineOperandType MOTy = MO.getType(); - + switch (MOTy) { - default: - assert(0 && "unknown operand type"); - break; + default: llvm_unreachable("unknown operand type"); case MachineOperand::MO_Register: // Ignore all implicit register operands. if (MO.isImplicit()) break; return MCOperand::CreateReg(MO.getReg()); case MachineOperand::MO_Immediate: - return MCOperand::CreateImm(MO.getImm()); + return MCOperand::CreateImm(MO.getImm() + offset); case MachineOperand::MO_MachineBasicBlock: case MachineOperand::MO_GlobalAddress: case MachineOperand::MO_ExternalSymbol: case MachineOperand::MO_JumpTableIndex: case MachineOperand::MO_ConstantPoolIndex: case MachineOperand::MO_BlockAddress: - return LowerSymbolOperand(MO, MOTy, 0); + return LowerSymbolOperand(MO, MOTy, offset); + case MachineOperand::MO_RegisterMask: + break; } return MCOperand(); @@ -115,7 +195,7 @@ MCOperand MipsMCInstLower::LowerOperand(const MachineOperand& MO) const { void MipsMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { OutMI.setOpcode(MI->getOpcode()); - + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { const MachineOperand &MO = MI->getOperand(i); MCOperand MCOp = LowerOperand(MO); @@ -124,3 +204,140 @@ void MipsMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { OutMI.addOperand(MCOp); } } + +void MipsMCInstLower::LowerUnalignedLoadStore(const MachineInstr *MI, + SmallVector<MCInst, + 4>& MCInsts) { + unsigned Opc = MI->getOpcode(); + MCInst Instr1, Instr2, Instr3, Move; + + bool TwoInstructions = false; + + assert(MI->getNumOperands() == 3); + assert(MI->getOperand(0).isReg()); + assert(MI->getOperand(1).isReg()); + + MCOperand Target = LowerOperand(MI->getOperand(0)); + MCOperand Base = LowerOperand(MI->getOperand(1)); + MCOperand ATReg = MCOperand::CreateReg(Mips::AT); + MCOperand ZeroReg = MCOperand::CreateReg(Mips::ZERO); + + MachineOperand UnLoweredName = MI->getOperand(2); + MCOperand Name = LowerOperand(UnLoweredName); + + Move.setOpcode(Mips::ADDu); + Move.addOperand(Target); + Move.addOperand(ATReg); + Move.addOperand(ZeroReg); + + switch (Opc) { + case Mips::ULW: { + // FIXME: only works for little endian right now + MCOperand AdjName = LowerOperand(UnLoweredName, 3); + if (Base.getReg() == (Target.getReg())) { + Instr1.setOpcode(Mips::LWL); + Instr1.addOperand(ATReg); + Instr1.addOperand(Base); + Instr1.addOperand(AdjName); + Instr2.setOpcode(Mips::LWR); + Instr2.addOperand(ATReg); + Instr2.addOperand(Base); + Instr2.addOperand(Name); + Instr3 = Move; + } else { + TwoInstructions = true; + Instr1.setOpcode(Mips::LWL); + Instr1.addOperand(Target); + Instr1.addOperand(Base); + Instr1.addOperand(AdjName); + Instr2.setOpcode(Mips::LWR); + Instr2.addOperand(Target); + Instr2.addOperand(Base); + Instr2.addOperand(Name); + } + break; + } + case Mips::ULHu: { + // FIXME: only works for little endian right now + MCOperand AdjName = LowerOperand(UnLoweredName, 1); + Instr1.setOpcode(Mips::LBu); + Instr1.addOperand(ATReg); + Instr1.addOperand(Base); + Instr1.addOperand(AdjName); + Instr2.setOpcode(Mips::LBu); + Instr2.addOperand(Target); + Instr2.addOperand(Base); + Instr2.addOperand(Name); + Instr3.setOpcode(Mips::INS); + Instr3.addOperand(Target); + Instr3.addOperand(ATReg); + Instr3.addOperand(MCOperand::CreateImm(0x8)); + Instr3.addOperand(MCOperand::CreateImm(0x18)); + break; + } + + case Mips::USW: { + // FIXME: only works for little endian right now + assert (Base.getReg() != Target.getReg()); + TwoInstructions = true; + MCOperand AdjName = LowerOperand(UnLoweredName, 3); + Instr1.setOpcode(Mips::SWL); + Instr1.addOperand(Target); + Instr1.addOperand(Base); + Instr1.addOperand(AdjName); + Instr2.setOpcode(Mips::SWR); + Instr2.addOperand(Target); + Instr2.addOperand(Base); + Instr2.addOperand(Name); + break; + } + case Mips::USH: { + MCOperand AdjName = LowerOperand(UnLoweredName, 1); + Instr1.setOpcode(Mips::SB); + Instr1.addOperand(Target); + Instr1.addOperand(Base); + Instr1.addOperand(Name); + Instr2.setOpcode(Mips::SRL); + Instr2.addOperand(ATReg); + Instr2.addOperand(Target); + Instr2.addOperand(MCOperand::CreateImm(8)); + Instr3.setOpcode(Mips::SB); + Instr3.addOperand(ATReg); + Instr3.addOperand(Base); + Instr3.addOperand(AdjName); + break; + } + default: + // FIXME: need to add others + llvm_unreachable("unaligned instruction not processed"); + } + + MCInsts.push_back(Instr1); + MCInsts.push_back(Instr2); + if (!TwoInstructions) MCInsts.push_back(Instr3); +} + +// Convert +// "setgp01 $reg" +// to +// "lui $reg, %hi(_gp_disp)" +// "addiu $reg, $reg, %lo(_gp_disp)" +void MipsMCInstLower::LowerSETGP01(const MachineInstr *MI, + SmallVector<MCInst, 4>& MCInsts) { + const MachineOperand &MO = MI->getOperand(0); + assert(MO.isReg()); + MCOperand RegOpnd = MCOperand::CreateReg(MO.getReg()); + StringRef SymName("_gp_disp"); + const MCSymbol *Sym = Ctx->GetOrCreateSymbol(SymName); + const MCSymbolRefExpr *MCSym; + + MCSym = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_Mips_ABS_HI, *Ctx); + MCOperand SymHi = MCOperand::CreateExpr(MCSym); + MCSym = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_Mips_ABS_LO, *Ctx); + MCOperand SymLo = MCOperand::CreateExpr(MCSym); + + MCInsts.resize(2); + + CreateMCInst(MCInsts[0], Mips::LUi, RegOpnd, SymHi); + CreateMCInst(MCInsts[1], Mips::ADDiu, RegOpnd, RegOpnd, SymLo); +} diff --git a/lib/Target/Mips/MipsMCInstLower.h b/lib/Target/Mips/MipsMCInstLower.h index 223f23aed286..c1d007d2f539 100644 --- a/lib/Target/Mips/MipsMCInstLower.h +++ b/lib/Target/Mips/MipsMCInstLower.h @@ -1,4 +1,4 @@ -//===-- MipsMCInstLower.h - Lower MachineInstr to MCInst -------------------==// +//===-- MipsMCInstLower.h - Lower MachineInstr to MCInst -------*- C++ -*--===// // // The LLVM Compiler Infrastructure // @@ -9,35 +9,39 @@ #ifndef MIPSMCINSTLOWER_H #define MIPSMCINSTLOWER_H +#include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/Support/Compiler.h" namespace llvm { - class MCAsmInfo; class MCContext; class MCInst; class MCOperand; - class MCSymbol; class MachineInstr; class MachineFunction; class Mangler; class MipsAsmPrinter; - + /// MipsMCInstLower - This class is used to lower an MachineInstr into an // MCInst. class LLVM_LIBRARY_VISIBILITY MipsMCInstLower { typedef MachineOperand::MachineOperandType MachineOperandType; - MCContext &Ctx; + MCContext *Ctx; Mangler *Mang; MipsAsmPrinter &AsmPrinter; public: - MipsMCInstLower(Mangler *mang, const MachineFunction &MF, - MipsAsmPrinter &asmprinter); + MipsMCInstLower(MipsAsmPrinter &asmprinter); + void Initialize(Mangler *mang, MCContext* C); void Lower(const MachineInstr *MI, MCInst &OutMI) const; + void LowerCPLOAD(SmallVector<MCInst, 4>& MCInsts); + void LowerCPRESTORE(int64_t Offset, SmallVector<MCInst, 4>& MCInsts); + void LowerUnalignedLoadStore(const MachineInstr *MI, + SmallVector<MCInst, 4>& MCInsts); + void LowerSETGP01(const MachineInstr *MI, SmallVector<MCInst, 4>& MCInsts); private: MCOperand LowerSymbolOperand(const MachineOperand &MO, MachineOperandType MOTy, unsigned Offset) const; - MCOperand LowerOperand(const MachineOperand& MO) const; + MCOperand LowerOperand(const MachineOperand& MO, unsigned offset = 0) const; }; } diff --git a/lib/Target/Mips/MipsMCSymbolRefExpr.cpp b/lib/Target/Mips/MipsMCSymbolRefExpr.cpp deleted file mode 100644 index a0a242c8c443..000000000000 --- a/lib/Target/Mips/MipsMCSymbolRefExpr.cpp +++ /dev/null @@ -1,70 +0,0 @@ -//===-- MipsMCSymbolRefExpr.cpp - Mips specific MC expression classes -----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "mipsmcsymbolrefexpr" -#include "MipsMCSymbolRefExpr.h" -#include "llvm/MC/MCAssembler.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCSymbol.h" -using namespace llvm; - -const MipsMCSymbolRefExpr* -MipsMCSymbolRefExpr::Create(VariantKind Kind, const MCSymbol *Symbol, - int Offset, MCContext &Ctx) { - return new (Ctx) MipsMCSymbolRefExpr(Kind, Symbol, Offset); -} - -void MipsMCSymbolRefExpr::PrintImpl(raw_ostream &OS) const { - switch (Kind) { - default: assert(0 && "Invalid kind!"); - case VK_Mips_None: break; - case VK_Mips_GPREL: OS << "%gp_rel("; break; - case VK_Mips_GOT_CALL: OS << "%call16("; break; - case VK_Mips_GOT: OS << "%got("; break; - case VK_Mips_ABS_HI: OS << "%hi("; break; - case VK_Mips_ABS_LO: OS << "%lo("; break; - case VK_Mips_TLSGD: OS << "%tlsgd("; break; - case VK_Mips_GOTTPREL: OS << "%gottprel("; break; - case VK_Mips_TPREL_HI: OS << "%tprel_hi("; break; - case VK_Mips_TPREL_LO: OS << "%tprel_lo("; break; - case VK_Mips_GPOFF_HI: OS << "%hi(%neg(%gp_rel("; break; - case VK_Mips_GPOFF_LO: OS << "%lo(%neg(%gp_rel("; break; - case VK_Mips_GOT_DISP: OS << "%got_disp("; break; - case VK_Mips_GOT_PAGE: OS << "%got_page("; break; - case VK_Mips_GOT_OFST: OS << "%got_ofst("; break; - } - - OS << *Symbol; - - if (Offset) { - if (Offset > 0) - OS << '+'; - OS << Offset; - } - - if (Kind == VK_Mips_GPOFF_HI || Kind == VK_Mips_GPOFF_LO) - OS << ")))"; - else if (Kind != VK_Mips_None) - OS << ')'; -} - -bool -MipsMCSymbolRefExpr::EvaluateAsRelocatableImpl(MCValue &Res, - const MCAsmLayout *Layout) const { - return false; -} - -void MipsMCSymbolRefExpr::AddValueSymbols(MCAssembler *Asm) const { - Asm->getOrCreateSymbolData(*Symbol); -} - -const MCSection *MipsMCSymbolRefExpr::FindAssociatedSection() const { - return Symbol->isDefined() ? &Symbol->getSection() : NULL; -} - diff --git a/lib/Target/Mips/MipsMCSymbolRefExpr.h b/lib/Target/Mips/MipsMCSymbolRefExpr.h deleted file mode 100644 index 55e85a79c1c8..000000000000 --- a/lib/Target/Mips/MipsMCSymbolRefExpr.h +++ /dev/null @@ -1,67 +0,0 @@ -//===-- MipsMCSymbolRefExpr.h - Mips specific MCSymbolRefExpr class -------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef MIPSMCSYMBOLREFEXPR_H -#define MIPSMCSYMBOLREFEXPR_H -#include "llvm/MC/MCExpr.h" - -namespace llvm { - -class MipsMCSymbolRefExpr : public MCTargetExpr { -public: - enum VariantKind { - VK_Mips_None, - VK_Mips_GPREL, - VK_Mips_GOT_CALL, - VK_Mips_GOT, - VK_Mips_ABS_HI, - VK_Mips_ABS_LO, - VK_Mips_TLSGD, - VK_Mips_GOTTPREL, - VK_Mips_TPREL_HI, - VK_Mips_TPREL_LO, - VK_Mips_GPOFF_HI, - VK_Mips_GPOFF_LO, - VK_Mips_GOT_DISP, - VK_Mips_GOT_PAGE, - VK_Mips_GOT_OFST - }; - -private: - const VariantKind Kind; - const MCSymbol *Symbol; - int Offset; - - explicit MipsMCSymbolRefExpr(VariantKind _Kind, const MCSymbol *_Symbol, - int _Offset) - : Kind(_Kind), Symbol(_Symbol), Offset(_Offset) {} - -public: - static const MipsMCSymbolRefExpr *Create(VariantKind Kind, - const MCSymbol *Symbol, int Offset, - MCContext &Ctx); - - void PrintImpl(raw_ostream &OS) const; - bool EvaluateAsRelocatableImpl(MCValue &Res, - const MCAsmLayout *Layout) const; - void AddValueSymbols(MCAssembler *) const; - const MCSection *FindAssociatedSection() const; - - static bool classof(const MCExpr *E) { - return E->getKind() == MCExpr::Target; - } - - static bool classof(const MipsMCSymbolRefExpr *) { return true; } - - int getOffset() const { return Offset; } - void setOffset(int O) { Offset = O; } -}; -} // end namespace llvm - -#endif diff --git a/lib/Target/Mips/MipsMachineFunction.cpp b/lib/Target/Mips/MipsMachineFunction.cpp new file mode 100644 index 000000000000..b00c62b09f4c --- /dev/null +++ b/lib/Target/Mips/MipsMachineFunction.cpp @@ -0,0 +1,50 @@ +//===-- MipsMachineFunctionInfo.cpp - Private data used for Mips ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsMachineFunction.h" +#include "MipsInstrInfo.h" +#include "MipsSubtarget.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "llvm/Function.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/CommandLine.h" + +using namespace llvm; + +static cl::opt<bool> +FixGlobalBaseReg("mips-fix-global-base-reg", cl::Hidden, cl::init(true), + cl::desc("Always use $gp as the global base register.")); + +bool MipsFunctionInfo::globalBaseRegFixed() const { + return FixGlobalBaseReg; +} + +bool MipsFunctionInfo::globalBaseRegSet() const { + return GlobalBaseReg; +} + +unsigned MipsFunctionInfo::getGlobalBaseReg() { + // Return if it has already been initialized. + if (GlobalBaseReg) + return GlobalBaseReg; + + const MipsSubtarget &ST = MF.getTarget().getSubtarget<MipsSubtarget>(); + + if (FixGlobalBaseReg) // $gp is the global base register. + return GlobalBaseReg = ST.isABI_N64() ? Mips::GP_64 : Mips::GP; + + const TargetRegisterClass *RC; + RC = ST.isABI_N64() ? + Mips::CPU64RegsRegisterClass : Mips::CPURegsRegisterClass; + + return GlobalBaseReg = MF.getRegInfo().createVirtualRegister(RC); +} + +void MipsFunctionInfo::anchor() { } diff --git a/lib/Target/Mips/MipsMachineFunction.h b/lib/Target/Mips/MipsMachineFunction.h index bc30b6b2425b..0fde55cb62e8 100644 --- a/lib/Target/Mips/MipsMachineFunction.h +++ b/lib/Target/Mips/MipsMachineFunction.h @@ -14,19 +14,17 @@ #ifndef MIPS_MACHINE_FUNCTION_INFO_H #define MIPS_MACHINE_FUNCTION_INFO_H -#include <utility> -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/VectorExtras.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFrameInfo.h" +#include <utility> namespace llvm { /// MipsFunctionInfo - This class is derived from MachineFunction private /// Mips target-specific information for each MachineFunction. class MipsFunctionInfo : public MachineFunctionInfo { + virtual void anchor(); -private: MachineFunction& MF; /// SRetReturnReg - Some subtargets require that sret lowering includes /// returning the value of the returned struct in a register. This field @@ -45,18 +43,20 @@ private: // InArgFIRange: Range of indices of all frame objects created during call to // LowerFormalArguments. // OutArgFIRange: Range of indices of all frame objects created during call to - // LowerCall except for the frame object for restoring $gp. + // LowerCall except for the frame object for restoring $gp. std::pair<int, int> InArgFIRange, OutArgFIRange; - int GPFI; // Index of the frame object for restoring $gp - mutable int DynAllocFI; // Frame index of dynamically allocated stack area. + int GPFI; // Index of the frame object for restoring $gp + mutable int DynAllocFI; // Frame index of dynamically allocated stack area. unsigned MaxCallFrameSize; + bool EmitNOAT; + public: MipsFunctionInfo(MachineFunction& MF) : MF(MF), SRetReturnReg(0), GlobalBaseReg(0), VarArgsFrameIndex(0), InArgFIRange(std::make_pair(-1, 0)), OutArgFIRange(std::make_pair(-1, 0)), GPFI(0), DynAllocFI(0), - MaxCallFrameSize(0) + MaxCallFrameSize(0), EmitNOAT(false) {} bool isInArgFI(int FI) const { @@ -64,7 +64,7 @@ public: } void setLastInArgFI(int FI) { InArgFIRange.second = FI; } - bool isOutArgFI(int FI) const { + bool isOutArgFI(int FI) const { return FI <= OutArgFIRange.first && FI >= OutArgFIRange.second; } void extendOutArgFIRange(int FirstFI, int LastFI) { @@ -92,14 +92,18 @@ public: unsigned getSRetReturnReg() const { return SRetReturnReg; } void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; } - unsigned getGlobalBaseReg() const { return GlobalBaseReg; } - void setGlobalBaseReg(unsigned Reg) { GlobalBaseReg = Reg; } + bool globalBaseRegFixed() const; + bool globalBaseRegSet() const; + unsigned getGlobalBaseReg(); int getVarArgsFrameIndex() const { return VarArgsFrameIndex; } void setVarArgsFrameIndex(int Index) { VarArgsFrameIndex = Index; } unsigned getMaxCallFrameSize() const { return MaxCallFrameSize; } void setMaxCallFrameSize(unsigned S) { MaxCallFrameSize = S; } + + bool getEmitNOAT() const { return EmitNOAT; } + void setEmitNOAT() { EmitNOAT = true; } }; } // end of namespace llvm diff --git a/lib/Target/Mips/MipsRegisterInfo.cpp b/lib/Target/Mips/MipsRegisterInfo.cpp index f8c0fdac8cf0..f30de449f6d5 100644 --- a/lib/Target/Mips/MipsRegisterInfo.cpp +++ b/lib/Target/Mips/MipsRegisterInfo.cpp @@ -1,4 +1,4 @@ -//===- MipsRegisterInfo.cpp - MIPS Register Information -== -----*- C++ -*-===// +//===-- MipsRegisterInfo.cpp - MIPS Register Information -== --------------===// // // The LLVM Compiler Infrastructure // @@ -13,9 +13,10 @@ #define DEBUG_TYPE "mips-reg-info" +#include "MipsRegisterInfo.h" #include "Mips.h" +#include "MipsAnalyzeImmediate.h" #include "MipsSubtarget.h" -#include "MipsRegisterInfo.h" #include "MipsMachineFunction.h" #include "llvm/Constants.h" #include "llvm/Type.h" @@ -45,97 +46,6 @@ MipsRegisterInfo::MipsRegisterInfo(const MipsSubtarget &ST, const TargetInstrInfo &tii) : MipsGenRegisterInfo(Mips::RA), 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::ZERO_64: case Mips::F0: case Mips::D0_64: - case Mips::D0: - return 0; - case Mips::AT: case Mips::AT_64: case Mips::F1: case Mips::D1_64: - return 1; - case Mips::V0: case Mips::V0_64: case Mips::F2: case Mips::D2_64: - case Mips::D1: - return 2; - case Mips::V1: case Mips::V1_64: case Mips::F3: case Mips::D3_64: - return 3; - case Mips::A0: case Mips::A0_64: case Mips::F4: case Mips::D4_64: - case Mips::D2: - return 4; - case Mips::A1: case Mips::A1_64: case Mips::F5: case Mips::D5_64: - return 5; - case Mips::A2: case Mips::A2_64: case Mips::F6: case Mips::D6_64: - case Mips::D3: - return 6; - case Mips::A3: case Mips::A3_64: case Mips::F7: case Mips::D7_64: - return 7; - case Mips::T0: case Mips::T0_64: case Mips::F8: case Mips::D8_64: - case Mips::D4: - return 8; - case Mips::T1: case Mips::T1_64: case Mips::F9: case Mips::D9_64: - return 9; - case Mips::T2: case Mips::T2_64: case Mips::F10: case Mips::D10_64: - case Mips::D5: - return 10; - case Mips::T3: case Mips::T3_64: case Mips::F11: case Mips::D11_64: - return 11; - case Mips::T4: case Mips::T4_64: case Mips::F12: case Mips::D12_64: - case Mips::D6: - return 12; - case Mips::T5: case Mips::T5_64: case Mips::F13: case Mips::D13_64: - return 13; - case Mips::T6: case Mips::T6_64: case Mips::F14: case Mips::D14_64: - case Mips::D7: - return 14; - case Mips::T7: case Mips::T7_64: case Mips::F15: case Mips::D15_64: - return 15; - case Mips::S0: case Mips::S0_64: case Mips::F16: case Mips::D16_64: - case Mips::D8: - return 16; - case Mips::S1: case Mips::S1_64: case Mips::F17: case Mips::D17_64: - return 17; - case Mips::S2: case Mips::S2_64: case Mips::F18: case Mips::D18_64: - case Mips::D9: - return 18; - case Mips::S3: case Mips::S3_64: case Mips::F19: case Mips::D19_64: - return 19; - case Mips::S4: case Mips::S4_64: case Mips::F20: case Mips::D20_64: - case Mips::D10: - return 20; - case Mips::S5: case Mips::S5_64: case Mips::F21: case Mips::D21_64: - return 21; - case Mips::S6: case Mips::S6_64: case Mips::F22: case Mips::D22_64: - case Mips::D11: - return 22; - case Mips::S7: case Mips::S7_64: case Mips::F23: case Mips::D23_64: - return 23; - case Mips::T8: case Mips::T8_64: case Mips::F24: case Mips::D24_64: - case Mips::D12: - return 24; - case Mips::T9: case Mips::T9_64: case Mips::F25: case Mips::D25_64: - return 25; - case Mips::K0: case Mips::K0_64: case Mips::F26: case Mips::D26_64: - case Mips::D13: - return 26; - case Mips::K1: case Mips::K1_64: case Mips::F27: case Mips::D27_64: - return 27; - case Mips::GP: case Mips::GP_64: case Mips::F28: case Mips::D28_64: - case Mips::D14: - return 28; - case Mips::SP: case Mips::SP_64: case Mips::F29: case Mips::D29_64: - return 29; - case Mips::FP: case Mips::FP_64: case Mips::F30: case Mips::D30_64: - case Mips::D15: - return 30; - case Mips::RA: case Mips::RA_64: case Mips::F31: case Mips::D31_64: - return 31; - default: llvm_unreachable("Unknown register number!"); - } - return 0; // Not reached -} - unsigned MipsRegisterInfo::getPICCallReg() { return Mips::T9; } //===----------------------------------------------------------------------===// @@ -143,71 +53,55 @@ unsigned MipsRegisterInfo::getPICCallReg() { return Mips::T9; } //===----------------------------------------------------------------------===// /// Mips Callee Saved Registers -const unsigned* MipsRegisterInfo:: +const uint16_t* MipsRegisterInfo:: getCalleeSavedRegs(const MachineFunction *MF) const { - // Mips callee-save register range is $16-$23, $f20-$f30 - static const unsigned SingleFloatOnlyCalleeSavedRegs[] = { - Mips::F31, Mips::F30, Mips::F29, Mips::F28, Mips::F27, Mips::F26, - Mips::F25, Mips::F24, Mips::F23, Mips::F22, Mips::F21, Mips::F20, - Mips::RA, Mips::FP, Mips::S7, Mips::S6, Mips::S5, Mips::S4, - Mips::S3, Mips::S2, Mips::S1, Mips::S0, 0 - }; - - static const unsigned Mips32CalleeSavedRegs[] = { - Mips::D15, Mips::D14, Mips::D13, Mips::D12, Mips::D11, Mips::D10, - Mips::RA, Mips::FP, Mips::S7, Mips::S6, Mips::S5, Mips::S4, - Mips::S3, Mips::S2, Mips::S1, Mips::S0, 0 - }; - - static const unsigned N32CalleeSavedRegs[] = { - Mips::D31_64, Mips::D29_64, Mips::D27_64, Mips::D25_64, Mips::D23_64, - Mips::D21_64, - Mips::RA_64, Mips::FP_64, Mips::GP_64, Mips::S7_64, Mips::S6_64, - Mips::S5_64, Mips::S4_64, Mips::S3_64, Mips::S2_64, Mips::S1_64, - Mips::S0_64, 0 - }; + if (Subtarget.isSingleFloat()) + return CSR_SingleFloatOnly_SaveList; + else if (!Subtarget.hasMips64()) + return CSR_O32_SaveList; + else if (Subtarget.isABI_N32()) + return CSR_N32_SaveList; - static const unsigned N64CalleeSavedRegs[] = { - Mips::D31_64, Mips::D30_64, Mips::D29_64, Mips::D28_64, Mips::D27_64, - Mips::D26_64, Mips::D25_64, Mips::D24_64, - Mips::RA_64, Mips::FP_64, Mips::GP_64, Mips::S7_64, Mips::S6_64, - Mips::S5_64, Mips::S4_64, Mips::S3_64, Mips::S2_64, Mips::S1_64, - Mips::S0_64, 0 - }; + assert(Subtarget.isABI_N64()); + return CSR_N64_SaveList; +} +const uint32_t* +MipsRegisterInfo::getCallPreservedMask(CallingConv::ID) const +{ if (Subtarget.isSingleFloat()) - return SingleFloatOnlyCalleeSavedRegs; + return CSR_SingleFloatOnly_RegMask; else if (!Subtarget.hasMips64()) - return Mips32CalleeSavedRegs; + return CSR_O32_RegMask; else if (Subtarget.isABI_N32()) - return N32CalleeSavedRegs; - + return CSR_N32_RegMask; + assert(Subtarget.isABI_N64()); - return N64CalleeSavedRegs; + return CSR_N64_RegMask; } BitVector MipsRegisterInfo:: getReservedRegs(const MachineFunction &MF) const { - static const unsigned ReservedCPURegs[] = { - Mips::ZERO, Mips::AT, Mips::K0, Mips::K1, - Mips::GP, Mips::SP, Mips::FP, Mips::RA, 0 + static const uint16_t ReservedCPURegs[] = { + Mips::ZERO, Mips::AT, Mips::K0, Mips::K1, + Mips::SP, Mips::FP, Mips::RA }; - static const unsigned ReservedCPU64Regs[] = { - Mips::ZERO_64, Mips::AT_64, Mips::K0_64, Mips::K1_64, - Mips::GP_64, Mips::SP_64, Mips::FP_64, Mips::RA_64, 0 + static const uint16_t ReservedCPU64Regs[] = { + Mips::ZERO_64, Mips::AT_64, Mips::K0_64, Mips::K1_64, + Mips::SP_64, Mips::FP_64, Mips::RA_64 }; BitVector Reserved(getNumRegs()); typedef TargetRegisterClass::iterator RegIter; - for (const unsigned *Reg = ReservedCPURegs; *Reg; ++Reg) - Reserved.set(*Reg); + for (unsigned I = 0; I < array_lengthof(ReservedCPURegs); ++I) + Reserved.set(ReservedCPURegs[I]); if (Subtarget.hasMips64()) { - for (const unsigned *Reg = ReservedCPU64Regs; *Reg; ++Reg) - Reserved.set(*Reg); + for (unsigned I = 0; I < array_lengthof(ReservedCPU64Regs); ++I) + Reserved.set(ReservedCPU64Regs[I]); // Reserve all registers in AFGR64. for (RegIter Reg = Mips::AFGR64RegisterClass->begin(); @@ -224,10 +118,25 @@ getReservedRegs(const MachineFunction &MF) const { Reg != Mips::FGR64RegisterClass->end(); ++Reg) Reserved.set(*Reg); } - + + // If GP is dedicated as a global base register, reserve it. + if (MF.getInfo<MipsFunctionInfo>()->globalBaseRegFixed()) { + Reserved.set(Mips::GP); + Reserved.set(Mips::GP_64); + } + + // Reserve hardware registers. + Reserved.set(Mips::HWR29); + Reserved.set(Mips::HWR29_64); + return Reserved; } +bool +MipsRegisterInfo::requiresRegisterScavenging(const MachineFunction &MF) const { + return true; +} + // This function eliminate ADJCALLSTACKDOWN, // ADJCALLSTACKUP pseudo instructions void MipsRegisterInfo:: @@ -259,8 +168,8 @@ eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, errs() << "<--------->\n" << MI); int FrameIndex = MI.getOperand(i).getIndex(); - int stackSize = MF.getFrameInfo()->getStackSize(); - int spOffset = MF.getFrameInfo()->getObjectOffset(FrameIndex); + uint64_t stackSize = MF.getFrameInfo()->getStackSize(); + int64_t spOffset = MF.getFrameInfo()->getObjectOffset(FrameIndex); DEBUG(errs() << "FrameIndex : " << FrameIndex << "\n" << "spOffset : " << spOffset << "\n" @@ -279,52 +188,71 @@ eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, // 1. Outgoing arguments. // 2. Pointer to dynamically allocated stack space. // 3. Locations for callee-saved registers. - // Everything else is referenced relative to whatever register + // Everything else is referenced relative to whatever register // getFrameRegister() returns. unsigned FrameReg; if (MipsFI->isOutArgFI(FrameIndex) || MipsFI->isDynAllocFI(FrameIndex) || (FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI)) - FrameReg = Mips::SP; + FrameReg = Subtarget.isABI_N64() ? Mips::SP_64 : Mips::SP; else - FrameReg = getFrameRegister(MF); - + FrameReg = getFrameRegister(MF); + // Calculate final offset. // - There is no need to change the offset if the frame object is one of the // following: an outgoing argument, pointer to a dynamically allocated // stack space or a $gp restore location, // - If the frame object is any of the following, its offset must be adjusted // by adding the size of the stack: - // incoming argument, callee-saved register location or local variable. - int Offset; + // incoming argument, callee-saved register location or local variable. + int64_t Offset; if (MipsFI->isOutArgFI(FrameIndex) || MipsFI->isGPFI(FrameIndex) || MipsFI->isDynAllocFI(FrameIndex)) Offset = spOffset; else - Offset = spOffset + stackSize; + Offset = spOffset + (int64_t)stackSize; Offset += MI.getOperand(i+1).getImm(); DEBUG(errs() << "Offset : " << Offset << "\n" << "<--------->\n"); // If MI is not a debug value, make sure Offset fits in the 16-bit immediate - // field. - if (!MI.isDebugValue() && (Offset >= 0x8000 || Offset < -0x8000)) { + // field. + if (!MI.isDebugValue() && !isInt<16>(Offset)) { MachineBasicBlock &MBB = *MI.getParent(); DebugLoc DL = II->getDebugLoc(); - int ImmHi = (((unsigned)Offset & 0xffff0000) >> 16) + - ((Offset & 0x8000) != 0); - - // FIXME: change this when mips goes MC". - BuildMI(MBB, II, DL, TII.get(Mips::NOAT)); - BuildMI(MBB, II, DL, TII.get(Mips::LUi), Mips::AT).addImm(ImmHi); - BuildMI(MBB, II, DL, TII.get(Mips::ADDu), Mips::AT).addReg(FrameReg) - .addReg(Mips::AT); - FrameReg = Mips::AT; - Offset = (short)(Offset & 0xffff); - - BuildMI(MBB, ++II, MI.getDebugLoc(), TII.get(Mips::ATMACRO)); + MipsAnalyzeImmediate AnalyzeImm; + unsigned Size = Subtarget.isABI_N64() ? 64 : 32; + unsigned LUi = Subtarget.isABI_N64() ? Mips::LUi64 : Mips::LUi; + unsigned ADDu = Subtarget.isABI_N64() ? Mips::DADDu : Mips::ADDu; + unsigned ZEROReg = Subtarget.isABI_N64() ? Mips::ZERO_64 : Mips::ZERO; + unsigned ATReg = Subtarget.isABI_N64() ? Mips::AT_64 : Mips::AT; + const MipsAnalyzeImmediate::InstSeq &Seq = + AnalyzeImm.Analyze(Offset, Size, true /* LastInstrIsADDiu */); + MipsAnalyzeImmediate::InstSeq::const_iterator Inst = Seq.begin(); + + MipsFI->setEmitNOAT(); + + // The first instruction can be a LUi, which is different from other + // instructions (ADDiu, ORI and SLL) in that it does not have a register + // operand. + if (Inst->Opc == LUi) + BuildMI(MBB, II, DL, TII.get(LUi), ATReg) + .addImm(SignExtend64<16>(Inst->ImmOpnd)); + else + BuildMI(MBB, II, DL, TII.get(Inst->Opc), ATReg).addReg(ZEROReg) + .addImm(SignExtend64<16>(Inst->ImmOpnd)); + + // Build the remaining instructions in Seq except for the last one. + for (++Inst; Inst != Seq.end() - 1; ++Inst) + BuildMI(MBB, II, DL, TII.get(Inst->Opc), ATReg).addReg(ATReg) + .addImm(SignExtend64<16>(Inst->ImmOpnd)); + + BuildMI(MBB, II, DL, TII.get(ADDu), ATReg).addReg(FrameReg).addReg(ATReg); + + FrameReg = ATReg; + Offset = SignExtend64<16>(Inst->ImmOpnd); } MI.getOperand(i).ChangeToRegister(FrameReg, false); @@ -334,18 +262,18 @@ eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, unsigned MipsRegisterInfo:: getFrameRegister(const MachineFunction &MF) const { const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); + bool IsN64 = Subtarget.isABI_N64(); - return TFI->hasFP(MF) ? Mips::FP : Mips::SP; + return TFI->hasFP(MF) ? (IsN64 ? Mips::FP_64 : Mips::FP) : + (IsN64 ? Mips::SP_64 : 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; } diff --git a/lib/Target/Mips/MipsRegisterInfo.h b/lib/Target/Mips/MipsRegisterInfo.h index 67e57dd71bdd..0716d29b2f38 100644 --- a/lib/Target/Mips/MipsRegisterInfo.h +++ b/lib/Target/Mips/MipsRegisterInfo.h @@ -1,4 +1,4 @@ -//===- MipsRegisterInfo.h - Mips Register Information Impl ------*- C++ -*-===// +//===-- MipsRegisterInfo.h - Mips Register Information Impl -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -42,10 +42,13 @@ struct MipsRegisterInfo : public MipsGenRegisterInfo { void adjustMipsStackFrame(MachineFunction &MF) const; /// Code Generation virtual methods... - const unsigned *getCalleeSavedRegs(const MachineFunction* MF = 0) const; + const uint16_t *getCalleeSavedRegs(const MachineFunction* MF = 0) const; + const uint32_t *getCallPreservedMask(CallingConv::ID) const; BitVector getReservedRegs(const MachineFunction &MF) const; + virtual bool requiresRegisterScavenging(const MachineFunction &MF) const; + void eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const; diff --git a/lib/Target/Mips/MipsRegisterInfo.td b/lib/Target/Mips/MipsRegisterInfo.td index 925ad9e70ab6..ce399a031201 100644 --- a/lib/Target/Mips/MipsRegisterInfo.td +++ b/lib/Target/Mips/MipsRegisterInfo.td @@ -1,4 +1,4 @@ -//===- MipsRegisterInfo.td - Mips Register defs ------------*- tablegen -*-===// +//===-- MipsRegisterInfo.td - Mips Register defs -----------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // @@ -50,6 +50,7 @@ class AFPR<bits<5> num, string n, list<Register> subregs> : MipsRegWithSubRegs<n, subregs> { let Num = num; let SubRegIndices = [sub_fpeven, sub_fpodd]; + let CoveredBySubRegs = 1; } class AFPR64<bits<5> num, string n, list<Register> subregs> @@ -68,8 +69,6 @@ class HWR<bits<5> num, string n> : MipsReg<n> { //===----------------------------------------------------------------------===// let Namespace = "Mips" in { - // FIXME: Fix DwarfRegNum. - // General Purpose Registers def ZERO : MipsGPRReg< 0, "ZERO">, DwarfRegNum<[0]>; def AT : MipsGPRReg< 1, "AT">, DwarfRegNum<[1]>; @@ -105,38 +104,38 @@ let Namespace = "Mips" in { def RA : MipsGPRReg< 31, "RA">, DwarfRegNum<[31]>; // General Purpose 64-bit Registers - def ZERO_64 : Mips64GPRReg< 0, "ZERO", [ZERO]>; - def AT_64 : Mips64GPRReg< 1, "AT", [AT]>; - def V0_64 : Mips64GPRReg< 2, "2", [V0]>; - def V1_64 : Mips64GPRReg< 3, "3", [V1]>; - def A0_64 : Mips64GPRReg< 4, "4", [A0]>; - def A1_64 : Mips64GPRReg< 5, "5", [A1]>; - def A2_64 : Mips64GPRReg< 6, "6", [A2]>; - def A3_64 : Mips64GPRReg< 7, "7", [A3]>; - def T0_64 : Mips64GPRReg< 8, "8", [T0]>; - def T1_64 : Mips64GPRReg< 9, "9", [T1]>; - def T2_64 : Mips64GPRReg< 10, "10", [T2]>; - def T3_64 : Mips64GPRReg< 11, "11", [T3]>; - def T4_64 : Mips64GPRReg< 12, "12", [T4]>; - def T5_64 : Mips64GPRReg< 13, "13", [T5]>; - def T6_64 : Mips64GPRReg< 14, "14", [T6]>; - def T7_64 : Mips64GPRReg< 15, "15", [T7]>; - def S0_64 : Mips64GPRReg< 16, "16", [S0]>; - def S1_64 : Mips64GPRReg< 17, "17", [S1]>; - def S2_64 : Mips64GPRReg< 18, "18", [S2]>; - def S3_64 : Mips64GPRReg< 19, "19", [S3]>; - def S4_64 : Mips64GPRReg< 20, "20", [S4]>; - def S5_64 : Mips64GPRReg< 21, "21", [S5]>; - def S6_64 : Mips64GPRReg< 22, "22", [S6]>; - def S7_64 : Mips64GPRReg< 23, "23", [S7]>; - def T8_64 : Mips64GPRReg< 24, "24", [T8]>; - def T9_64 : Mips64GPRReg< 25, "25", [T9]>; - def K0_64 : Mips64GPRReg< 26, "26", [K0]>; - def K1_64 : Mips64GPRReg< 27, "27", [K1]>; - def GP_64 : Mips64GPRReg< 28, "GP", [GP]>; - def SP_64 : Mips64GPRReg< 29, "SP", [SP]>; - def FP_64 : Mips64GPRReg< 30, "FP", [FP]>; - def RA_64 : Mips64GPRReg< 31, "RA", [RA]>; + def ZERO_64 : Mips64GPRReg< 0, "ZERO", [ZERO]>, DwarfRegNum<[0]>; + def AT_64 : Mips64GPRReg< 1, "AT", [AT]>, DwarfRegNum<[1]>; + def V0_64 : Mips64GPRReg< 2, "2", [V0]>, DwarfRegNum<[2]>; + def V1_64 : Mips64GPRReg< 3, "3", [V1]>, DwarfRegNum<[3]>; + def A0_64 : Mips64GPRReg< 4, "4", [A0]>, DwarfRegNum<[4]>; + def A1_64 : Mips64GPRReg< 5, "5", [A1]>, DwarfRegNum<[5]>; + def A2_64 : Mips64GPRReg< 6, "6", [A2]>, DwarfRegNum<[6]>; + def A3_64 : Mips64GPRReg< 7, "7", [A3]>, DwarfRegNum<[7]>; + def T0_64 : Mips64GPRReg< 8, "8", [T0]>, DwarfRegNum<[8]>; + def T1_64 : Mips64GPRReg< 9, "9", [T1]>, DwarfRegNum<[9]>; + def T2_64 : Mips64GPRReg< 10, "10", [T2]>, DwarfRegNum<[10]>; + def T3_64 : Mips64GPRReg< 11, "11", [T3]>, DwarfRegNum<[11]>; + def T4_64 : Mips64GPRReg< 12, "12", [T4]>, DwarfRegNum<[12]>; + def T5_64 : Mips64GPRReg< 13, "13", [T5]>, DwarfRegNum<[13]>; + def T6_64 : Mips64GPRReg< 14, "14", [T6]>, DwarfRegNum<[14]>; + def T7_64 : Mips64GPRReg< 15, "15", [T7]>, DwarfRegNum<[15]>; + def S0_64 : Mips64GPRReg< 16, "16", [S0]>, DwarfRegNum<[16]>; + def S1_64 : Mips64GPRReg< 17, "17", [S1]>, DwarfRegNum<[17]>; + def S2_64 : Mips64GPRReg< 18, "18", [S2]>, DwarfRegNum<[18]>; + def S3_64 : Mips64GPRReg< 19, "19", [S3]>, DwarfRegNum<[19]>; + def S4_64 : Mips64GPRReg< 20, "20", [S4]>, DwarfRegNum<[20]>; + def S5_64 : Mips64GPRReg< 21, "21", [S5]>, DwarfRegNum<[21]>; + def S6_64 : Mips64GPRReg< 22, "22", [S6]>, DwarfRegNum<[22]>; + def S7_64 : Mips64GPRReg< 23, "23", [S7]>, DwarfRegNum<[23]>; + def T8_64 : Mips64GPRReg< 24, "24", [T8]>, DwarfRegNum<[24]>; + def T9_64 : Mips64GPRReg< 25, "25", [T9]>, DwarfRegNum<[25]>; + def K0_64 : Mips64GPRReg< 26, "26", [K0]>, DwarfRegNum<[26]>; + def K1_64 : Mips64GPRReg< 27, "27", [K1]>, DwarfRegNum<[27]>; + def GP_64 : Mips64GPRReg< 28, "GP", [GP]>, DwarfRegNum<[28]>; + def SP_64 : Mips64GPRReg< 29, "SP", [SP]>, DwarfRegNum<[29]>; + def FP_64 : Mips64GPRReg< 30, "FP", [FP]>, DwarfRegNum<[30]>; + def RA_64 : Mips64GPRReg< 31, "RA", [RA]>, DwarfRegNum<[31]>; /// Mips Single point precision FPU Registers def F0 : FPR< 0, "F0">, DwarfRegNum<[32]>; @@ -192,38 +191,38 @@ let Namespace = "Mips" in { def D15 : AFPR<30, "F30", [F30, F31]>; /// Mips Double point precision FPU Registers in MFP64 mode. - def D0_64 : AFPR64<0, "F0", [F0]>; - def D1_64 : AFPR64<1, "F1", [F1]>; - def D2_64 : AFPR64<2, "F2", [F2]>; - def D3_64 : AFPR64<3, "F3", [F3]>; - def D4_64 : AFPR64<4, "F4", [F4]>; - def D5_64 : AFPR64<5, "F5", [F5]>; - def D6_64 : AFPR64<6, "F6", [F6]>; - def D7_64 : AFPR64<7, "F7", [F7]>; - def D8_64 : AFPR64<8, "F8", [F8]>; - def D9_64 : AFPR64<9, "F9", [F9]>; - def D10_64 : AFPR64<10, "F10", [F10]>; - def D11_64 : AFPR64<11, "F11", [F11]>; - def D12_64 : AFPR64<12, "F12", [F12]>; - def D13_64 : AFPR64<13, "F13", [F13]>; - def D14_64 : AFPR64<14, "F14", [F14]>; - def D15_64 : AFPR64<15, "F15", [F15]>; - def D16_64 : AFPR64<16, "F16", [F16]>; - def D17_64 : AFPR64<17, "F17", [F17]>; - def D18_64 : AFPR64<18, "F18", [F18]>; - def D19_64 : AFPR64<19, "F19", [F19]>; - def D20_64 : AFPR64<20, "F20", [F20]>; - def D21_64 : AFPR64<21, "F21", [F21]>; - def D22_64 : AFPR64<22, "F22", [F22]>; - def D23_64 : AFPR64<23, "F23", [F23]>; - def D24_64 : AFPR64<24, "F24", [F24]>; - def D25_64 : AFPR64<25, "F25", [F25]>; - def D26_64 : AFPR64<26, "F26", [F26]>; - def D27_64 : AFPR64<27, "F27", [F27]>; - def D28_64 : AFPR64<28, "F28", [F28]>; - def D29_64 : AFPR64<29, "F29", [F29]>; - def D30_64 : AFPR64<30, "F30", [F30]>; - def D31_64 : AFPR64<31, "F31", [F31]>; + def D0_64 : AFPR64<0, "F0", [F0]>, DwarfRegNum<[32]>; + def D1_64 : AFPR64<1, "F1", [F1]>, DwarfRegNum<[33]>; + def D2_64 : AFPR64<2, "F2", [F2]>, DwarfRegNum<[34]>; + def D3_64 : AFPR64<3, "F3", [F3]>, DwarfRegNum<[35]>; + def D4_64 : AFPR64<4, "F4", [F4]>, DwarfRegNum<[36]>; + def D5_64 : AFPR64<5, "F5", [F5]>, DwarfRegNum<[37]>; + def D6_64 : AFPR64<6, "F6", [F6]>, DwarfRegNum<[38]>; + def D7_64 : AFPR64<7, "F7", [F7]>, DwarfRegNum<[39]>; + def D8_64 : AFPR64<8, "F8", [F8]>, DwarfRegNum<[40]>; + def D9_64 : AFPR64<9, "F9", [F9]>, DwarfRegNum<[41]>; + def D10_64 : AFPR64<10, "F10", [F10]>, DwarfRegNum<[42]>; + def D11_64 : AFPR64<11, "F11", [F11]>, DwarfRegNum<[43]>; + def D12_64 : AFPR64<12, "F12", [F12]>, DwarfRegNum<[44]>; + def D13_64 : AFPR64<13, "F13", [F13]>, DwarfRegNum<[45]>; + def D14_64 : AFPR64<14, "F14", [F14]>, DwarfRegNum<[46]>; + def D15_64 : AFPR64<15, "F15", [F15]>, DwarfRegNum<[47]>; + def D16_64 : AFPR64<16, "F16", [F16]>, DwarfRegNum<[48]>; + def D17_64 : AFPR64<17, "F17", [F17]>, DwarfRegNum<[49]>; + def D18_64 : AFPR64<18, "F18", [F18]>, DwarfRegNum<[50]>; + def D19_64 : AFPR64<19, "F19", [F19]>, DwarfRegNum<[51]>; + def D20_64 : AFPR64<20, "F20", [F20]>, DwarfRegNum<[52]>; + def D21_64 : AFPR64<21, "F21", [F21]>, DwarfRegNum<[53]>; + def D22_64 : AFPR64<22, "F22", [F22]>, DwarfRegNum<[54]>; + def D23_64 : AFPR64<23, "F23", [F23]>, DwarfRegNum<[55]>; + def D24_64 : AFPR64<24, "F24", [F24]>, DwarfRegNum<[56]>; + def D25_64 : AFPR64<25, "F25", [F25]>, DwarfRegNum<[57]>; + def D26_64 : AFPR64<26, "F26", [F26]>, DwarfRegNum<[58]>; + def D27_64 : AFPR64<27, "F27", [F27]>, DwarfRegNum<[59]>; + def D28_64 : AFPR64<28, "F28", [F28]>, DwarfRegNum<[60]>; + def D29_64 : AFPR64<29, "F29", [F29]>, DwarfRegNum<[61]>; + def D30_64 : AFPR64<30, "F30", [F30]>, DwarfRegNum<[62]>; + def D31_64 : AFPR64<31, "F31", [F31]>, DwarfRegNum<[63]>; // Hi/Lo registers def HI : Register<"hi">, DwarfRegNum<[64]>; @@ -239,6 +238,7 @@ let Namespace = "Mips" in { // Hardware register $29 def HWR29 : Register<"29">; + def HWR29_64 : Register<"29">; } //===----------------------------------------------------------------------===// @@ -301,3 +301,5 @@ def HILO64 : RegisterClass<"Mips", [i64], 64, (add HI64, LO64)> { // Hardware registers def HWRegs : RegisterClass<"Mips", [i32], 32, (add HWR29)>; +def HWRegs64 : RegisterClass<"Mips", [i64], 32, (add HWR29_64)>; + diff --git a/lib/Target/Mips/MipsRelocations.h b/lib/Target/Mips/MipsRelocations.h index 66d1bfd993f5..0787ed399d5f 100644 --- a/lib/Target/Mips/MipsRelocations.h +++ b/lib/Target/Mips/MipsRelocations.h @@ -1,16 +1,16 @@ -//===- MipsRelocations.h - Mips Code Relocations ---------------*- C++ -*-===// +//===-- MipsRelocations.h - Mips Code Relocations ---------------*- 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 target-specific relocation types // (for relocation-model=static). // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #ifndef MIPSRELOCATIONS_H_ #define MIPSRELOCATIONS_H_ @@ -20,10 +20,10 @@ namespace llvm { namespace Mips{ enum RelocationType { - // reloc_mips_branch - pc relative relocation for branches. The lower 18 + // reloc_mips_pc16 - pc relative relocation for branches. The lower 18 // bits of the difference between the branch target and the branch // instruction, shifted right by 2. - reloc_mips_branch = 1, + reloc_mips_pc16 = 1, // reloc_mips_hi - upper 16 bits of the address (modified by +1 if the // lower 16 bits of the address is negative). diff --git a/lib/Target/Mips/MipsSchedule.td b/lib/Target/Mips/MipsSchedule.td index 00be8ee94431..1add02ff83e9 100644 --- a/lib/Target/Mips/MipsSchedule.td +++ b/lib/Target/Mips/MipsSchedule.td @@ -1,4 +1,4 @@ -//===- MipsSchedule.td - Mips Scheduling Definitions -------*- tablegen -*-===// +//===-- MipsSchedule.td - Mips Scheduling Definitions ------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/Mips/MipsSubtarget.cpp b/lib/Target/Mips/MipsSubtarget.cpp index 016d449a1067..00347df9ac84 100644 --- a/lib/Target/Mips/MipsSubtarget.cpp +++ b/lib/Target/Mips/MipsSubtarget.cpp @@ -1,4 +1,4 @@ -//===- MipsSubtarget.cpp - Mips Subtarget Information -----------*- C++ -*-===// +//===-- MipsSubtarget.cpp - Mips Subtarget Information --------------------===// // // The LLVM Compiler Infrastructure // @@ -13,6 +13,7 @@ #include "MipsSubtarget.h" #include "Mips.h" +#include "MipsRegisterInfo.h" #include "llvm/Support/TargetRegistry.h" #define GET_SUBTARGETINFO_TARGET_DESC @@ -21,17 +22,19 @@ using namespace llvm; +void MipsSubtarget::anchor() { } + MipsSubtarget::MipsSubtarget(const std::string &TT, const std::string &CPU, const std::string &FS, bool little) : MipsGenSubtargetInfo(TT, CPU, FS), - MipsArchVersion(Mips32), MipsABI(UnknownABI), IsLittle(little), + MipsArchVersion(Mips32), MipsABI(UnknownABI), 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 CPUName = CPU; if (CPUName.empty()) - CPUName = "mips32r1"; + CPUName = "mips32"; // Parse features string. ParseSubtargetFeatures(CPUName, FS); @@ -41,7 +44,7 @@ MipsSubtarget::MipsSubtarget(const std::string &TT, const std::string &CPU, // Set MipsABI if it hasn't been set yet. if (MipsABI == UnknownABI) - MipsABI = hasMips64() ? N64 : O32; + MipsABI = hasMips64() ? N64 : O32; // Check if Architecture and ABI are compatible. assert(((!hasMips64() && (isABI_O32() || isABI_EABI())) || @@ -52,3 +55,14 @@ MipsSubtarget::MipsSubtarget(const std::string &TT, const std::string &CPU, if (TT.find("linux") == std::string::npos) IsLinux = false; } + +bool +MipsSubtarget::enablePostRAScheduler(CodeGenOpt::Level OptLevel, + TargetSubtargetInfo::AntiDepBreakMode& Mode, + RegClassVector& CriticalPathRCs) const { + Mode = TargetSubtargetInfo::ANTIDEP_CRITICAL; + CriticalPathRCs.clear(); + CriticalPathRCs.push_back(hasMips64() ? + &Mips::CPU64RegsRegClass : &Mips::CPURegsRegClass); + return OptLevel >= CodeGenOpt::Aggressive; +} diff --git a/lib/Target/Mips/MipsSubtarget.h b/lib/Target/Mips/MipsSubtarget.h index d9dddad23a48..7faf77baa650 100644 --- a/lib/Target/Mips/MipsSubtarget.h +++ b/lib/Target/Mips/MipsSubtarget.h @@ -1,4 +1,4 @@ -//=====-- MipsSubtarget.h - Define Subtarget for the Mips -----*- C++ -*--====// +//===-- MipsSubtarget.h - Define Subtarget for the Mips ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -25,6 +25,7 @@ namespace llvm { class StringRef; class MipsSubtarget : public MipsGenSubtargetInfo { + virtual void anchor(); public: // NOTE: O64 will not be supported. @@ -88,6 +89,9 @@ protected: InstrItineraryData InstrItins; public: + virtual bool enablePostRAScheduler(CodeGenOpt::Level OptLevel, + AntiDepBreakMode& Mode, + RegClassVector& CriticalPathRCs) const; /// Only O32 and EABI supported right now. bool isABI_EABI() const { return MipsABI == EABI; } @@ -111,6 +115,8 @@ public: bool hasMips64() const { return MipsArchVersion >= Mips64; } bool hasMips64r2() const { return MipsArchVersion == Mips64r2; } + bool hasMips32r2Or64() const { return hasMips32r2() || hasMips64(); } + bool isLittle() const { return IsLittle; } bool isFP64bit() const { return IsFP64bit; } bool isGP64bit() const { return IsGP64bit; } diff --git a/lib/Target/Mips/MipsTargetMachine.cpp b/lib/Target/Mips/MipsTargetMachine.cpp index 6480da3e6dfc..ad022311ed7d 100644 --- a/lib/Target/Mips/MipsTargetMachine.cpp +++ b/lib/Target/Mips/MipsTargetMachine.cpp @@ -11,9 +11,10 @@ // //===----------------------------------------------------------------------===// -#include "Mips.h" #include "MipsTargetMachine.h" +#include "Mips.h" #include "llvm/PassManager.h" +#include "llvm/CodeGen/Passes.h" #include "llvm/Support/TargetRegistry.h" using namespace llvm; @@ -34,86 +35,119 @@ extern "C" void LLVMInitializeMipsTarget() { // Using CodeModel::Large enables different CALL behavior. MipsTargetMachine:: MipsTargetMachine(const Target &T, StringRef TT, - StringRef CPU, StringRef FS, + StringRef CPU, StringRef FS, const TargetOptions &Options, Reloc::Model RM, CodeModel::Model CM, - bool isLittle): - LLVMTargetMachine(T, TT, CPU, FS, RM, CM), - Subtarget(TT, CPU, FS, isLittle), - DataLayout(isLittle ? - (Subtarget.isABI_N64() ? - "e-p:64:64:64-i8:8:32-i16:16:32-i64:64:64-f128:128:128-n32" : - "e-p:32:32:32-i8:8:32-i16:16:32-i64:64:64-n32") : - (Subtarget.isABI_N64() ? - "E-p:64:64:64-i8:8:32-i16:16:32-i64:64:64-f128:128:128-n32" : - "E-p:32:32:32-i8:8:32-i16:16:32-i64:64:64-n32")), - InstrInfo(*this), - FrameLowering(Subtarget), - TLInfo(*this), TSInfo(*this), JITInfo() { + CodeGenOpt::Level OL, + bool isLittle) + : LLVMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL), + Subtarget(TT, CPU, FS, isLittle), + DataLayout(isLittle ? + (Subtarget.isABI_N64() ? + "e-p:64:64:64-i8:8:32-i16:16:32-i64:64:64-f128:128:128-n32" : + "e-p:32:32:32-i8:8:32-i16:16:32-i64:64:64-n32") : + (Subtarget.isABI_N64() ? + "E-p:64:64:64-i8:8:32-i16:16:32-i64:64:64-f128:128:128-n32" : + "E-p:32:32:32-i8:8:32-i16:16:32-i64:64:64-n32")), + InstrInfo(*this), + FrameLowering(Subtarget), + TLInfo(*this), TSInfo(*this), JITInfo() { } +void MipsebTargetMachine::anchor() { } + MipsebTargetMachine:: MipsebTargetMachine(const Target &T, StringRef TT, - StringRef CPU, StringRef FS, - Reloc::Model RM, CodeModel::Model CM) : - MipsTargetMachine(T, TT, CPU, FS, RM, CM, false) {} + StringRef CPU, StringRef FS, const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL) + : MipsTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {} + +void MipselTargetMachine::anchor() { } MipselTargetMachine:: MipselTargetMachine(const Target &T, StringRef TT, - StringRef CPU, StringRef FS, - Reloc::Model RM, CodeModel::Model CM) : - MipsTargetMachine(T, TT, CPU, FS, RM, CM, true) {} + StringRef CPU, StringRef FS, const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL) + : MipsTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, true) {} + +void Mips64ebTargetMachine::anchor() { } Mips64ebTargetMachine:: Mips64ebTargetMachine(const Target &T, StringRef TT, - StringRef CPU, StringRef FS, - Reloc::Model RM, CodeModel::Model CM) : - MipsTargetMachine(T, TT, CPU, FS, RM, CM, false) {} + StringRef CPU, StringRef FS, const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL) + : MipsTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {} + +void Mips64elTargetMachine::anchor() { } Mips64elTargetMachine:: Mips64elTargetMachine(const Target &T, StringRef TT, - StringRef CPU, StringRef FS, - Reloc::Model RM, CodeModel::Model CM) : - MipsTargetMachine(T, TT, CPU, FS, RM, CM, true) {} + StringRef CPU, StringRef FS, const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL) + : MipsTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, true) {} + +namespace { +/// Mips Code Generator Pass Configuration Options. +class MipsPassConfig : public TargetPassConfig { +public: + MipsPassConfig(MipsTargetMachine *TM, PassManagerBase &PM) + : TargetPassConfig(TM, PM) {} + + MipsTargetMachine &getMipsTargetMachine() const { + return getTM<MipsTargetMachine>(); + } + + const MipsSubtarget &getMipsSubtarget() const { + return *getMipsTargetMachine().getSubtargetImpl(); + } + + virtual bool addInstSelector(); + virtual bool addPreRegAlloc(); + virtual bool addPreSched2(); + virtual bool addPreEmitPass(); +}; +} // namespace + +TargetPassConfig *MipsTargetMachine::createPassConfig(PassManagerBase &PM) { + return new MipsPassConfig(this, PM); +} // Install an instruction selector pass using // the ISelDag to gen Mips code. -bool MipsTargetMachine:: -addInstSelector(PassManagerBase &PM, CodeGenOpt::Level OptLevel) +bool MipsPassConfig::addInstSelector() { - PM.add(createMipsISelDag(*this)); + PM.add(createMipsISelDag(getMipsTargetMachine())); 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) +bool MipsPassConfig::addPreEmitPass() { - PM.add(createMipsDelaySlotFillerPass(*this)); + PM.add(createMipsDelaySlotFillerPass(getMipsTargetMachine())); return true; } -bool MipsTargetMachine:: -addPreRegAlloc(PassManagerBase &PM, CodeGenOpt::Level OptLevel) { +bool MipsPassConfig::addPreRegAlloc() { // Do not restore $gp if target is Mips64. // In N32/64, $gp is a callee-saved register. - if (!Subtarget.hasMips64()) - PM.add(createMipsEmitGPRestorePass(*this)); + if (!getMipsSubtarget().hasMips64()) + PM.add(createMipsEmitGPRestorePass(getMipsTargetMachine())); return true; } -bool MipsTargetMachine:: -addPostRegAlloc(PassManagerBase &PM, CodeGenOpt::Level OptLevel) { - PM.add(createMipsExpandPseudoPass(*this)); +bool MipsPassConfig::addPreSched2() { + PM.add(createMipsExpandPseudoPass(getMipsTargetMachine())); return true; } bool MipsTargetMachine::addCodeEmitter(PassManagerBase &PM, - CodeGenOpt::Level OptLevel, - JITCodeEmitter &JCE) { + JITCodeEmitter &JCE) { // Machine code emitter pass for Mips. PM.add(createMipsJITCodeEmitterPass(*this, JCE)); return false; } - diff --git a/lib/Target/Mips/MipsTargetMachine.h b/lib/Target/Mips/MipsTargetMachine.h index 118ed107c514..80c00e80f12c 100644 --- a/lib/Target/Mips/MipsTargetMachine.h +++ b/lib/Target/Mips/MipsTargetMachine.h @@ -1,4 +1,4 @@ -//===-- MipsTargetMachine.h - Define TargetMachine for Mips -00--*- C++ -*-===// +//===-- MipsTargetMachine.h - Define TargetMachine for Mips -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,15 +14,15 @@ #ifndef MIPSTARGETMACHINE_H #define MIPSTARGETMACHINE_H -#include "MipsSubtarget.h" +#include "MipsFrameLowering.h" #include "MipsInstrInfo.h" #include "MipsISelLowering.h" -#include "MipsFrameLowering.h" +#include "MipsJITInfo.h" #include "MipsSelectionDAGInfo.h" +#include "MipsSubtarget.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetFrameLowering.h" -#include "MipsJITInfo.h" namespace llvm { class formatted_raw_ostream; @@ -38,8 +38,9 @@ namespace llvm { public: MipsTargetMachine(const Target &T, StringRef TT, - StringRef CPU, StringRef FS, + StringRef CPU, StringRef FS, const TargetOptions &Options, Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL, bool isLittle); virtual const MipsInstrInfo *getInstrInfo() const @@ -67,15 +68,8 @@ namespace llvm { } // Pass Pipeline Configuration - virtual bool addInstSelector(PassManagerBase &PM, - CodeGenOpt::Level OptLevel); - virtual bool addPreEmitPass(PassManagerBase &PM, - CodeGenOpt::Level OptLevel); - virtual bool addPreRegAlloc(PassManagerBase &PM, - CodeGenOpt::Level OptLevel); - virtual bool addPostRegAlloc(PassManagerBase &, CodeGenOpt::Level); + virtual TargetPassConfig *createPassConfig(PassManagerBase &PM); virtual bool addCodeEmitter(PassManagerBase &PM, - CodeGenOpt::Level OptLevel, JITCodeEmitter &JCE); }; @@ -83,37 +77,47 @@ namespace llvm { /// MipsebTargetMachine - Mips32 big endian target machine. /// class MipsebTargetMachine : public MipsTargetMachine { + virtual void anchor(); public: MipsebTargetMachine(const Target &T, StringRef TT, - StringRef CPU, StringRef FS, - Reloc::Model RM, CodeModel::Model CM); + StringRef CPU, StringRef FS, const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL); }; /// MipselTargetMachine - Mips32 little endian target machine. /// class MipselTargetMachine : public MipsTargetMachine { + virtual void anchor(); public: MipselTargetMachine(const Target &T, StringRef TT, - StringRef CPU, StringRef FS, - Reloc::Model RM, CodeModel::Model CM); + StringRef CPU, StringRef FS, const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL); }; /// Mips64ebTargetMachine - Mips64 big endian target machine. /// class Mips64ebTargetMachine : public MipsTargetMachine { + virtual void anchor(); public: Mips64ebTargetMachine(const Target &T, StringRef TT, StringRef CPU, StringRef FS, - Reloc::Model RM, CodeModel::Model CM); + const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL); }; /// Mips64elTargetMachine - Mips64 little endian target machine. /// class Mips64elTargetMachine : public MipsTargetMachine { + virtual void anchor(); public: Mips64elTargetMachine(const Target &T, StringRef TT, StringRef CPU, StringRef FS, - Reloc::Model RM, CodeModel::Model CM); + const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL); }; } // End llvm namespace diff --git a/lib/Target/Mips/MipsTargetObjectFile.cpp b/lib/Target/Mips/MipsTargetObjectFile.cpp index 05c46f5c97a5..04dc60aa6b45 100644 --- a/lib/Target/Mips/MipsTargetObjectFile.cpp +++ b/lib/Target/Mips/MipsTargetObjectFile.cpp @@ -1,4 +1,4 @@ -//===-- MipsTargetObjectFile.cpp - Mips object files ----------------------===// +//===-- MipsTargetObjectFile.cpp - Mips Object Files ----------------------===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/Mips/TargetInfo/CMakeLists.txt b/lib/Target/Mips/TargetInfo/CMakeLists.txt index 5692604504a8..4172d00a33f0 100644 --- a/lib/Target/Mips/TargetInfo/CMakeLists.txt +++ b/lib/Target/Mips/TargetInfo/CMakeLists.txt @@ -4,10 +4,4 @@ add_llvm_library(LLVMMipsInfo MipsTargetInfo.cpp ) -add_llvm_library_dependencies(LLVMMipsInfo - LLVMMC - LLVMSupport - LLVMTarget - ) - add_dependencies(LLVMMipsInfo MipsCommonTableGen) diff --git a/lib/Target/Mips/TargetInfo/LLVMBuild.txt b/lib/Target/Mips/TargetInfo/LLVMBuild.txt new file mode 100644 index 000000000000..2d425686227f --- /dev/null +++ b/lib/Target/Mips/TargetInfo/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/Mips/TargetInfo/LLVMBuild.txt ---------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = MipsInfo +parent = Mips +required_libraries = MC Support Target +add_to_library_groups = Mips |