diff options
author | Stephen Hines <srhines@google.com> | 2014-02-11 20:01:10 -0800 |
---|---|---|
committer | Stephen Hines <srhines@google.com> | 2014-02-11 20:01:10 -0800 |
commit | ce9904c6ea8fd669978a8eefb854b330eb9828ff (patch) | |
tree | 2418ee2e96ea220977c8fb74959192036ab5b133 /lib/Target/Sparc | |
parent | c27b10b198c1d9e9b51f2303994313ec2778edd7 (diff) | |
parent | dbb832b83351cec97b025b61c26536ef50c3181c (diff) | |
download | external_llvm-ce9904c6ea8fd669978a8eefb854b330eb9828ff.zip external_llvm-ce9904c6ea8fd669978a8eefb854b330eb9828ff.tar.gz external_llvm-ce9904c6ea8fd669978a8eefb854b330eb9828ff.tar.bz2 |
Merge remote-tracking branch 'upstream/release_34' into merge-20140211
Conflicts:
lib/Linker/LinkModules.cpp
lib/Support/Unix/Signals.inc
Change-Id: Ia54f291fa5dc828052d2412736e8495c1282aa64
Diffstat (limited to 'lib/Target/Sparc')
33 files changed, 2477 insertions, 310 deletions
diff --git a/lib/Target/Sparc/CMakeLists.txt b/lib/Target/Sparc/CMakeLists.txt index acf7496..6339394 100644 --- a/lib/Target/Sparc/CMakeLists.txt +++ b/lib/Target/Sparc/CMakeLists.txt @@ -2,6 +2,7 @@ set(LLVM_TARGET_DEFINITIONS Sparc.td) tablegen(LLVM SparcGenRegisterInfo.inc -gen-register-info) tablegen(LLVM SparcGenInstrInfo.inc -gen-instr-info) +tablegen(LLVM SparcGenCodeEmitter.inc -gen-emitter) tablegen(LLVM SparcGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM SparcGenDAGISel.inc -gen-dag-isel) tablegen(LLVM SparcGenSubtargetInfo.inc -gen-subtarget) @@ -20,6 +21,8 @@ add_llvm_target(SparcCodeGen SparcSubtarget.cpp SparcTargetMachine.cpp SparcSelectionDAGInfo.cpp + SparcJITInfo.cpp + SparcCodeEmitter.cpp ) add_dependencies(LLVMSparcCodeGen SparcCommonTableGen intrinsics_gen) diff --git a/lib/Target/Sparc/DelaySlotFiller.cpp b/lib/Target/Sparc/DelaySlotFiller.cpp index b101751..9a0466a 100644 --- a/lib/Target/Sparc/DelaySlotFiller.cpp +++ b/lib/Target/Sparc/DelaySlotFiller.cpp @@ -14,6 +14,7 @@ #define DEBUG_TYPE "delay-slot-filler" #include "Sparc.h" +#include "SparcSubtarget.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/MachineFunctionPass.h" @@ -39,10 +40,13 @@ namespace { /// layout, etc. /// TargetMachine &TM; + const SparcSubtarget *Subtarget; static char ID; Filler(TargetMachine &tm) - : MachineFunctionPass(ID), TM(tm) { } + : MachineFunctionPass(ID), TM(tm), + Subtarget(&TM.getSubtarget<SparcSubtarget>()) { + } virtual const char *getPassName() const { return "SPARC Delay Slot Filler"; @@ -102,6 +106,8 @@ FunctionPass *llvm::createSparcDelaySlotFillerPass(TargetMachine &tm) { bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) { bool Changed = false; + const TargetInstrInfo *TII = TM.getInstrInfo(); + for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ) { MachineBasicBlock::iterator MI = I; ++I; @@ -114,6 +120,14 @@ bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) { continue; } + if (!Subtarget->isV9() && + (MI->getOpcode() == SP::FCMPS || MI->getOpcode() == SP::FCMPD + || MI->getOpcode() == SP::FCMPQ)) { + BuildMI(MBB, I, MI->getDebugLoc(), TII->get(SP::NOP)); + Changed = true; + continue; + } + // If MI has no delay slot, skip. if (!MI->hasDelaySlot()) continue; @@ -126,7 +140,6 @@ bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) { ++FilledSlots; Changed = true; - const TargetInstrInfo *TII = TM.getInstrInfo(); if (D == MBB.end()) BuildMI(MBB, I, MI->getDebugLoc(), TII->get(SP::NOP)); else @@ -156,7 +169,7 @@ Filler::findDelayInstr(MachineBasicBlock &MBB, if (slot == MBB.begin()) return MBB.end(); - if (slot->getOpcode() == SP::RET) + if (slot->getOpcode() == SP::RET || slot->getOpcode() == SP::TLS_CALL) return MBB.end(); if (slot->getOpcode() == SP::RETL) { @@ -342,6 +355,7 @@ bool Filler::needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize) case SP::CALL: structSizeOpNum = 1; break; case SP::JMPLrr: case SP::JMPLri: structSizeOpNum = 2; break; + case SP::TLS_CALL: return false; } const MachineOperand &MO = I->getOperand(structSizeOpNum); diff --git a/lib/Target/Sparc/LLVMBuild.txt b/lib/Target/Sparc/LLVMBuild.txt index 7d54d32..fd8e5d9 100644 --- a/lib/Target/Sparc/LLVMBuild.txt +++ b/lib/Target/Sparc/LLVMBuild.txt @@ -23,6 +23,7 @@ type = TargetGroup name = Sparc parent = Target has_asmprinter = 1 +has_jit = 1 [component_1] type = Library diff --git a/lib/Target/Sparc/MCTargetDesc/SparcBaseInfo.h b/lib/Target/Sparc/MCTargetDesc/SparcBaseInfo.h index aac0e8d..f3caeaa 100644 --- a/lib/Target/Sparc/MCTargetDesc/SparcBaseInfo.h +++ b/lib/Target/Sparc/MCTargetDesc/SparcBaseInfo.h @@ -53,7 +53,27 @@ enum TOF { // Extract bits 41-32 of an address. // Assembler: %hm(addr) - MO_HM + MO_HM, + + // TargetFlags for Thread Local Storage. + MO_TLS_GD_HI22, + MO_TLS_GD_LO10, + MO_TLS_GD_ADD, + MO_TLS_GD_CALL, + MO_TLS_LDM_HI22, + MO_TLS_LDM_LO10, + MO_TLS_LDM_ADD, + MO_TLS_LDM_CALL, + MO_TLS_LDO_HIX22, + MO_TLS_LDO_LOX10, + MO_TLS_LDO_ADD, + MO_TLS_IE_HI22, + MO_TLS_IE_LO10, + MO_TLS_IE_LD, + MO_TLS_IE_LDX, + MO_TLS_IE_ADD, + MO_TLS_LE_HIX22, + MO_TLS_LE_LOX10 }; } // end namespace SPII diff --git a/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp b/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp index 5a52abe..baac36b 100644 --- a/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp +++ b/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp @@ -21,23 +21,26 @@ void SparcELFMCAsmInfo::anchor() { } SparcELFMCAsmInfo::SparcELFMCAsmInfo(StringRef TT) { IsLittleEndian = false; Triple TheTriple(TT); - if (TheTriple.getArch() == Triple::sparcv9) { + bool isV9 = (TheTriple.getArch() == Triple::sparcv9); + + if (isV9) { PointerSize = CalleeSaveStackSlotSize = 8; } Data16bitsDirective = "\t.half\t"; Data32bitsDirective = "\t.word\t"; - Data64bitsDirective = 0; // .xword is only supported by V9. + // .xword is only supported by V9. + Data64bitsDirective = (isV9) ? "\t.xword\t" : 0; ZeroDirective = "\t.skip\t"; CommentString = "!"; HasLEB128 = true; SupportsDebugInformation = true; - + + ExceptionsType = ExceptionHandling::DwarfCFI; + SunStyleELFSectionSwitchSyntax = true; UsesELFSectionDirectiveForBSS = true; - WeakRefDirective = "\t.weak\t"; - PrivateGlobalPrefix = ".L"; } diff --git a/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h b/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h index 621e8ff..1e58e37 100644 --- a/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h +++ b/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h @@ -14,12 +14,12 @@ #ifndef SPARCTARGETASMINFO_H #define SPARCTARGETASMINFO_H -#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCAsmInfoELF.h" namespace llvm { class StringRef; - class SparcELFMCAsmInfo : public MCAsmInfo { + class SparcELFMCAsmInfo : public MCAsmInfoELF { virtual void anchor(); public: explicit SparcELFMCAsmInfo(StringRef TT); diff --git a/lib/Target/Sparc/Makefile b/lib/Target/Sparc/Makefile index 4b81ada..c171db7 100644 --- a/lib/Target/Sparc/Makefile +++ b/lib/Target/Sparc/Makefile @@ -14,7 +14,8 @@ TARGET = Sparc # Make sure that tblgen is run, first thing. BUILT_SOURCES = SparcGenRegisterInfo.inc SparcGenInstrInfo.inc \ SparcGenAsmWriter.inc SparcGenDAGISel.inc \ - SparcGenSubtargetInfo.inc SparcGenCallingConv.inc + SparcGenSubtargetInfo.inc SparcGenCallingConv.inc \ + SparcGenCodeEmitter.inc DIRS = TargetInfo MCTargetDesc diff --git a/lib/Target/Sparc/Sparc.h b/lib/Target/Sparc/Sparc.h index 98563db..f44b604 100644 --- a/lib/Target/Sparc/Sparc.h +++ b/lib/Target/Sparc/Sparc.h @@ -26,6 +26,8 @@ namespace llvm { FunctionPass *createSparcISelDag(SparcTargetMachine &TM); FunctionPass *createSparcDelaySlotFillerPass(TargetMachine &TM); + FunctionPass *createSparcJITCodeEmitterPass(SparcTargetMachine &TM, + JITCodeEmitter &JCE); } // end namespace llvm; @@ -103,5 +105,22 @@ namespace llvm { } llvm_unreachable("Invalid cond code"); } + + inline static unsigned HI22(int64_t imm) { + return (unsigned)((imm >> 10) & ((1 << 22)-1)); + } + + inline static unsigned LO10(int64_t imm) { + return (unsigned)(imm & 0x3FF); + } + + inline static unsigned HIX22(int64_t imm) { + return HI22(~imm); + } + + inline static unsigned LOX10(int64_t imm) { + return ~LO10(~imm); + } + } // end namespace llvm #endif diff --git a/lib/Target/Sparc/Sparc.td b/lib/Target/Sparc/Sparc.td index d42c40f..0df48f6 100644 --- a/lib/Target/Sparc/Sparc.td +++ b/lib/Target/Sparc/Sparc.td @@ -30,6 +30,10 @@ def FeatureVIS : SubtargetFeature<"vis", "IsVIS", "true", "Enable UltraSPARC Visual Instruction Set extensions">; +def FeatureHardQuad + : SubtargetFeature<"hard-quad-float", "HasHardQuad", "true", + "Enable quad-word floating point instructions">; + //===----------------------------------------------------------------------===// // Register File, Calling Conv, Instruction Descriptions //===----------------------------------------------------------------------===// diff --git a/lib/Target/Sparc/SparcAsmPrinter.cpp b/lib/Target/Sparc/SparcAsmPrinter.cpp index 3fe2b44..d06c894 100644 --- a/lib/Target/Sparc/SparcAsmPrinter.cpp +++ b/lib/Target/Sparc/SparcAsmPrinter.cpp @@ -20,6 +20,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" @@ -43,6 +44,7 @@ namespace { const char *Modifier = 0); void printCCOperand(const MachineInstr *MI, int opNum, raw_ostream &OS); + virtual void EmitFunctionBodyStart(); virtual void EmitInstruction(const MachineInstr *MI) { SmallString<128> Str; raw_svector_ostream OS(Str); @@ -63,11 +65,35 @@ namespace { virtual bool isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const; + void EmitGlobalRegisterDecl(unsigned reg) { + SmallString<128> Str; + raw_svector_ostream OS(Str); + OS << "\t.register " + << "%" << StringRef(getRegisterName(reg)).lower() + << ", " + << ((reg == SP::G6 || reg == SP::G7)? "#ignore" : "#scratch"); + OutStreamer.EmitRawText(OS.str()); + } + }; } // end of anonymous namespace #include "SparcGenAsmWriter.inc" +void SparcAsmPrinter::EmitFunctionBodyStart() { + if (!TM.getSubtarget<SparcSubtarget>().is64Bit()) + return; + + const MachineRegisterInfo &MRI = MF->getRegInfo(); + const unsigned globalRegs[] = { SP::G2, SP::G3, SP::G6, SP::G7, 0 }; + for (unsigned i = 0; globalRegs[i] != 0; ++i) { + unsigned reg = globalRegs[i]; + if (MRI.use_empty(reg)) + continue; + EmitGlobalRegisterDecl(reg); + } +} + void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum, raw_ostream &O) { const MachineOperand &MO = MI->getOperand (opNum); @@ -79,11 +105,37 @@ void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum, assert(TF == SPII::MO_NO_FLAG && "Cannot handle target flags on call address"); else if (MI->getOpcode() == SP::SETHIi) - assert((TF == SPII::MO_HI || TF == SPII::MO_H44 || TF == SPII::MO_HH) && + assert((TF == SPII::MO_HI || TF == SPII::MO_H44 || TF == SPII::MO_HH + || TF == SPII::MO_TLS_GD_HI22 + || TF == SPII::MO_TLS_LDM_HI22 + || TF == SPII::MO_TLS_LDO_HIX22 + || TF == SPII::MO_TLS_IE_HI22 + || TF == SPII::MO_TLS_LE_HIX22) && "Invalid target flags for address operand on sethi"); + else if (MI->getOpcode() == SP::TLS_CALL) + assert((TF == SPII::MO_NO_FLAG + || TF == SPII::MO_TLS_GD_CALL + || TF == SPII::MO_TLS_LDM_CALL) && + "Cannot handle target flags on tls call address"); + else if (MI->getOpcode() == SP::TLS_ADDrr) + assert((TF == SPII::MO_TLS_GD_ADD || TF == SPII::MO_TLS_LDM_ADD + || TF == SPII::MO_TLS_LDO_ADD || TF == SPII::MO_TLS_IE_ADD) && + "Cannot handle target flags on add for TLS"); + else if (MI->getOpcode() == SP::TLS_LDrr) + assert(TF == SPII::MO_TLS_IE_LD && + "Cannot handle target flags on ld for TLS"); + else if (MI->getOpcode() == SP::TLS_LDXrr) + assert(TF == SPII::MO_TLS_IE_LDX && + "Cannot handle target flags on ldx for TLS"); + else if (MI->getOpcode() == SP::XORri) + assert((TF == SPII::MO_TLS_LDO_LOX10 || TF == SPII::MO_TLS_LE_LOX10) && + "Cannot handle target flags on xor for TLS"); else - assert((TF == SPII::MO_LO || TF == SPII::MO_M44 || TF == SPII::MO_L44 || - TF == SPII::MO_HM) && + assert((TF == SPII::MO_LO || TF == SPII::MO_M44 || TF == SPII::MO_L44 + || TF == SPII::MO_HM + || TF == SPII::MO_TLS_GD_LO10 + || TF == SPII::MO_TLS_LDM_LO10 + || TF == SPII::MO_TLS_IE_LO10 ) && "Invalid target flags for small address operand"); } #endif @@ -102,6 +154,24 @@ void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum, case SPII::MO_L44: O << "%l44("; break; case SPII::MO_HH: O << "%hh("; break; case SPII::MO_HM: O << "%hm("; break; + case SPII::MO_TLS_GD_HI22: O << "%tgd_hi22("; break; + case SPII::MO_TLS_GD_LO10: O << "%tgd_lo10("; break; + case SPII::MO_TLS_GD_ADD: O << "%tgd_add("; break; + case SPII::MO_TLS_GD_CALL: O << "%tgd_call("; break; + case SPII::MO_TLS_LDM_HI22: O << "%tldm_hi22("; break; + case SPII::MO_TLS_LDM_LO10: O << "%tldm_lo10("; break; + case SPII::MO_TLS_LDM_ADD: O << "%tldm_add("; break; + case SPII::MO_TLS_LDM_CALL: O << "%tldm_call("; break; + case SPII::MO_TLS_LDO_HIX22: O << "%tldo_hix22("; break; + case SPII::MO_TLS_LDO_LOX10: O << "%tldo_lox10("; break; + case SPII::MO_TLS_LDO_ADD: O << "%tldo_add("; break; + case SPII::MO_TLS_IE_HI22: O << "%tie_hi22("; break; + case SPII::MO_TLS_IE_LO10: O << "%tie_lo10("; break; + case SPII::MO_TLS_IE_LD: O << "%tie_ld("; break; + case SPII::MO_TLS_IE_LDX: O << "%tie_ldx("; break; + case SPII::MO_TLS_IE_ADD: O << "%tie_add("; break; + case SPII::MO_TLS_LE_HIX22: O << "%tle_hix22("; break; + case SPII::MO_TLS_LE_LOX10: O << "%tle_lox10("; break; } switch (MO.getType()) { @@ -116,7 +186,7 @@ void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum, O << *MO.getMBB()->getSymbol(); return; case MachineOperand::MO_GlobalAddress: - O << *Mang->getSymbol(MO.getGlobal()); + O << *getSymbol(MO.getGlobal()); break; case MachineOperand::MO_BlockAddress: O << GetBlockAddressSymbol(MO.getBlockAddress())->getName(); diff --git a/lib/Target/Sparc/SparcCallingConv.td b/lib/Target/Sparc/SparcCallingConv.td index a181bcf..acd4ec2 100644 --- a/lib/Target/Sparc/SparcCallingConv.td +++ b/lib/Target/Sparc/SparcCallingConv.td @@ -117,3 +117,14 @@ def CC_Sparc64 : CallingConv<[ // arguments whether they are passed in registers or not. CCCustom<"CC_Sparc64_Full"> ]>; + +// Callee-saved registers are handled by the register window mechanism. +def CSR : CalleeSavedRegs<(add)> { + let OtherPreserved = (add (sequence "I%u", 0, 7), + (sequence "L%u", 0, 7)); +} + +// Callee-saved registers for calls with ReturnsTwice attribute. +def RTCSR : CalleeSavedRegs<(add)> { + let OtherPreserved = (add I6, I7); +} diff --git a/lib/Target/Sparc/SparcCodeEmitter.cpp b/lib/Target/Sparc/SparcCodeEmitter.cpp new file mode 100644 index 0000000..9bfe31f --- /dev/null +++ b/lib/Target/Sparc/SparcCodeEmitter.cpp @@ -0,0 +1,245 @@ +//===-- Sparc/SparcCodeEmitter.cpp - Convert Sparc Code to Machine Code ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +// +// This file contains the pass that transforms the Sparc machine instructions +// into relocatable machine code. +// +//===---------------------------------------------------------------------===// + +#define DEBUG_TYPE "jit" +#include "Sparc.h" +#include "MCTargetDesc/SparcBaseInfo.h" +#include "SparcRelocations.h" +#include "SparcTargetMachine.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/JITCodeEmitter.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/Support/Debug.h" + +using namespace llvm; + +STATISTIC(NumEmitted, "Number of machine instructions emitted"); + +namespace { + +class SparcCodeEmitter : public MachineFunctionPass { + SparcJITInfo *JTI; + const SparcInstrInfo *II; + const DataLayout *TD; + const SparcSubtarget *Subtarget; + TargetMachine &TM; + JITCodeEmitter &MCE; + const std::vector<MachineConstantPoolEntry> *MCPEs; + bool IsPIC; + + void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired<MachineModuleInfo> (); + MachineFunctionPass::getAnalysisUsage(AU); + } + + static char ID; + +public: + SparcCodeEmitter(TargetMachine &tm, JITCodeEmitter &mce) + : MachineFunctionPass(ID), JTI(0), II(0), TD(0), + TM(tm), MCE(mce), MCPEs(0), + IsPIC(TM.getRelocationModel() == Reloc::PIC_) {} + + bool runOnMachineFunction(MachineFunction &MF); + + virtual const char *getPassName() const { + return "Sparc Machine Code Emitter"; + } + + /// getBinaryCodeForInstr - This function, generated by the + /// CodeEmitterGenerator using TableGen, produces the binary encoding for + /// machine instructions. + uint64_t getBinaryCodeForInstr(const MachineInstr &MI) const; + + void emitInstruction(MachineBasicBlock::instr_iterator MI, + MachineBasicBlock &MBB); + +private: + /// getMachineOpValue - Return binary encoding of operand. If the machine + /// operand requires relocation, record the relocation and return zero. + unsigned getMachineOpValue(const MachineInstr &MI, + const MachineOperand &MO) const; + + void emitWord(unsigned Word); + + unsigned getRelocation(const MachineInstr &MI, + const MachineOperand &MO) const; + + void emitGlobalAddress(const GlobalValue *GV, unsigned Reloc) const; + void emitExternalSymbolAddress(const char *ES, unsigned Reloc) const; + void emitConstPoolAddress(unsigned CPI, unsigned Reloc) const; + void emitMachineBasicBlock(MachineBasicBlock *BB, unsigned Reloc) const; +}; +} // end anonymous namespace. + +char SparcCodeEmitter::ID = 0; + +bool SparcCodeEmitter::runOnMachineFunction(MachineFunction &MF) { + SparcTargetMachine &Target = static_cast<SparcTargetMachine &>( + const_cast<TargetMachine &>(MF.getTarget())); + + JTI = Target.getJITInfo(); + II = Target.getInstrInfo(); + TD = Target.getDataLayout(); + Subtarget = &TM.getSubtarget<SparcSubtarget> (); + MCPEs = &MF.getConstantPool()->getConstants(); + JTI->Initialize(MF, IsPIC); + MCE.setModuleInfo(&getAnalysis<MachineModuleInfo> ()); + + do { + DEBUG(errs() << "JITTing function '" + << MF.getName() << "'\n"); + MCE.startFunction(MF); + + for (MachineFunction::iterator MBB = MF.begin(), E = MF.end(); + MBB != E; ++MBB){ + MCE.StartMachineBasicBlock(MBB); + for (MachineBasicBlock::instr_iterator I = MBB->instr_begin(), + E = MBB->instr_end(); I != E;) + emitInstruction(*I++, *MBB); + } + } while (MCE.finishFunction(MF)); + + return false; +} + +void SparcCodeEmitter::emitInstruction(MachineBasicBlock::instr_iterator MI, + MachineBasicBlock &MBB) { + DEBUG(errs() << "JIT: " << (void*)MCE.getCurrentPCValue() << ":\t" << *MI); + + MCE.processDebugLoc(MI->getDebugLoc(), true); + + ++NumEmitted; + + switch (MI->getOpcode()) { + default: { + emitWord(getBinaryCodeForInstr(*MI)); + break; + } + case TargetOpcode::INLINEASM: { + // We allow inline assembler nodes with empty bodies - they can + // implicitly define registers, which is ok for JIT. + if (MI->getOperand(0).getSymbolName()[0]) { + report_fatal_error("JIT does not support inline asm!"); + } + break; + } + case TargetOpcode::PROLOG_LABEL: + case TargetOpcode::EH_LABEL: { + MCE.emitLabel(MI->getOperand(0).getMCSymbol()); + break; + } + case TargetOpcode::IMPLICIT_DEF: + case TargetOpcode::KILL: { + // Do nothing. + break; + } + case SP::GETPCX: { + report_fatal_error("JIT does not support pseudo instruction GETPCX yet!"); + break; + } + } + + MCE.processDebugLoc(MI->getDebugLoc(), false); +} + +void SparcCodeEmitter::emitWord(unsigned Word) { + DEBUG(errs() << " 0x"; + errs().write_hex(Word) << "\n"); + MCE.emitWordBE(Word); +} + +/// getMachineOpValue - Return binary encoding of operand. If the machine +/// operand requires relocation, record the relocation and return zero. +unsigned SparcCodeEmitter::getMachineOpValue(const MachineInstr &MI, + const MachineOperand &MO) const { + if (MO.isReg()) + return TM.getRegisterInfo()->getEncodingValue(MO.getReg()); + else if (MO.isImm()) + return static_cast<unsigned>(MO.getImm()); + else if (MO.isGlobal()) + emitGlobalAddress(MO.getGlobal(), getRelocation(MI, MO)); + else if (MO.isSymbol()) + emitExternalSymbolAddress(MO.getSymbolName(), getRelocation(MI, MO)); + else if (MO.isCPI()) + emitConstPoolAddress(MO.getIndex(), getRelocation(MI, MO)); + else if (MO.isMBB()) + emitMachineBasicBlock(MO.getMBB(), getRelocation(MI, MO)); + else + llvm_unreachable("Unable to encode MachineOperand!"); + return 0; +} +unsigned SparcCodeEmitter::getRelocation(const MachineInstr &MI, + const MachineOperand &MO) const { + + unsigned TF = MO.getTargetFlags(); + switch (TF) { + default: + case SPII::MO_NO_FLAG: break; + case SPII::MO_LO: return SP::reloc_sparc_lo; + case SPII::MO_HI: return SP::reloc_sparc_hi; + case SPII::MO_H44: + case SPII::MO_M44: + case SPII::MO_L44: + case SPII::MO_HH: + case SPII::MO_HM: assert(0 && "FIXME: Implement Medium/Large code model."); + } + + unsigned Opc = MI.getOpcode(); + switch (Opc) { + default: break; + case SP::CALL: return SP::reloc_sparc_pc30; + case SP::BA: + case SP::BCOND: + case SP::FBCOND: return SP::reloc_sparc_pc22; + case SP::BPXCC: return SP::reloc_sparc_pc19; + } + llvm_unreachable("unknown reloc!"); +} + +void SparcCodeEmitter::emitGlobalAddress(const GlobalValue *GV, + unsigned Reloc) const { + MCE.addRelocation(MachineRelocation::getGV(MCE.getCurrentPCOffset(), Reloc, + const_cast<GlobalValue *>(GV), 0, + true)); +} + +void SparcCodeEmitter:: +emitExternalSymbolAddress(const char *ES, unsigned Reloc) const { + MCE.addRelocation(MachineRelocation::getExtSym(MCE.getCurrentPCOffset(), + Reloc, ES, 0, 0)); +} + +void SparcCodeEmitter:: +emitConstPoolAddress(unsigned CPI, unsigned Reloc) const { + MCE.addRelocation(MachineRelocation::getConstPool(MCE.getCurrentPCOffset(), + Reloc, CPI, 0, false)); +} + +void SparcCodeEmitter::emitMachineBasicBlock(MachineBasicBlock *BB, + unsigned Reloc) const { + MCE.addRelocation(MachineRelocation::getBB(MCE.getCurrentPCOffset(), + Reloc, BB)); +} + + +/// createSparcJITCodeEmitterPass - Return a pass that emits the collected Sparc +/// code to the specified MCE object. +FunctionPass *llvm::createSparcJITCodeEmitterPass(SparcTargetMachine &TM, + JITCodeEmitter &JCE) { + return new SparcCodeEmitter(TM, JCE); +} + +#include "SparcGenCodeEmitter.inc" diff --git a/lib/Target/Sparc/SparcFrameLowering.cpp b/lib/Target/Sparc/SparcFrameLowering.cpp index 536e466..c75998a 100644 --- a/lib/Target/Sparc/SparcFrameLowering.cpp +++ b/lib/Target/Sparc/SparcFrameLowering.cpp @@ -33,6 +33,51 @@ DisableLeafProc("disable-sparc-leaf-proc", cl::Hidden); +void SparcFrameLowering::emitSPAdjustment(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + int NumBytes, + unsigned ADDrr, + unsigned ADDri) const { + + DebugLoc dl = (MBBI != MBB.end()) ? MBBI->getDebugLoc() : DebugLoc(); + const SparcInstrInfo &TII = + *static_cast<const SparcInstrInfo*>(MF.getTarget().getInstrInfo()); + + if (NumBytes >= -4096 && NumBytes < 4096) { + BuildMI(MBB, MBBI, dl, TII.get(ADDri), SP::O6) + .addReg(SP::O6).addImm(NumBytes); + return; + } + + // Emit this the hard way. This clobbers G1 which we always know is + // available here. + if (NumBytes >= 0) { + // Emit nonnegative numbers with sethi + or. + // sethi %hi(NumBytes), %g1 + // or %g1, %lo(NumBytes), %g1 + // add %sp, %g1, %sp + BuildMI(MBB, MBBI, dl, TII.get(SP::SETHIi), SP::G1) + .addImm(HI22(NumBytes)); + BuildMI(MBB, MBBI, dl, TII.get(SP::ORri), SP::G1) + .addReg(SP::G1).addImm(LO10(NumBytes)); + BuildMI(MBB, MBBI, dl, TII.get(ADDrr), SP::O6) + .addReg(SP::O6).addReg(SP::G1); + return ; + } + + // Emit negative numbers with sethi + xor. + // sethi %hix(NumBytes), %g1 + // xor %g1, %lox(NumBytes), %g1 + // add %sp, %g1, %sp + BuildMI(MBB, MBBI, dl, TII.get(SP::SETHIi), SP::G1) + .addImm(HIX22(NumBytes)); + BuildMI(MBB, MBBI, dl, TII.get(SP::XORri), SP::G1) + .addReg(SP::G1).addImm(LOX10(NumBytes)); + BuildMI(MBB, MBBI, dl, TII.get(ADDrr), SP::O6) + .addReg(SP::O6).addReg(SP::G1); +} + void SparcFrameLowering::emitPrologue(MachineFunction &MF) const { SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>(); @@ -55,21 +100,27 @@ void SparcFrameLowering::emitPrologue(MachineFunction &MF) const { SAVErr = SP::ADDrr; } NumBytes = - SubTarget.getAdjustedFrameSize(NumBytes); - - if (NumBytes >= -4096) { - BuildMI(MBB, MBBI, dl, TII.get(SAVEri), SP::O6) - .addReg(SP::O6).addImm(NumBytes); - } else { - // Emit this the hard way. This clobbers G1 which we always know is - // available here. - unsigned OffHi = (unsigned)NumBytes >> 10U; - BuildMI(MBB, MBBI, dl, TII.get(SP::SETHIi), SP::G1).addImm(OffHi); - // Emit G1 = G1 + I6 - BuildMI(MBB, MBBI, dl, TII.get(SP::ORri), SP::G1) - .addReg(SP::G1).addImm(NumBytes & ((1 << 10)-1)); - BuildMI(MBB, MBBI, dl, TII.get(SAVErr), SP::O6) - .addReg(SP::O6).addReg(SP::G1); - } + emitSPAdjustment(MF, MBB, MBBI, NumBytes, SAVErr, SAVEri); + + MachineModuleInfo &MMI = MF.getMMI(); + const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); + MCSymbol *FrameLabel = MMI.getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, dl, TII.get(SP::PROLOG_LABEL)).addSym(FrameLabel); + + unsigned regFP = MRI->getDwarfRegNum(SP::I6, true); + + // Emit ".cfi_def_cfa_register 30". + MMI.addFrameInst(MCCFIInstruction::createDefCfaRegister(FrameLabel, + regFP)); + // Emit ".cfi_window_save". + MMI.addFrameInst(MCCFIInstruction::createWindowSave(FrameLabel)); + + unsigned regInRA = MRI->getDwarfRegNum(SP::I7, true); + unsigned regOutRA = MRI->getDwarfRegNum(SP::O7, true); + // Emit ".cfi_register 15, 31". + MMI.addFrameInst(MCCFIInstruction::createRegister(FrameLabel, + regOutRA, + regInRA)); } void SparcFrameLowering:: @@ -77,15 +128,12 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const { if (!hasReservedCallFrame(MF)) { MachineInstr &MI = *I; - DebugLoc DL = MI.getDebugLoc(); int Size = MI.getOperand(0).getImm(); if (MI.getOpcode() == SP::ADJCALLSTACKDOWN) Size = -Size; - const SparcInstrInfo &TII = - *static_cast<const SparcInstrInfo*>(MF.getTarget().getInstrInfo()); + if (Size) - BuildMI(MBB, I, DL, TII.get(SP::ADDri), SP::O6).addReg(SP::O6) - .addImm(Size); + emitSPAdjustment(MF, MBB, I, Size, SP::ADDrr, SP::ADDri); } MBB.erase(I); } @@ -112,21 +160,7 @@ void SparcFrameLowering::emitEpilogue(MachineFunction &MF, return; NumBytes = SubTarget.getAdjustedFrameSize(NumBytes); - - if (NumBytes < 4096) { - BuildMI(MBB, MBBI, dl, TII.get(SP::ADDri), SP::O6) - .addReg(SP::O6).addImm(NumBytes); - } else { - // Emit this the hard way. This clobbers G1 which we always know is - // available here. - unsigned OffHi = (unsigned)NumBytes >> 10U; - BuildMI(MBB, MBBI, dl, TII.get(SP::SETHIi), SP::G1).addImm(OffHi); - // Emit G1 = G1 + I6 - BuildMI(MBB, MBBI, dl, TII.get(SP::ORri), SP::G1) - .addReg(SP::G1).addImm(NumBytes & ((1 << 10)-1)); - BuildMI(MBB, MBBI, dl, TII.get(SP::ADDrr), SP::O6) - .addReg(SP::O6).addReg(SP::G1); - } + emitSPAdjustment(MF, MBB, MBBI, NumBytes, SP::ADDrr, SP::ADDri); } bool SparcFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { diff --git a/lib/Target/Sparc/SparcFrameLowering.h b/lib/Target/Sparc/SparcFrameLowering.h index 8eaef59..072fde3 100644 --- a/lib/Target/Sparc/SparcFrameLowering.h +++ b/lib/Target/Sparc/SparcFrameLowering.h @@ -49,6 +49,14 @@ private: // Returns true if MF is a leaf procedure. bool isLeafProc(MachineFunction &MF) const; + + + // Emits code for adjusting SP in function prologue/epilogue. + void emitSPAdjustment(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + int NumBytes, unsigned ADDrr, unsigned ADDri) const; + }; } // End llvm namespace diff --git a/lib/Target/Sparc/SparcISelDAGToDAG.cpp b/lib/Target/Sparc/SparcISelDAGToDAG.cpp index db62151..b012bfd 100644 --- a/lib/Target/Sparc/SparcISelDAGToDAG.cpp +++ b/lib/Target/Sparc/SparcISelDAGToDAG.cpp @@ -80,7 +80,8 @@ bool SparcDAGToDAGISel::SelectADDRri(SDValue Addr, return true; } if (Addr.getOpcode() == ISD::TargetExternalSymbol || - Addr.getOpcode() == ISD::TargetGlobalAddress) + Addr.getOpcode() == ISD::TargetGlobalAddress || + Addr.getOpcode() == ISD::TargetGlobalTLSAddress) return false; // direct calls. if (Addr.getOpcode() == ISD::ADD) { @@ -117,7 +118,8 @@ bool SparcDAGToDAGISel::SelectADDRri(SDValue Addr, bool SparcDAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) { if (Addr.getOpcode() == ISD::FrameIndex) return false; if (Addr.getOpcode() == ISD::TargetExternalSymbol || - Addr.getOpcode() == ISD::TargetGlobalAddress) + Addr.getOpcode() == ISD::TargetGlobalAddress || + Addr.getOpcode() == ISD::TargetGlobalTLSAddress) return false; // direct calls. if (Addr.getOpcode() == ISD::ADD) { @@ -139,8 +141,10 @@ bool SparcDAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) { SDNode *SparcDAGToDAGISel::Select(SDNode *N) { SDLoc dl(N); - if (N->isMachineOpcode()) + if (N->isMachineOpcode()) { + N->setNodeId(-1); return NULL; // Already selected. + } switch (N->getOpcode()) { default: break; diff --git a/lib/Target/Sparc/SparcISelLowering.cpp b/lib/Target/Sparc/SparcISelLowering.cpp index 4b0fa67..64625f7 100644 --- a/lib/Target/Sparc/SparcISelLowering.cpp +++ b/lib/Target/Sparc/SparcISelLowering.cpp @@ -14,6 +14,7 @@ #include "SparcISelLowering.h" #include "SparcMachineFunctionInfo.h" +#include "SparcRegisterInfo.h" #include "SparcTargetMachine.h" #include "MCTargetDesc/SparcBaseInfo.h" #include "llvm/CodeGen/CallingConvLower.h" @@ -648,6 +649,27 @@ SparcTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, return LowerCall_32(CLI, InVals); } +static bool hasReturnsTwiceAttr(SelectionDAG &DAG, SDValue Callee, + ImmutableCallSite *CS) { + if (CS) + return CS->hasFnAttr(Attribute::ReturnsTwice); + + const Function *CalleeFn = 0; + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) { + CalleeFn = dyn_cast<Function>(G->getGlobal()); + } else if (ExternalSymbolSDNode *E = + dyn_cast<ExternalSymbolSDNode>(Callee)) { + const Function *Fn = DAG.getMachineFunction().getFunction(); + const Module *M = Fn->getParent(); + const char *CalleeName = E->getSymbol(); + CalleeFn = M->getFunction(CalleeName); + } + + if (!CalleeFn) + return false; + return CalleeFn->hasFnAttribute(Attribute::ReturnsTwice); +} + // Lower a call for the 32-bit ABI. SDValue SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, @@ -861,6 +883,7 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, } unsigned SRetArgSize = (hasStructRetAttr)? getSRetArgSize(DAG, Callee):0; + bool hasReturnsTwice = hasReturnsTwiceAttr(DAG, Callee, CLI.CS); // If the callee is a GlobalAddress node (quite common, every direct call is) // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. @@ -880,6 +903,16 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) Ops.push_back(DAG.getRegister(toCallerWindow(RegsToPass[i].first), RegsToPass[i].second.getValueType())); + + // Add a register mask operand representing the call-preserved registers. + const SparcRegisterInfo *TRI = + ((const SparcTargetMachine&)getTargetMachine()).getRegisterInfo(); + const uint32_t *Mask = ((hasReturnsTwice) + ? TRI->getRTCallPreservedMask(CallConv) + : 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); @@ -908,6 +941,23 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, return Chain; } +// This functions returns true if CalleeName is a ABI function that returns +// a long double (fp128). +static bool isFP128ABICall(const char *CalleeName) +{ + static const char *const ABICalls[] = + { "_Q_add", "_Q_sub", "_Q_mul", "_Q_div", + "_Q_sqrt", "_Q_neg", + "_Q_itoq", "_Q_stoq", "_Q_dtoq", "_Q_utoq", + "_Q_lltoq", "_Q_ulltoq", + 0 + }; + for (const char * const *I = ABICalls; *I != 0; ++I) + if (strcmp(CalleeName, *I) == 0) + return true; + return false; +} + unsigned SparcTargetLowering::getSRetArgSize(SelectionDAG &DAG, SDValue Callee) const { @@ -918,7 +968,10 @@ SparcTargetLowering::getSRetArgSize(SelectionDAG &DAG, SDValue Callee) const dyn_cast<ExternalSymbolSDNode>(Callee)) { const Function *Fn = DAG.getMachineFunction().getFunction(); const Module *M = Fn->getParent(); - CalleeFn = M->getFunction(E->getSymbol()); + const char *CalleeName = E->getSymbol(); + CalleeFn = M->getFunction(CalleeName); + if (!CalleeFn && isFP128ABICall(CalleeName)) + return 16; // Return sizeof(fp128) } if (!CalleeFn) @@ -983,6 +1036,9 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI, SDLoc DL = CLI.DL; SDValue Chain = CLI.Chain; + // Sparc target does not yet support tail call optimization. + CLI.IsTailCall = false; + // Analyze operands of the call, assigning locations to each operand. SmallVector<CCValAssign, 16> ArgLocs; CCState CCInfo(CLI.CallConv, CLI.IsVarArg, DAG.getMachineFunction(), @@ -1099,6 +1155,7 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI, // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. // Likewise ExternalSymbol -> TargetExternalSymbol. SDValue Callee = CLI.Callee; + bool hasReturnsTwice = hasReturnsTwiceAttr(DAG, Callee, CLI.CS); if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, getPointerTy()); else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) @@ -1112,6 +1169,15 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI, Ops.push_back(DAG.getRegister(RegsToPass[i].first, RegsToPass[i].second.getValueType())); + // Add a register mask operand representing the call-preserved registers. + const SparcRegisterInfo *TRI = + ((const SparcTargetMachine&)getTargetMachine()).getRegisterInfo(); + const uint32_t *Mask = ((hasReturnsTwice) + ? TRI->getRTCallPreservedMask(CLI.CallConv) + : TRI->getCallPreservedMask(CLI.CallConv)); + assert(Mask && "Missing call preserved mask for calling convention"); + Ops.push_back(DAG.getRegisterMask(Mask)); + // Make sure the CopyToReg nodes are glued to the call instruction which // consumes the registers. if (InGlue.getNode()) @@ -1244,15 +1310,21 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) addRegisterClass(MVT::i32, &SP::IntRegsRegClass); addRegisterClass(MVT::f32, &SP::FPRegsRegClass); addRegisterClass(MVT::f64, &SP::DFPRegsRegClass); + addRegisterClass(MVT::f128, &SP::QFPRegsRegClass); if (Subtarget->is64Bit()) addRegisterClass(MVT::i64, &SP::I64RegsRegClass); // Turn FP extload into load/fextend setLoadExtAction(ISD::EXTLOAD, MVT::f32, Expand); + setLoadExtAction(ISD::EXTLOAD, MVT::f64, Expand); + // Sparc doesn't have i1 sign extending load setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote); + // Turn FP truncstore into trunc + store. setTruncStoreAction(MVT::f64, MVT::f32, Expand); + setTruncStoreAction(MVT::f128, MVT::f32, Expand); + setTruncStoreAction(MVT::f128, MVT::f64, Expand); // Custom legalize GlobalAddress nodes into LO/HI parts. setOperationAction(ISD::GlobalAddress, getPointerTy(), Custom); @@ -1271,13 +1343,25 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) setOperationAction(ISD::SDIVREM, MVT::i32, Expand); setOperationAction(ISD::UDIVREM, MVT::i32, Expand); + // ... nor does SparcV9. + if (Subtarget->is64Bit()) { + setOperationAction(ISD::UREM, MVT::i64, Expand); + setOperationAction(ISD::SREM, MVT::i64, Expand); + setOperationAction(ISD::SDIVREM, MVT::i64, Expand); + setOperationAction(ISD::UDIVREM, MVT::i64, Expand); + } + // Custom expand fp<->sint setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); setOperationAction(ISD::SINT_TO_FP, MVT::i32, Custom); + setOperationAction(ISD::FP_TO_SINT, MVT::i64, Custom); + setOperationAction(ISD::SINT_TO_FP, MVT::i64, Custom); - // Expand fp<->uint - setOperationAction(ISD::FP_TO_UINT, MVT::i32, Expand); - setOperationAction(ISD::UINT_TO_FP, MVT::i32, Expand); + // Custom Expand fp<->uint + setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom); + setOperationAction(ISD::UINT_TO_FP, MVT::i32, Custom); + setOperationAction(ISD::FP_TO_UINT, MVT::i64, Custom); + setOperationAction(ISD::UINT_TO_FP, MVT::i64, Custom); setOperationAction(ISD::BITCAST, MVT::f32, Expand); setOperationAction(ISD::BITCAST, MVT::i32, Expand); @@ -1286,9 +1370,12 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) setOperationAction(ISD::SELECT, MVT::i32, Expand); setOperationAction(ISD::SELECT, MVT::f32, Expand); setOperationAction(ISD::SELECT, MVT::f64, Expand); + setOperationAction(ISD::SELECT, MVT::f128, Expand); + setOperationAction(ISD::SETCC, MVT::i32, Expand); setOperationAction(ISD::SETCC, MVT::f32, Expand); setOperationAction(ISD::SETCC, MVT::f64, Expand); + setOperationAction(ISD::SETCC, MVT::f128, Expand); // Sparc doesn't have BRCOND either, it has BR_CC. setOperationAction(ISD::BRCOND, MVT::Other, Expand); @@ -1297,18 +1384,34 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) setOperationAction(ISD::BR_CC, MVT::i32, Custom); setOperationAction(ISD::BR_CC, MVT::f32, Custom); setOperationAction(ISD::BR_CC, MVT::f64, Custom); + setOperationAction(ISD::BR_CC, MVT::f128, Custom); setOperationAction(ISD::SELECT_CC, MVT::i32, Custom); setOperationAction(ISD::SELECT_CC, MVT::f32, Custom); setOperationAction(ISD::SELECT_CC, MVT::f64, Custom); + setOperationAction(ISD::SELECT_CC, MVT::f128, Custom); if (Subtarget->is64Bit()) { + setOperationAction(ISD::ADDC, MVT::i64, Custom); + setOperationAction(ISD::ADDE, MVT::i64, Custom); + setOperationAction(ISD::SUBC, MVT::i64, Custom); + setOperationAction(ISD::SUBE, MVT::i64, Custom); setOperationAction(ISD::BITCAST, MVT::f64, Expand); setOperationAction(ISD::BITCAST, MVT::i64, Expand); setOperationAction(ISD::SELECT, MVT::i64, Expand); setOperationAction(ISD::SETCC, MVT::i64, Expand); setOperationAction(ISD::BR_CC, MVT::i64, Custom); setOperationAction(ISD::SELECT_CC, MVT::i64, Custom); + + setOperationAction(ISD::CTPOP, MVT::i64, Legal); + setOperationAction(ISD::CTTZ , MVT::i64, Expand); + setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i64, Expand); + setOperationAction(ISD::CTLZ , MVT::i64, Expand); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i64, Expand); + setOperationAction(ISD::BSWAP, MVT::i64, Expand); + setOperationAction(ISD::ROTL , MVT::i64, Expand); + setOperationAction(ISD::ROTR , MVT::i64, Expand); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Custom); } // FIXME: There are instructions available for ATOMIC_FENCE @@ -1321,6 +1424,11 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) setOperationAction(ISD::FABS, MVT::f64, Custom); } + setOperationAction(ISD::FSIN , MVT::f128, Expand); + setOperationAction(ISD::FCOS , MVT::f128, Expand); + setOperationAction(ISD::FSINCOS, MVT::f128, Expand); + setOperationAction(ISD::FREM , MVT::f128, Expand); + setOperationAction(ISD::FMA , MVT::f128, Expand); setOperationAction(ISD::FSIN , MVT::f64, Expand); setOperationAction(ISD::FCOS , MVT::f64, Expand); setOperationAction(ISD::FSINCOS, MVT::f64, Expand); @@ -1339,8 +1447,10 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) setOperationAction(ISD::ROTL , MVT::i32, Expand); setOperationAction(ISD::ROTR , MVT::i32, Expand); setOperationAction(ISD::BSWAP, MVT::i32, Expand); + setOperationAction(ISD::FCOPYSIGN, MVT::f128, Expand); setOperationAction(ISD::FCOPYSIGN, MVT::f64, Expand); setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand); + setOperationAction(ISD::FPOW , MVT::f128, Expand); setOperationAction(ISD::FPOW , MVT::f64, Expand); setOperationAction(ISD::FPOW , MVT::f32, Expand); @@ -1352,7 +1462,12 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand); setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand); - setOperationAction(ISD::EH_LABEL, MVT::Other, Expand); + if (Subtarget->is64Bit()) { + setOperationAction(ISD::UMUL_LOHI, MVT::i64, Expand); + setOperationAction(ISD::SMUL_LOHI, MVT::i64, Expand); + setOperationAction(ISD::MULHU, MVT::i64, Expand); + setOperationAction(ISD::MULHS, MVT::i64, Expand); + } // VASTART needs to be custom lowered to use the VarArgsFrameIndex. setOperationAction(ISD::VASTART , MVT::Other, Custom); @@ -1366,14 +1481,100 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) setOperationAction(ISD::STACKRESTORE , MVT::Other, Expand); setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32 , Custom); - // No debug info support yet. - setOperationAction(ISD::EH_LABEL, MVT::Other, Expand); + setExceptionPointerRegister(SP::I0); + setExceptionSelectorRegister(SP::I1); setStackPointerRegisterToSaveRestore(SP::O6); if (Subtarget->isV9()) setOperationAction(ISD::CTPOP, MVT::i32, Legal); + if (Subtarget->isV9() && Subtarget->hasHardQuad()) { + setOperationAction(ISD::LOAD, MVT::f128, Legal); + setOperationAction(ISD::STORE, MVT::f128, Legal); + } else { + setOperationAction(ISD::LOAD, MVT::f128, Custom); + setOperationAction(ISD::STORE, MVT::f128, Custom); + } + + if (Subtarget->hasHardQuad()) { + setOperationAction(ISD::FADD, MVT::f128, Legal); + setOperationAction(ISD::FSUB, MVT::f128, Legal); + setOperationAction(ISD::FMUL, MVT::f128, Legal); + setOperationAction(ISD::FDIV, MVT::f128, Legal); + setOperationAction(ISD::FSQRT, MVT::f128, Legal); + setOperationAction(ISD::FP_EXTEND, MVT::f128, Legal); + setOperationAction(ISD::FP_ROUND, MVT::f64, Legal); + if (Subtarget->isV9()) { + setOperationAction(ISD::FNEG, MVT::f128, Legal); + setOperationAction(ISD::FABS, MVT::f128, Legal); + } else { + setOperationAction(ISD::FNEG, MVT::f128, Custom); + setOperationAction(ISD::FABS, MVT::f128, Custom); + } + + if (!Subtarget->is64Bit()) { + setLibcallName(RTLIB::FPTOSINT_F128_I64, "_Q_qtoll"); + setLibcallName(RTLIB::FPTOUINT_F128_I64, "_Q_qtoull"); + setLibcallName(RTLIB::SINTTOFP_I64_F128, "_Q_lltoq"); + setLibcallName(RTLIB::UINTTOFP_I64_F128, "_Q_ulltoq"); + } + + } else { + // Custom legalize f128 operations. + + setOperationAction(ISD::FADD, MVT::f128, Custom); + setOperationAction(ISD::FSUB, MVT::f128, Custom); + setOperationAction(ISD::FMUL, MVT::f128, Custom); + setOperationAction(ISD::FDIV, MVT::f128, Custom); + setOperationAction(ISD::FSQRT, MVT::f128, Custom); + setOperationAction(ISD::FNEG, MVT::f128, Custom); + setOperationAction(ISD::FABS, MVT::f128, Custom); + + setOperationAction(ISD::FP_EXTEND, MVT::f128, Custom); + setOperationAction(ISD::FP_ROUND, MVT::f64, Custom); + setOperationAction(ISD::FP_ROUND, MVT::f32, Custom); + + // Setup Runtime library names. + if (Subtarget->is64Bit()) { + setLibcallName(RTLIB::ADD_F128, "_Qp_add"); + setLibcallName(RTLIB::SUB_F128, "_Qp_sub"); + setLibcallName(RTLIB::MUL_F128, "_Qp_mul"); + setLibcallName(RTLIB::DIV_F128, "_Qp_div"); + setLibcallName(RTLIB::SQRT_F128, "_Qp_sqrt"); + setLibcallName(RTLIB::FPTOSINT_F128_I32, "_Qp_qtoi"); + setLibcallName(RTLIB::FPTOUINT_F128_I32, "_Qp_qtoui"); + setLibcallName(RTLIB::SINTTOFP_I32_F128, "_Qp_itoq"); + setLibcallName(RTLIB::UINTTOFP_I32_F128, "_Qp_uitoq"); + setLibcallName(RTLIB::FPTOSINT_F128_I64, "_Qp_qtox"); + setLibcallName(RTLIB::FPTOUINT_F128_I64, "_Qp_qtoux"); + setLibcallName(RTLIB::SINTTOFP_I64_F128, "_Qp_xtoq"); + setLibcallName(RTLIB::UINTTOFP_I64_F128, "_Qp_uxtoq"); + setLibcallName(RTLIB::FPEXT_F32_F128, "_Qp_stoq"); + setLibcallName(RTLIB::FPEXT_F64_F128, "_Qp_dtoq"); + setLibcallName(RTLIB::FPROUND_F128_F32, "_Qp_qtos"); + setLibcallName(RTLIB::FPROUND_F128_F64, "_Qp_qtod"); + } else { + setLibcallName(RTLIB::ADD_F128, "_Q_add"); + setLibcallName(RTLIB::SUB_F128, "_Q_sub"); + setLibcallName(RTLIB::MUL_F128, "_Q_mul"); + setLibcallName(RTLIB::DIV_F128, "_Q_div"); + setLibcallName(RTLIB::SQRT_F128, "_Q_sqrt"); + setLibcallName(RTLIB::FPTOSINT_F128_I32, "_Q_qtoi"); + setLibcallName(RTLIB::FPTOUINT_F128_I32, "_Q_qtou"); + setLibcallName(RTLIB::SINTTOFP_I32_F128, "_Q_itoq"); + setLibcallName(RTLIB::UINTTOFP_I32_F128, "_Q_utoq"); + setLibcallName(RTLIB::FPTOSINT_F128_I64, "_Q_qtoll"); + setLibcallName(RTLIB::FPTOUINT_F128_I64, "_Q_qtoull"); + setLibcallName(RTLIB::SINTTOFP_I64_F128, "_Q_lltoq"); + setLibcallName(RTLIB::UINTTOFP_I64_F128, "_Q_ulltoq"); + setLibcallName(RTLIB::FPEXT_F32_F128, "_Q_stoq"); + setLibcallName(RTLIB::FPEXT_F64_F128, "_Q_dtoq"); + setLibcallName(RTLIB::FPROUND_F128_F32, "_Q_qtos"); + setLibcallName(RTLIB::FPROUND_F128_F64, "_Q_qtod"); + } + } + setMinFunctionAlignment(2); computeRegisterProperties(); @@ -1394,13 +1595,24 @@ const char *SparcTargetLowering::getTargetNodeName(unsigned Opcode) const { case SPISD::Lo: return "SPISD::Lo"; case SPISD::FTOI: return "SPISD::FTOI"; case SPISD::ITOF: return "SPISD::ITOF"; + case SPISD::FTOX: return "SPISD::FTOX"; + case SPISD::XTOF: return "SPISD::XTOF"; case SPISD::CALL: return "SPISD::CALL"; case SPISD::RET_FLAG: return "SPISD::RET_FLAG"; case SPISD::GLOBAL_BASE_REG: return "SPISD::GLOBAL_BASE_REG"; case SPISD::FLUSHW: return "SPISD::FLUSHW"; + case SPISD::TLS_ADD: return "SPISD::TLS_ADD"; + case SPISD::TLS_LD: return "SPISD::TLS_LD"; + case SPISD::TLS_CALL: return "SPISD::TLS_CALL"; } } +EVT SparcTargetLowering::getSetCCResultType(LLVMContext &, EVT VT) const { + if (!VT.isVector()) + return MVT::i32; + return VT.changeVectorElementTypeToInteger(); +} + /// isMaskedValueZeroForTargetNode - Return true if 'Op & Mask' is known to /// be zero. Op is expected to be a target specific node. Used by DAG /// combiner. @@ -1505,6 +1717,10 @@ SDValue SparcTargetLowering::makeAddress(SDValue Op, SelectionDAG &DAG) const { SDValue HiLo = makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG); SDValue GlobalBase = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, VT); SDValue AbsAddr = DAG.getNode(ISD::ADD, DL, VT, GlobalBase, HiLo); + // GLOBAL_BASE_REG codegen'ed with call. Inform MFI that this + // function has calls. + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + MFI->setHasCalls(true); return DAG.getLoad(VT, DL, DAG.getEntryNode(), AbsAddr, MachinePointerInfo::getGOT(), false, false, false, 0); } @@ -1513,6 +1729,7 @@ SDValue SparcTargetLowering::makeAddress(SDValue Op, SelectionDAG &DAG) const { switch(getTargetMachine().getCodeModel()) { default: llvm_unreachable("Unsupported absolute code model"); + case CodeModel::JITDefault: case CodeModel::Small: // abs32. return makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG); @@ -1549,23 +1766,430 @@ SDValue SparcTargetLowering::LowerBlockAddress(SDValue Op, return makeAddress(Op, DAG); } -static SDValue LowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG) { +SDValue SparcTargetLowering::LowerGlobalTLSAddress(SDValue Op, + SelectionDAG &DAG) const { + + GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op); + SDLoc DL(GA); + const GlobalValue *GV = GA->getGlobal(); + EVT PtrVT = getPointerTy(); + + TLSModel::Model model = getTargetMachine().getTLSModel(GV); + + if (model == TLSModel::GeneralDynamic || model == TLSModel::LocalDynamic) { + unsigned HiTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_HI22 + : SPII::MO_TLS_LDM_HI22); + unsigned LoTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_LO10 + : SPII::MO_TLS_LDM_LO10); + unsigned addTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_ADD + : SPII::MO_TLS_LDM_ADD); + unsigned callTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_CALL + : SPII::MO_TLS_LDM_CALL); + + SDValue HiLo = makeHiLoPair(Op, HiTF, LoTF, DAG); + SDValue Base = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, PtrVT); + SDValue Argument = DAG.getNode(SPISD::TLS_ADD, DL, PtrVT, Base, HiLo, + withTargetFlags(Op, addTF, DAG)); + + SDValue Chain = DAG.getEntryNode(); + SDValue InFlag; + + Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(1, true), DL); + Chain = DAG.getCopyToReg(Chain, DL, SP::O0, Argument, InFlag); + InFlag = Chain.getValue(1); + SDValue Callee = DAG.getTargetExternalSymbol("__tls_get_addr", PtrVT); + SDValue Symbol = withTargetFlags(Op, callTF, DAG); + + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); + SmallVector<SDValue, 4> Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + Ops.push_back(Symbol); + Ops.push_back(DAG.getRegister(SP::O0, PtrVT)); + const uint32_t *Mask = getTargetMachine() + .getRegisterInfo()->getCallPreservedMask(CallingConv::C); + assert(Mask && "Missing call preserved mask for calling convention"); + Ops.push_back(DAG.getRegisterMask(Mask)); + Ops.push_back(InFlag); + Chain = DAG.getNode(SPISD::TLS_CALL, DL, NodeTys, &Ops[0], Ops.size()); + InFlag = Chain.getValue(1); + Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(1, true), + DAG.getIntPtrConstant(0, true), InFlag, DL); + InFlag = Chain.getValue(1); + SDValue Ret = DAG.getCopyFromReg(Chain, DL, SP::O0, PtrVT, InFlag); + + if (model != TLSModel::LocalDynamic) + return Ret; + + SDValue Hi = DAG.getNode(SPISD::Hi, DL, PtrVT, + withTargetFlags(Op, SPII::MO_TLS_LDO_HIX22, DAG)); + SDValue Lo = DAG.getNode(SPISD::Lo, DL, PtrVT, + withTargetFlags(Op, SPII::MO_TLS_LDO_LOX10, DAG)); + HiLo = DAG.getNode(ISD::XOR, DL, PtrVT, Hi, Lo); + return DAG.getNode(SPISD::TLS_ADD, DL, PtrVT, Ret, HiLo, + withTargetFlags(Op, SPII::MO_TLS_LDO_ADD, DAG)); + } + + if (model == TLSModel::InitialExec) { + unsigned ldTF = ((PtrVT == MVT::i64)? SPII::MO_TLS_IE_LDX + : SPII::MO_TLS_IE_LD); + + SDValue Base = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, PtrVT); + + // GLOBAL_BASE_REG codegen'ed with call. Inform MFI that this + // function has calls. + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + MFI->setHasCalls(true); + + SDValue TGA = makeHiLoPair(Op, + SPII::MO_TLS_IE_HI22, SPII::MO_TLS_IE_LO10, DAG); + SDValue Ptr = DAG.getNode(ISD::ADD, DL, PtrVT, Base, TGA); + SDValue Offset = DAG.getNode(SPISD::TLS_LD, + DL, PtrVT, Ptr, + withTargetFlags(Op, ldTF, DAG)); + return DAG.getNode(SPISD::TLS_ADD, DL, PtrVT, + DAG.getRegister(SP::G7, PtrVT), Offset, + withTargetFlags(Op, SPII::MO_TLS_IE_ADD, DAG)); + } + + assert(model == TLSModel::LocalExec); + SDValue Hi = DAG.getNode(SPISD::Hi, DL, PtrVT, + withTargetFlags(Op, SPII::MO_TLS_LE_HIX22, DAG)); + SDValue Lo = DAG.getNode(SPISD::Lo, DL, PtrVT, + withTargetFlags(Op, SPII::MO_TLS_LE_LOX10, DAG)); + SDValue Offset = DAG.getNode(ISD::XOR, DL, PtrVT, Hi, Lo); + + return DAG.getNode(ISD::ADD, DL, PtrVT, + DAG.getRegister(SP::G7, PtrVT), Offset); +} + +SDValue +SparcTargetLowering::LowerF128_LibCallArg(SDValue Chain, ArgListTy &Args, + SDValue Arg, SDLoc DL, + SelectionDAG &DAG) const { + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + EVT ArgVT = Arg.getValueType(); + Type *ArgTy = ArgVT.getTypeForEVT(*DAG.getContext()); + + ArgListEntry Entry; + Entry.Node = Arg; + Entry.Ty = ArgTy; + + if (ArgTy->isFP128Ty()) { + // Create a stack object and pass the pointer to the library function. + int FI = MFI->CreateStackObject(16, 8, false); + SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy()); + Chain = DAG.getStore(Chain, + DL, + Entry.Node, + FIPtr, + MachinePointerInfo(), + false, + false, + 8); + + Entry.Node = FIPtr; + Entry.Ty = PointerType::getUnqual(ArgTy); + } + Args.push_back(Entry); + return Chain; +} + +SDValue +SparcTargetLowering::LowerF128Op(SDValue Op, SelectionDAG &DAG, + const char *LibFuncName, + unsigned numArgs) const { + + ArgListTy Args; + + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + + SDValue Callee = DAG.getExternalSymbol(LibFuncName, getPointerTy()); + Type *RetTy = Op.getValueType().getTypeForEVT(*DAG.getContext()); + Type *RetTyABI = RetTy; + SDValue Chain = DAG.getEntryNode(); + SDValue RetPtr; + + if (RetTy->isFP128Ty()) { + // Create a Stack Object to receive the return value of type f128. + ArgListEntry Entry; + int RetFI = MFI->CreateStackObject(16, 8, false); + RetPtr = DAG.getFrameIndex(RetFI, getPointerTy()); + Entry.Node = RetPtr; + Entry.Ty = PointerType::getUnqual(RetTy); + if (!Subtarget->is64Bit()) + Entry.isSRet = true; + Entry.isReturned = false; + Args.push_back(Entry); + RetTyABI = Type::getVoidTy(*DAG.getContext()); + } + + assert(Op->getNumOperands() >= numArgs && "Not enough operands!"); + for (unsigned i = 0, e = numArgs; i != e; ++i) { + Chain = LowerF128_LibCallArg(Chain, Args, Op.getOperand(i), SDLoc(Op), DAG); + } + TargetLowering:: + CallLoweringInfo CLI(Chain, + RetTyABI, + false, false, false, false, + 0, CallingConv::C, + false, false, true, + Callee, Args, DAG, SDLoc(Op)); + std::pair<SDValue, SDValue> CallInfo = LowerCallTo(CLI); + + // chain is in second result. + if (RetTyABI == RetTy) + return CallInfo.first; + + assert (RetTy->isFP128Ty() && "Unexpected return type!"); + + Chain = CallInfo.second; + + // Load RetPtr to get the return value. + return DAG.getLoad(Op.getValueType(), + SDLoc(Op), + Chain, + RetPtr, + MachinePointerInfo(), + false, false, false, 8); +} + +SDValue +SparcTargetLowering::LowerF128Compare(SDValue LHS, SDValue RHS, + unsigned &SPCC, + SDLoc DL, + SelectionDAG &DAG) const { + + const char *LibCall = 0; + bool is64Bit = Subtarget->is64Bit(); + switch(SPCC) { + default: llvm_unreachable("Unhandled conditional code!"); + case SPCC::FCC_E : LibCall = is64Bit? "_Qp_feq" : "_Q_feq"; break; + case SPCC::FCC_NE : LibCall = is64Bit? "_Qp_fne" : "_Q_fne"; break; + case SPCC::FCC_L : LibCall = is64Bit? "_Qp_flt" : "_Q_flt"; break; + case SPCC::FCC_G : LibCall = is64Bit? "_Qp_fgt" : "_Q_fgt"; break; + case SPCC::FCC_LE : LibCall = is64Bit? "_Qp_fle" : "_Q_fle"; break; + case SPCC::FCC_GE : LibCall = is64Bit? "_Qp_fge" : "_Q_fge"; break; + case SPCC::FCC_UL : + case SPCC::FCC_ULE: + case SPCC::FCC_UG : + case SPCC::FCC_UGE: + case SPCC::FCC_U : + case SPCC::FCC_O : + case SPCC::FCC_LG : + case SPCC::FCC_UE : LibCall = is64Bit? "_Qp_cmp" : "_Q_cmp"; break; + } + + SDValue Callee = DAG.getExternalSymbol(LibCall, getPointerTy()); + Type *RetTy = Type::getInt32Ty(*DAG.getContext()); + ArgListTy Args; + SDValue Chain = DAG.getEntryNode(); + Chain = LowerF128_LibCallArg(Chain, Args, LHS, DL, DAG); + Chain = LowerF128_LibCallArg(Chain, Args, RHS, DL, DAG); + + TargetLowering:: + CallLoweringInfo CLI(Chain, + RetTy, + false, false, false, false, + 0, CallingConv::C, + false, false, true, + Callee, Args, DAG, DL); + + std::pair<SDValue, SDValue> CallInfo = LowerCallTo(CLI); + + // result is in first, and chain is in second result. + SDValue Result = CallInfo.first; + + switch(SPCC) { + default: { + SDValue RHS = DAG.getTargetConstant(0, Result.getValueType()); + SPCC = SPCC::ICC_NE; + return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); + } + case SPCC::FCC_UL : { + SDValue Mask = DAG.getTargetConstant(1, Result.getValueType()); + Result = DAG.getNode(ISD::AND, DL, Result.getValueType(), Result, Mask); + SDValue RHS = DAG.getTargetConstant(0, Result.getValueType()); + SPCC = SPCC::ICC_NE; + return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); + } + case SPCC::FCC_ULE: { + SDValue RHS = DAG.getTargetConstant(2, Result.getValueType()); + SPCC = SPCC::ICC_NE; + return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); + } + case SPCC::FCC_UG : { + SDValue RHS = DAG.getTargetConstant(1, Result.getValueType()); + SPCC = SPCC::ICC_G; + return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); + } + case SPCC::FCC_UGE: { + SDValue RHS = DAG.getTargetConstant(1, Result.getValueType()); + SPCC = SPCC::ICC_NE; + return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); + } + + case SPCC::FCC_U : { + SDValue RHS = DAG.getTargetConstant(3, Result.getValueType()); + SPCC = SPCC::ICC_E; + return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); + } + case SPCC::FCC_O : { + SDValue RHS = DAG.getTargetConstant(3, Result.getValueType()); + SPCC = SPCC::ICC_NE; + return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); + } + case SPCC::FCC_LG : { + SDValue Mask = DAG.getTargetConstant(3, Result.getValueType()); + Result = DAG.getNode(ISD::AND, DL, Result.getValueType(), Result, Mask); + SDValue RHS = DAG.getTargetConstant(0, Result.getValueType()); + SPCC = SPCC::ICC_NE; + return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); + } + case SPCC::FCC_UE : { + SDValue Mask = DAG.getTargetConstant(3, Result.getValueType()); + Result = DAG.getNode(ISD::AND, DL, Result.getValueType(), Result, Mask); + SDValue RHS = DAG.getTargetConstant(0, Result.getValueType()); + SPCC = SPCC::ICC_E; + return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); + } + } +} + +static SDValue +LowerF128_FPEXTEND(SDValue Op, SelectionDAG &DAG, + const SparcTargetLowering &TLI) { + + if (Op.getOperand(0).getValueType() == MVT::f64) + return TLI.LowerF128Op(Op, DAG, + TLI.getLibcallName(RTLIB::FPEXT_F64_F128), 1); + + if (Op.getOperand(0).getValueType() == MVT::f32) + return TLI.LowerF128Op(Op, DAG, + TLI.getLibcallName(RTLIB::FPEXT_F32_F128), 1); + + llvm_unreachable("fpextend with non-float operand!"); + return SDValue(0, 0); +} + +static SDValue +LowerF128_FPROUND(SDValue Op, SelectionDAG &DAG, + const SparcTargetLowering &TLI) { + // FP_ROUND on f64 and f32 are legal. + if (Op.getOperand(0).getValueType() != MVT::f128) + return Op; + + if (Op.getValueType() == MVT::f64) + return TLI.LowerF128Op(Op, DAG, + TLI.getLibcallName(RTLIB::FPROUND_F128_F64), 1); + if (Op.getValueType() == MVT::f32) + return TLI.LowerF128Op(Op, DAG, + TLI.getLibcallName(RTLIB::FPROUND_F128_F32), 1); + + llvm_unreachable("fpround to non-float!"); + return SDValue(0, 0); +} + +static SDValue LowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG, + const SparcTargetLowering &TLI, + bool hasHardQuad) { + SDLoc dl(Op); + EVT VT = Op.getValueType(); + assert(VT == MVT::i32 || VT == MVT::i64); + + // Expand f128 operations to fp128 abi calls. + if (Op.getOperand(0).getValueType() == MVT::f128 + && (!hasHardQuad || !TLI.isTypeLegal(VT))) { + const char *libName = TLI.getLibcallName(VT == MVT::i32 + ? RTLIB::FPTOSINT_F128_I32 + : RTLIB::FPTOSINT_F128_I64); + return TLI.LowerF128Op(Op, DAG, libName, 1); + } + + // Expand if the resulting type is illegal. + if (!TLI.isTypeLegal(VT)) + return SDValue(0, 0); + + // Otherwise, Convert the fp value to integer in an FP register. + if (VT == MVT::i32) + Op = DAG.getNode(SPISD::FTOI, dl, MVT::f32, Op.getOperand(0)); + else + Op = DAG.getNode(SPISD::FTOX, dl, MVT::f64, Op.getOperand(0)); + + return DAG.getNode(ISD::BITCAST, dl, VT, Op); +} + +static SDValue LowerSINT_TO_FP(SDValue Op, SelectionDAG &DAG, + const SparcTargetLowering &TLI, + bool hasHardQuad) { + SDLoc dl(Op); + EVT OpVT = Op.getOperand(0).getValueType(); + assert(OpVT == MVT::i32 || (OpVT == MVT::i64)); + + EVT floatVT = (OpVT == MVT::i32) ? MVT::f32 : MVT::f64; + + // Expand f128 operations to fp128 ABI calls. + if (Op.getValueType() == MVT::f128 + && (!hasHardQuad || !TLI.isTypeLegal(OpVT))) { + const char *libName = TLI.getLibcallName(OpVT == MVT::i32 + ? RTLIB::SINTTOFP_I32_F128 + : RTLIB::SINTTOFP_I64_F128); + return TLI.LowerF128Op(Op, DAG, libName, 1); + } + + // Expand if the operand type is illegal. + if (!TLI.isTypeLegal(OpVT)) + return SDValue(0, 0); + + // Otherwise, Convert the int value to FP in an FP register. + SDValue Tmp = DAG.getNode(ISD::BITCAST, dl, floatVT, Op.getOperand(0)); + unsigned opcode = (OpVT == MVT::i32)? SPISD::ITOF : SPISD::XTOF; + return DAG.getNode(opcode, dl, Op.getValueType(), Tmp); +} + +static SDValue LowerFP_TO_UINT(SDValue Op, SelectionDAG &DAG, + const SparcTargetLowering &TLI, + bool hasHardQuad) { SDLoc dl(Op); - // Convert the fp value to integer in an FP register. - assert(Op.getValueType() == MVT::i32); - Op = DAG.getNode(SPISD::FTOI, dl, MVT::f32, Op.getOperand(0)); - return DAG.getNode(ISD::BITCAST, dl, MVT::i32, Op); + EVT VT = Op.getValueType(); + + // Expand if it does not involve f128 or the target has support for + // quad floating point instructions and the resulting type is legal. + if (Op.getOperand(0).getValueType() != MVT::f128 || + (hasHardQuad && TLI.isTypeLegal(VT))) + return SDValue(0, 0); + + assert(VT == MVT::i32 || VT == MVT::i64); + + return TLI.LowerF128Op(Op, DAG, + TLI.getLibcallName(VT == MVT::i32 + ? RTLIB::FPTOUINT_F128_I32 + : RTLIB::FPTOUINT_F128_I64), + 1); } -static SDValue LowerSINT_TO_FP(SDValue Op, SelectionDAG &DAG) { +static SDValue LowerUINT_TO_FP(SDValue Op, SelectionDAG &DAG, + const SparcTargetLowering &TLI, + bool hasHardQuad) { SDLoc dl(Op); - assert(Op.getOperand(0).getValueType() == MVT::i32); - SDValue Tmp = DAG.getNode(ISD::BITCAST, dl, MVT::f32, Op.getOperand(0)); - // Convert the int value to FP in an FP register. - return DAG.getNode(SPISD::ITOF, dl, Op.getValueType(), Tmp); + EVT OpVT = Op.getOperand(0).getValueType(); + assert(OpVT == MVT::i32 || OpVT == MVT::i64); + + // Expand if it does not involve f128 or the target has support for + // quad floating point instructions and the operand type is legal. + if (Op.getValueType() != MVT::f128 || (hasHardQuad && TLI.isTypeLegal(OpVT))) + return SDValue(0, 0); + + return TLI.LowerF128Op(Op, DAG, + TLI.getLibcallName(OpVT == MVT::i32 + ? RTLIB::UINTTOFP_I32_F128 + : RTLIB::UINTTOFP_I64_F128), + 1); } -static SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) { +static SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG, + const SparcTargetLowering &TLI, + bool hasHardQuad) { SDValue Chain = Op.getOperand(0); ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get(); SDValue LHS = Op.getOperand(2); @@ -1586,15 +2210,23 @@ static SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) { // 32-bit compares use the icc flags, 64-bit uses the xcc flags. Opc = LHS.getValueType() == MVT::i32 ? SPISD::BRICC : SPISD::BRXCC; } else { - CompareFlag = DAG.getNode(SPISD::CMPFCC, dl, MVT::Glue, LHS, RHS); - if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC); - Opc = SPISD::BRFCC; + if (!hasHardQuad && LHS.getValueType() == MVT::f128) { + if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC); + CompareFlag = TLI.LowerF128Compare(LHS, RHS, SPCC, dl, DAG); + Opc = SPISD::BRICC; + } else { + CompareFlag = DAG.getNode(SPISD::CMPFCC, dl, MVT::Glue, LHS, RHS); + if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC); + Opc = SPISD::BRFCC; + } } return DAG.getNode(Opc, dl, MVT::Other, Chain, Dest, DAG.getConstant(SPCC, MVT::i32), CompareFlag); } -static SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) { +static SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG, + const SparcTargetLowering &TLI, + bool hasHardQuad) { SDValue LHS = Op.getOperand(0); SDValue RHS = Op.getOperand(1); ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get(); @@ -1614,9 +2246,15 @@ static SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) { SPISD::SELECT_ICC : SPISD::SELECT_XCC; if (SPCC == ~0U) SPCC = IntCondCCodeToICC(CC); } else { - CompareFlag = DAG.getNode(SPISD::CMPFCC, dl, MVT::Glue, LHS, RHS); - Opc = SPISD::SELECT_FCC; - if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC); + if (!hasHardQuad && LHS.getValueType() == MVT::f128) { + if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC); + CompareFlag = TLI.LowerF128Compare(LHS, RHS, SPCC, dl, DAG); + Opc = SPISD::SELECT_ICC; + } else { + CompareFlag = DAG.getNode(SPISD::CMPFCC, dl, MVT::Glue, LHS, RHS); + Opc = SPISD::SELECT_FCC; + if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC); + } } return DAG.getNode(Opc, dl, TrueVal.getValueType(), TrueVal, FalseVal, DAG.getConstant(SPCC, MVT::i32), CompareFlag); @@ -1665,20 +2303,25 @@ static SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) { std::min(PtrVT.getSizeInBits(), VT.getSizeInBits())/8); } -static SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) { +static SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG, + const SparcSubtarget *Subtarget) { SDValue Chain = Op.getOperand(0); // Legalize the chain. SDValue Size = Op.getOperand(1); // Legalize the size. + EVT VT = Size->getValueType(0); SDLoc dl(Op); unsigned SPReg = SP::O6; - SDValue SP = DAG.getCopyFromReg(Chain, dl, SPReg, MVT::i32); - SDValue NewSP = DAG.getNode(ISD::SUB, dl, MVT::i32, SP, Size); // Value + SDValue SP = DAG.getCopyFromReg(Chain, dl, SPReg, VT); + SDValue NewSP = DAG.getNode(ISD::SUB, dl, VT, SP, Size); // Value Chain = DAG.getCopyToReg(SP.getValue(1), dl, SPReg, NewSP); // Output chain // The resultant pointer is actually 16 words from the bottom of the stack, // to provide a register spill area. - SDValue NewVal = DAG.getNode(ISD::ADD, dl, MVT::i32, NewSP, - DAG.getConstant(96, MVT::i32)); + unsigned regSpillArea = Subtarget->is64Bit() ? 128 : 96; + regSpillArea += Subtarget->getStackPointerBias(); + + SDValue NewVal = DAG.getNode(ISD::ADD, dl, VT, NewSP, + DAG.getConstant(regSpillArea, VT)); SDValue Ops[2] = { NewVal, Chain }; return DAG.getMergeValues(Ops, 2, dl); } @@ -1759,12 +2402,12 @@ static SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG, return RetAddr; } -static SDValue LowerF64Op(SDValue Op, SelectionDAG &DAG) +static SDValue LowerF64Op(SDValue Op, SelectionDAG &DAG, unsigned opcode) { SDLoc dl(Op); assert(Op.getValueType() == MVT::f64 && "LowerF64Op called on non-double!"); - assert(Op.getOpcode() == ISD::FNEG || Op.getOpcode() == ISD::FABS); + assert(opcode == ISD::FNEG || opcode == ISD::FABS); // Lower fneg/fabs on f64 to fneg/fabs on f32. // fneg f64 => fneg f32:sub_even, fmov f32:sub_odd. @@ -1776,7 +2419,7 @@ static SDValue LowerF64Op(SDValue Op, SelectionDAG &DAG) SDValue Lo32 = DAG.getTargetExtractSubreg(SP::sub_odd, dl, MVT::f32, SrcReg64); - Hi32 = DAG.getNode(Op.getOpcode(), dl, MVT::f32, Hi32); + Hi32 = DAG.getNode(opcode, dl, MVT::f32, Hi32); SDValue DstReg64 = SDValue(DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, MVT::f64), 0); @@ -1787,28 +2430,244 @@ static SDValue LowerF64Op(SDValue Op, SelectionDAG &DAG) return DstReg64; } +// Lower a f128 load into two f64 loads. +static SDValue LowerF128Load(SDValue Op, SelectionDAG &DAG) +{ + SDLoc dl(Op); + LoadSDNode *LdNode = dyn_cast<LoadSDNode>(Op.getNode()); + assert(LdNode && LdNode->getOffset().getOpcode() == ISD::UNDEF + && "Unexpected node type"); + + unsigned alignment = LdNode->getAlignment(); + if (alignment > 8) + alignment = 8; + + SDValue Hi64 = DAG.getLoad(MVT::f64, + dl, + LdNode->getChain(), + LdNode->getBasePtr(), + LdNode->getPointerInfo(), + false, false, false, alignment); + EVT addrVT = LdNode->getBasePtr().getValueType(); + SDValue LoPtr = DAG.getNode(ISD::ADD, dl, addrVT, + LdNode->getBasePtr(), + DAG.getConstant(8, addrVT)); + SDValue Lo64 = DAG.getLoad(MVT::f64, + dl, + LdNode->getChain(), + LoPtr, + LdNode->getPointerInfo(), + false, false, false, alignment); + + SDValue SubRegEven = DAG.getTargetConstant(SP::sub_even64, MVT::i32); + SDValue SubRegOdd = DAG.getTargetConstant(SP::sub_odd64, MVT::i32); + + SDNode *InFP128 = DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF, + dl, MVT::f128); + InFP128 = DAG.getMachineNode(TargetOpcode::INSERT_SUBREG, dl, + MVT::f128, + SDValue(InFP128, 0), + Hi64, + SubRegEven); + InFP128 = DAG.getMachineNode(TargetOpcode::INSERT_SUBREG, dl, + MVT::f128, + SDValue(InFP128, 0), + Lo64, + SubRegOdd); + SDValue OutChains[2] = { SDValue(Hi64.getNode(), 1), + SDValue(Lo64.getNode(), 1) }; + SDValue OutChain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + &OutChains[0], 2); + SDValue Ops[2] = {SDValue(InFP128,0), OutChain}; + return DAG.getMergeValues(Ops, 2, dl); +} + +// Lower a f128 store into two f64 stores. +static SDValue LowerF128Store(SDValue Op, SelectionDAG &DAG) { + SDLoc dl(Op); + StoreSDNode *StNode = dyn_cast<StoreSDNode>(Op.getNode()); + assert(StNode && StNode->getOffset().getOpcode() == ISD::UNDEF + && "Unexpected node type"); + SDValue SubRegEven = DAG.getTargetConstant(SP::sub_even64, MVT::i32); + SDValue SubRegOdd = DAG.getTargetConstant(SP::sub_odd64, MVT::i32); + + SDNode *Hi64 = DAG.getMachineNode(TargetOpcode::EXTRACT_SUBREG, + dl, + MVT::f64, + StNode->getValue(), + SubRegEven); + SDNode *Lo64 = DAG.getMachineNode(TargetOpcode::EXTRACT_SUBREG, + dl, + MVT::f64, + StNode->getValue(), + SubRegOdd); + + unsigned alignment = StNode->getAlignment(); + if (alignment > 8) + alignment = 8; + + SDValue OutChains[2]; + OutChains[0] = DAG.getStore(StNode->getChain(), + dl, + SDValue(Hi64, 0), + StNode->getBasePtr(), + MachinePointerInfo(), + false, false, alignment); + EVT addrVT = StNode->getBasePtr().getValueType(); + SDValue LoPtr = DAG.getNode(ISD::ADD, dl, addrVT, + StNode->getBasePtr(), + DAG.getConstant(8, addrVT)); + OutChains[1] = DAG.getStore(StNode->getChain(), + dl, + SDValue(Lo64, 0), + LoPtr, + MachinePointerInfo(), + false, false, alignment); + return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + &OutChains[0], 2); +} + +static SDValue LowerFNEG(SDValue Op, SelectionDAG &DAG, + const SparcTargetLowering &TLI, + bool is64Bit) { + if (Op.getValueType() == MVT::f64) + return LowerF64Op(Op, DAG, ISD::FNEG); + if (Op.getValueType() == MVT::f128) + return TLI.LowerF128Op(Op, DAG, ((is64Bit) ? "_Qp_neg" : "_Q_neg"), 1); + return Op; +} + +static SDValue LowerFABS(SDValue Op, SelectionDAG &DAG, bool isV9) { + if (Op.getValueType() == MVT::f64) + return LowerF64Op(Op, DAG, ISD::FABS); + if (Op.getValueType() != MVT::f128) + return Op; + + // Lower fabs on f128 to fabs on f64 + // fabs f128 => fabs f64:sub_even64, fmov f64:sub_odd64 + + SDLoc dl(Op); + SDValue SrcReg128 = Op.getOperand(0); + SDValue Hi64 = DAG.getTargetExtractSubreg(SP::sub_even64, dl, MVT::f64, + SrcReg128); + SDValue Lo64 = DAG.getTargetExtractSubreg(SP::sub_odd64, dl, MVT::f64, + SrcReg128); + if (isV9) + Hi64 = DAG.getNode(Op.getOpcode(), dl, MVT::f64, Hi64); + else + Hi64 = LowerF64Op(Hi64, DAG, ISD::FABS); + + SDValue DstReg128 = SDValue(DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF, + dl, MVT::f128), 0); + DstReg128 = DAG.getTargetInsertSubreg(SP::sub_even64, dl, MVT::f128, + DstReg128, Hi64); + DstReg128 = DAG.getTargetInsertSubreg(SP::sub_odd64, dl, MVT::f128, + DstReg128, Lo64); + return DstReg128; +} + +static SDValue LowerADDC_ADDE_SUBC_SUBE(SDValue Op, SelectionDAG &DAG) { + + if (Op.getValueType() != MVT::i64) + return Op; + + SDLoc dl(Op); + SDValue Src1 = Op.getOperand(0); + SDValue Src1Lo = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src1); + SDValue Src1Hi = DAG.getNode(ISD::SRL, dl, MVT::i64, Src1, + DAG.getConstant(32, MVT::i64)); + Src1Hi = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src1Hi); + + SDValue Src2 = Op.getOperand(1); + SDValue Src2Lo = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src2); + SDValue Src2Hi = DAG.getNode(ISD::SRL, dl, MVT::i64, Src2, + DAG.getConstant(32, MVT::i64)); + Src2Hi = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src2Hi); + + + bool hasChain = false; + unsigned hiOpc = Op.getOpcode(); + switch (Op.getOpcode()) { + default: llvm_unreachable("Invalid opcode"); + case ISD::ADDC: hiOpc = ISD::ADDE; break; + case ISD::ADDE: hasChain = true; break; + case ISD::SUBC: hiOpc = ISD::SUBE; break; + case ISD::SUBE: hasChain = true; break; + } + SDValue Lo; + SDVTList VTs = DAG.getVTList(MVT::i32, MVT::Glue); + if (hasChain) { + Lo = DAG.getNode(Op.getOpcode(), dl, VTs, Src1Lo, Src2Lo, + Op.getOperand(2)); + } else { + Lo = DAG.getNode(Op.getOpcode(), dl, VTs, Src1Lo, Src2Lo); + } + SDValue Hi = DAG.getNode(hiOpc, dl, VTs, Src1Hi, Src2Hi, Lo.getValue(1)); + SDValue Carry = Hi.getValue(1); + + Lo = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i64, Lo); + Hi = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i64, Hi); + Hi = DAG.getNode(ISD::SHL, dl, MVT::i64, Hi, + DAG.getConstant(32, MVT::i64)); + + SDValue Dst = DAG.getNode(ISD::OR, dl, MVT::i64, Hi, Lo); + SDValue Ops[2] = { Dst, Carry }; + return DAG.getMergeValues(Ops, 2, dl); +} + SDValue SparcTargetLowering:: LowerOperation(SDValue Op, SelectionDAG &DAG) const { + + bool hasHardQuad = Subtarget->hasHardQuad(); + bool is64Bit = Subtarget->is64Bit(); + bool isV9 = Subtarget->isV9(); + switch (Op.getOpcode()) { default: llvm_unreachable("Should not custom lower this!"); - case ISD::FNEG: - case ISD::FABS: return LowerF64Op(Op, DAG); - case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG, *this); case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG); - case ISD::GlobalTLSAddress: - llvm_unreachable("TLS not implemented for Sparc."); + case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG); case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); case ISD::BlockAddress: return LowerBlockAddress(Op, DAG); case ISD::ConstantPool: return LowerConstantPool(Op, DAG); - case ISD::FP_TO_SINT: return LowerFP_TO_SINT(Op, DAG); - case ISD::SINT_TO_FP: return LowerSINT_TO_FP(Op, DAG); - case ISD::BR_CC: return LowerBR_CC(Op, DAG); - case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG); + case ISD::FP_TO_SINT: return LowerFP_TO_SINT(Op, DAG, *this, + hasHardQuad); + case ISD::SINT_TO_FP: return LowerSINT_TO_FP(Op, DAG, *this, + hasHardQuad); + case ISD::FP_TO_UINT: return LowerFP_TO_UINT(Op, DAG, *this, + hasHardQuad); + case ISD::UINT_TO_FP: return LowerUINT_TO_FP(Op, DAG, *this, + hasHardQuad); + case ISD::BR_CC: return LowerBR_CC(Op, DAG, *this, + hasHardQuad); + case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG, *this, + hasHardQuad); case ISD::VASTART: return LowerVASTART(Op, DAG, *this); case ISD::VAARG: return LowerVAARG(Op, DAG); - case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG); + case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG, + Subtarget); + + case ISD::LOAD: return LowerF128Load(Op, DAG); + case ISD::STORE: return LowerF128Store(Op, DAG); + case ISD::FADD: return LowerF128Op(Op, DAG, + getLibcallName(RTLIB::ADD_F128), 2); + case ISD::FSUB: return LowerF128Op(Op, DAG, + getLibcallName(RTLIB::SUB_F128), 2); + case ISD::FMUL: return LowerF128Op(Op, DAG, + getLibcallName(RTLIB::MUL_F128), 2); + case ISD::FDIV: return LowerF128Op(Op, DAG, + getLibcallName(RTLIB::DIV_F128), 2); + case ISD::FSQRT: return LowerF128Op(Op, DAG, + getLibcallName(RTLIB::SQRT_F128),1); + case ISD::FNEG: return LowerFNEG(Op, DAG, *this, is64Bit); + case ISD::FABS: return LowerFABS(Op, DAG, isV9); + case ISD::FP_EXTEND: return LowerF128_FPEXTEND(Op, DAG, *this); + case ISD::FP_ROUND: return LowerF128_FPROUND(Op, DAG, *this); + case ISD::ADDC: + case ISD::ADDE: + case ISD::SUBC: + case ISD::SUBE: return LowerADDC_ADDE_SUBC_SUBE(Op, DAG); } } @@ -1825,11 +2684,13 @@ SparcTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, case SP::SELECT_CC_Int_ICC: case SP::SELECT_CC_FP_ICC: case SP::SELECT_CC_DFP_ICC: + case SP::SELECT_CC_QFP_ICC: BROpcode = SP::BCOND; break; case SP::SELECT_CC_Int_FCC: case SP::SELECT_CC_FP_FCC: case SP::SELECT_CC_DFP_FCC: + case SP::SELECT_CC_QFP_FCC: BROpcode = SP::FBCOND; break; } @@ -1924,3 +2785,50 @@ SparcTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { // The Sparc target isn't yet aware of offsets. return false; } + +void SparcTargetLowering::ReplaceNodeResults(SDNode *N, + SmallVectorImpl<SDValue>& Results, + SelectionDAG &DAG) const { + + SDLoc dl(N); + + RTLIB::Libcall libCall = RTLIB::UNKNOWN_LIBCALL; + + switch (N->getOpcode()) { + default: + llvm_unreachable("Do not know how to custom type legalize this operation!"); + + case ISD::FP_TO_SINT: + case ISD::FP_TO_UINT: + // Custom lower only if it involves f128 or i64. + if (N->getOperand(0).getValueType() != MVT::f128 + || N->getValueType(0) != MVT::i64) + return; + libCall = ((N->getOpcode() == ISD::FP_TO_SINT) + ? RTLIB::FPTOSINT_F128_I64 + : RTLIB::FPTOUINT_F128_I64); + + Results.push_back(LowerF128Op(SDValue(N, 0), + DAG, + getLibcallName(libCall), + 1)); + return; + + case ISD::SINT_TO_FP: + case ISD::UINT_TO_FP: + // Custom lower only if it involves f128 or i64. + if (N->getValueType(0) != MVT::f128 + || N->getOperand(0).getValueType() != MVT::i64) + return; + + libCall = ((N->getOpcode() == ISD::SINT_TO_FP) + ? RTLIB::SINTTOFP_I64_F128 + : RTLIB::UINTTOFP_I64_F128); + + Results.push_back(LowerF128Op(SDValue(N, 0), + DAG, + getLibcallName(libCall), + 1)); + return; + } +} diff --git a/lib/Target/Sparc/SparcISelLowering.h b/lib/Target/Sparc/SparcISelLowering.h index 261c25a..2659fc8 100644 --- a/lib/Target/Sparc/SparcISelLowering.h +++ b/lib/Target/Sparc/SparcISelLowering.h @@ -37,11 +37,17 @@ namespace llvm { FTOI, // FP to Int within a FP register. ITOF, // Int to FP within a FP register. + FTOX, // FP to Int64 within a FP register. + XTOF, // Int64 to FP within a FP register. CALL, // A call instruction. RET_FLAG, // Return with a flag operand. - GLOBAL_BASE_REG, // Global base reg for PIC - FLUSHW // FLUSH register windows to stack + GLOBAL_BASE_REG, // Global base reg for PIC. + FLUSHW, // FLUSH register windows to stack. + + TLS_ADD, // For Thread Local Storage (TLS). + TLS_LD, + TLS_CALL }; } @@ -73,6 +79,9 @@ namespace llvm { virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const; virtual MVT getScalarShiftAmountTy(EVT LHSTy) const { return MVT::i32; } + /// getSetCCResultType - Return the ISD::SETCC ValueType + virtual EVT getSetCCResultType(LLVMContext &Context, EVT VT) const; + virtual SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, @@ -119,6 +128,7 @@ namespace llvm { SDLoc DL, SelectionDAG &DAG) const; SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const; SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const; SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; @@ -127,6 +137,27 @@ namespace llvm { SDValue makeHiLoPair(SDValue Op, unsigned HiTF, unsigned LoTF, SelectionDAG &DAG) const; SDValue makeAddress(SDValue Op, SelectionDAG &DAG) const; + + SDValue LowerF128_LibCallArg(SDValue Chain, ArgListTy &Args, + SDValue Arg, SDLoc DL, + SelectionDAG &DAG) const; + SDValue LowerF128Op(SDValue Op, SelectionDAG &DAG, + const char *LibFuncName, + unsigned numArgs) const; + SDValue LowerF128Compare(SDValue LHS, SDValue RHS, + unsigned &SPCC, + SDLoc DL, + SelectionDAG &DAG) const; + + bool ShouldShrinkFPConstant(EVT VT) const { + // Do not shrink FP constpool if VT == MVT::f128. + // (ldd, call _Q_fdtoq) is more expensive than two ldds. + return VT != MVT::f128; + } + + virtual void ReplaceNodeResults(SDNode *N, + SmallVectorImpl<SDValue>& Results, + SelectionDAG &DAG) const; }; } // end namespace llvm diff --git a/lib/Target/Sparc/SparcInstr64Bit.td b/lib/Target/Sparc/SparcInstr64Bit.td index 47658ee..8656de5 100644 --- a/lib/Target/Sparc/SparcInstr64Bit.td +++ b/lib/Target/Sparc/SparcInstr64Bit.td @@ -153,15 +153,11 @@ def : Pat<(xor i64:$a, (not i64:$b)), (XNORrr $a, $b)>; def : Pat<(add i64:$a, i64:$b), (ADDrr $a, $b)>; def : Pat<(sub i64:$a, i64:$b), (SUBrr $a, $b)>; -// Add/sub with carry were renamed to addc/subc in SPARC v9. -def : Pat<(adde i64:$a, i64:$b), (ADDXrr $a, $b)>; -def : Pat<(sube i64:$a, i64:$b), (SUBXrr $a, $b)>; - -def : Pat<(addc i64:$a, i64:$b), (ADDCCrr $a, $b)>; -def : Pat<(subc i64:$a, i64:$b), (SUBCCrr $a, $b)>; - def : Pat<(SPcmpicc i64:$a, i64:$b), (CMPrr $a, $b)>; +def : Pat<(tlsadd i64:$a, i64:$b, tglobaltlsaddr:$sym), + (TLS_ADDrr $a, $b, $sym)>; + // Register-immediate instructions. def : Pat<(and i64:$a, (i64 simm13:$b)), (ANDri $a, (as_i32imm $b))>; @@ -173,6 +169,14 @@ def : Pat<(sub i64:$a, (i64 simm13:$b)), (SUBri $a, (as_i32imm $b))>; def : Pat<(SPcmpicc i64:$a, (i64 simm13:$b)), (CMPri $a, (as_i32imm $b))>; +def : Pat<(ctpop i64:$src), (POPCrr $src)>; + +// "LEA" form of add +def LEAX_ADDri : F3_2<2, 0b000000, + (outs I64Regs:$dst), (ins MEMri:$addr), + "add ${addr:arith}, $dst", + [(set iPTR:$dst, ADDRri:$addr)]>; + } // Predicates = [Is64Bit] @@ -237,6 +241,12 @@ def LDXri : F3_2<3, 0b001011, (outs I64Regs:$dst), (ins MEMri:$addr), "ldx [$addr], $dst", [(set i64:$dst, (load ADDRri:$addr))]>; +let mayLoad = 1 in + def TLS_LDXrr : F3_1<3, 0b001011, + (outs IntRegs:$dst), (ins MEMrr:$addr, TLSSym:$sym), + "ldx [$addr], $dst, $sym", + [(set i64:$dst, + (tlsld ADDRrr:$addr, tglobaltlsaddr:$sym))]>; // Extending loads to i64. def : Pat<(i64 (zextloadi1 ADDRrr:$addr)), (LDUBrr ADDRrr:$addr)>; @@ -312,9 +322,9 @@ def : Pat<(store (i64 0), ADDRri:$dst), (STXri ADDRri:$dst, (i64 G0))>; let Predicates = [Is64Bit] in { let Uses = [ICC] in -def BPXCC : BranchSP<0, (ins brtarget:$dst, CCOp:$cc), - "b$cc %xcc, $dst", - [(SPbrxcc bb:$dst, imm:$cc)]>; +def BPXCC : BranchSP<(ins brtarget:$imm22, CCOp:$cond), + "b$cond %xcc, $imm22", + [(SPbrxcc bb:$imm22, imm:$cond)]>; // Conditional moves on %xcc. let Uses = [ICC], Constraints = "$f = $rd" in { @@ -340,6 +350,42 @@ def FMOVD_XCC : Pseudo<(outs DFPRegs:$rd), (SPselectxcc f64:$rs2, f64:$f, imm:$cond))]>; } // Uses, Constraints +//===----------------------------------------------------------------------===// +// 64-bit Floating Point Conversions. +//===----------------------------------------------------------------------===// + +let Predicates = [Is64Bit] in { + +def FXTOS : F3_3u<2, 0b110100, 0b010000100, + (outs FPRegs:$dst), (ins DFPRegs:$src), + "fxtos $src, $dst", + [(set FPRegs:$dst, (SPxtof DFPRegs:$src))]>; +def FXTOD : F3_3u<2, 0b110100, 0b010001000, + (outs DFPRegs:$dst), (ins DFPRegs:$src), + "fxtod $src, $dst", + [(set DFPRegs:$dst, (SPxtof DFPRegs:$src))]>; +def FXTOQ : F3_3u<2, 0b110100, 0b010001100, + (outs QFPRegs:$dst), (ins DFPRegs:$src), + "fxtoq $src, $dst", + [(set QFPRegs:$dst, (SPxtof DFPRegs:$src))]>, + Requires<[HasHardQuad]>; + +def FSTOX : F3_3u<2, 0b110100, 0b010000001, + (outs DFPRegs:$dst), (ins FPRegs:$src), + "fstox $src, $dst", + [(set DFPRegs:$dst, (SPftox FPRegs:$src))]>; +def FDTOX : F3_3u<2, 0b110100, 0b010000010, + (outs DFPRegs:$dst), (ins DFPRegs:$src), + "fdtox $src, $dst", + [(set DFPRegs:$dst, (SPftox DFPRegs:$src))]>; +def FQTOX : F3_3u<2, 0b110100, 0b010000011, + (outs DFPRegs:$dst), (ins QFPRegs:$src), + "fqtox $src, $dst", + [(set DFPRegs:$dst, (SPftox QFPRegs:$src))]>, + Requires<[HasHardQuad]>; + +} // Predicates = [Is64Bit] + def : Pat<(SPselectxcc i64:$t, i64:$f, imm:$cond), (MOVXCCrr $t, $f, imm:$cond)>; def : Pat<(SPselectxcc (i64 simm11:$t), i64:$f, imm:$cond), diff --git a/lib/Target/Sparc/SparcInstrFormats.td b/lib/Target/Sparc/SparcInstrFormats.td index 6cdf6bc..afa2874 100644 --- a/lib/Target/Sparc/SparcInstrFormats.td +++ b/lib/Target/Sparc/SparcInstrFormats.td @@ -47,12 +47,11 @@ class F2_1<bits<3> op2Val, dag outs, dag ins, string asmstr, list<dag> pattern> let Inst{29-25} = rd; } -class F2_2<bits<4> condVal, bits<3> op2Val, dag outs, dag ins, string asmstr, +class F2_2<bits<3> op2Val, dag outs, dag ins, string asmstr, list<dag> pattern> : F2<outs, ins, asmstr, pattern> { bits<4> cond; bit annul = 0; // currently unused - let cond = condVal; let op2 = op2Val; let Inst{29} = annul; @@ -112,6 +111,32 @@ class F3_3<bits<2> opVal, bits<6> op3val, bits<9> opfval, dag outs, dag ins, let Inst{4-0} = rs2; } +// floating-point unary operations. +class F3_3u<bits<2> opVal, bits<6> op3val, bits<9> opfval, dag outs, dag ins, + string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> { + bits<5> rs2; + + let op = opVal; + let op3 = op3val; + let rs1 = 0; + + let Inst{13-5} = opfval; // fp opcode + let Inst{4-0} = rs2; +} + +// floating-point compares. +class F3_3c<bits<2> opVal, bits<6> op3val, bits<9> opfval, dag outs, dag ins, + string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> { + bits<5> rs2; + + let op = opVal; + let op3 = op3val; + let rd = 0; + + let Inst{13-5} = opfval; // fp opcode + let Inst{4-0} = rs2; +} + // Shift by register rs2. class F3_Sr<bits<2> opVal, bits<6> op3val, bit xVal, dag outs, dag ins, string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> { @@ -150,3 +175,59 @@ multiclass F3_S<string OpcStr, bits<6> Op3Val, bit XVal, SDNode OpNode, !strconcat(OpcStr, " $rs, $shcnt, $rd"), [(set VT:$rd, (OpNode VT:$rs, (i32 imm:$shcnt)))]>; } + +class F4<bits<6> op3, dag outs, dag ins, string asmstr, list<dag> pattern> + : InstSP<outs, ins, asmstr, pattern> { + bits<5> rd; + + let op = 2; + let Inst{29-25} = rd; + let Inst{24-19} = op3; +} + + +class F4_1<bits<6> op3, dag outs, dag ins, + string asmstr, list<dag> pattern> + : F4<op3, outs, ins, asmstr, pattern> { + + bits<3> cc; + bits<4> cond; + bits<5> rs2; + + let Inst{4-0} = rs2; + let Inst{11} = cc{0}; + let Inst{12} = cc{1}; + let Inst{13} = 0; + let Inst{17-14} = cond; + let Inst{18} = cc{2}; + +} + +class F4_2<bits<6> op3, dag outs, dag ins, + string asmstr, list<dag> pattern> + : F4<op3, outs, ins, asmstr, pattern> { + bits<3> cc; + bits<4> cond; + bits<11> simm11; + + let Inst{10-0} = simm11; + let Inst{11} = cc{0}; + let Inst{12} = cc{1}; + let Inst{13} = 1; + let Inst{17-14} = cond; + let Inst{18} = cc{2}; +} + +class F4_3<bits<6> op3, bits<6> opf_low, dag outs, dag ins, + string asmstr, list<dag> pattern> + : F4<op3, outs, ins, asmstr, pattern> { + bits<4> cond; + bits<3> opf_cc; + bits<5> rs2; + + let Inst{18} = 0; + let Inst{17-14} = cond; + let Inst{13-11} = opf_cc; + let Inst{10-5} = opf_low; + let Inst{4-0} = rs2; +} diff --git a/lib/Target/Sparc/SparcInstrInfo.cpp b/lib/Target/Sparc/SparcInstrInfo.cpp index 6c14bc9..c10b5b3 100644 --- a/lib/Target/Sparc/SparcInstrInfo.cpp +++ b/lib/Target/Sparc/SparcInstrInfo.cpp @@ -24,11 +24,15 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TargetRegistry.h" -#define GET_INSTRINFO_CTOR +#define GET_INSTRINFO_CTOR_DTOR #include "SparcGenInstrInfo.inc" using namespace llvm; + +// Pin the vtable to this file. +void SparcInstrInfo::anchor() {} + SparcInstrInfo::SparcInstrInfo(SparcSubtarget &ST) : SparcGenInstrInfo(SP::ADJCALLSTACKDOWN, SP::ADJCALLSTACKUP), RI(ST), Subtarget(ST) { @@ -44,7 +48,8 @@ unsigned SparcInstrInfo::isLoadFromStackSlot(const MachineInstr *MI, if (MI->getOpcode() == SP::LDri || MI->getOpcode() == SP::LDXri || MI->getOpcode() == SP::LDFri || - MI->getOpcode() == SP::LDDFri) { + MI->getOpcode() == SP::LDDFri || + MI->getOpcode() == SP::LDQFri) { if (MI->getOperand(1).isFI() && MI->getOperand(2).isImm() && MI->getOperand(2).getImm() == 0) { FrameIndex = MI->getOperand(1).getIndex(); @@ -64,7 +69,8 @@ unsigned SparcInstrInfo::isStoreToStackSlot(const MachineInstr *MI, if (MI->getOpcode() == SP::STri || MI->getOpcode() == SP::STXri || MI->getOpcode() == SP::STFri || - MI->getOpcode() == SP::STDFri) { + MI->getOpcode() == SP::STDFri || + MI->getOpcode() == SP::STQFri) { if (MI->getOperand(0).isFI() && MI->getOperand(1).isImm() && MI->getOperand(1).getImm() == 0) { FrameIndex = MI->getOperand(0).getIndex(); @@ -100,14 +106,14 @@ static SPCC::CondCodes GetOppositeBranchCondition(SPCC::CondCodes CC) case SPCC::FCC_U: return SPCC::FCC_O; case SPCC::FCC_O: return SPCC::FCC_U; - case SPCC::FCC_G: return SPCC::FCC_LE; - case SPCC::FCC_LE: return SPCC::FCC_G; - case SPCC::FCC_UG: return SPCC::FCC_ULE; - case SPCC::FCC_ULE: return SPCC::FCC_UG; - case SPCC::FCC_L: return SPCC::FCC_GE; - case SPCC::FCC_GE: return SPCC::FCC_L; - case SPCC::FCC_UL: return SPCC::FCC_UGE; - case SPCC::FCC_UGE: return SPCC::FCC_UL; + case SPCC::FCC_G: return SPCC::FCC_ULE; + case SPCC::FCC_LE: return SPCC::FCC_UG; + case SPCC::FCC_UG: return SPCC::FCC_LE; + case SPCC::FCC_ULE: return SPCC::FCC_G; + case SPCC::FCC_L: return SPCC::FCC_UGE; + case SPCC::FCC_GE: return SPCC::FCC_UL; + case SPCC::FCC_UL: return SPCC::FCC_GE; + case SPCC::FCC_UGE: return SPCC::FCC_L; case SPCC::FCC_LG: return SPCC::FCC_UE; case SPCC::FCC_UE: return SPCC::FCC_LG; case SPCC::FCC_NE: return SPCC::FCC_E; @@ -273,6 +279,16 @@ void SparcInstrInfo::copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, DebugLoc DL, unsigned DestReg, unsigned SrcReg, bool KillSrc) const { + unsigned numSubRegs = 0; + unsigned movOpc = 0; + const unsigned *subRegIdx = 0; + + const unsigned DFP_FP_SubRegsIdx[] = { SP::sub_even, SP::sub_odd }; + const unsigned QFP_DFP_SubRegsIdx[] = { SP::sub_even64, SP::sub_odd64 }; + const unsigned QFP_FP_SubRegsIdx[] = { SP::sub_even, SP::sub_odd, + SP::sub_odd64_then_sub_even, + SP::sub_odd64_then_sub_odd }; + if (SP::IntRegsRegClass.contains(DestReg, SrcReg)) BuildMI(MBB, I, DL, get(SP::ORrr), DestReg).addReg(SP::G0) .addReg(SrcReg, getKillRegState(KillSrc)); @@ -285,23 +301,47 @@ void SparcInstrInfo::copyPhysReg(MachineBasicBlock &MBB, .addReg(SrcReg, getKillRegState(KillSrc)); } else { // Use two FMOVS instructions. - const TargetRegisterInfo *TRI = &getRegisterInfo(); - MachineInstr *MovMI = 0; - unsigned subRegIdx[] = {SP::sub_even, SP::sub_odd}; - for (unsigned i = 0; i != 2; ++i) { - unsigned Dst = TRI->getSubReg(DestReg, subRegIdx[i]); - unsigned Src = TRI->getSubReg(SrcReg, subRegIdx[i]); - assert(Dst && Src && "Bad sub-register"); - - MovMI = BuildMI(MBB, I, DL, get(SP::FMOVS), Dst).addReg(Src); + subRegIdx = DFP_FP_SubRegsIdx; + numSubRegs = 2; + movOpc = SP::FMOVS; + } + } else if (SP::QFPRegsRegClass.contains(DestReg, SrcReg)) { + if (Subtarget.isV9()) { + if (Subtarget.hasHardQuad()) { + BuildMI(MBB, I, DL, get(SP::FMOVQ), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)); + } else { + // Use two FMOVD instructions. + subRegIdx = QFP_DFP_SubRegsIdx; + numSubRegs = 2; + movOpc = SP::FMOVD; } - // Add implicit super-register defs and kills to the last MovMI. - MovMI->addRegisterDefined(DestReg, TRI); - if (KillSrc) - MovMI->addRegisterKilled(SrcReg, TRI); + } else { + // Use four FMOVS instructions. + subRegIdx = QFP_FP_SubRegsIdx; + numSubRegs = 4; + movOpc = SP::FMOVS; } } else llvm_unreachable("Impossible reg-to-reg copy"); + + if (numSubRegs == 0 || subRegIdx == 0 || movOpc == 0) + return; + + const TargetRegisterInfo *TRI = &getRegisterInfo(); + MachineInstr *MovMI = 0; + + for (unsigned i = 0; i != numSubRegs; ++i) { + unsigned Dst = TRI->getSubReg(DestReg, subRegIdx[i]); + unsigned Src = TRI->getSubReg(SrcReg, subRegIdx[i]); + assert(Dst && Src && "Bad sub-register"); + + MovMI = BuildMI(MBB, I, DL, get(movOpc), Dst).addReg(Src); + } + // Add implicit super-register defs and kills to the last MovMI. + MovMI->addRegisterDefined(DestReg, TRI); + if (KillSrc) + MovMI->addRegisterKilled(SrcReg, TRI); } void SparcInstrInfo:: @@ -321,7 +361,7 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, MFI.getObjectAlignment(FI)); // On the order of operands here: think "[FrameIdx + 0] = SrcReg". - if (RC == &SP::I64RegsRegClass) + if (RC == &SP::I64RegsRegClass) BuildMI(MBB, I, DL, get(SP::STXri)).addFrameIndex(FI).addImm(0) .addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO); else if (RC == &SP::IntRegsRegClass) @@ -330,9 +370,14 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, else if (RC == &SP::FPRegsRegClass) BuildMI(MBB, I, DL, get(SP::STFri)).addFrameIndex(FI).addImm(0) .addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO); - else if (RC == &SP::DFPRegsRegClass) + else if (SP::DFPRegsRegClass.hasSubClassEq(RC)) BuildMI(MBB, I, DL, get(SP::STDFri)).addFrameIndex(FI).addImm(0) .addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO); + else if (SP::QFPRegsRegClass.hasSubClassEq(RC)) + // Use STQFri irrespective of its legality. If STQ is not legal, it will be + // lowered into two STDs in eliminateFrameIndex. + BuildMI(MBB, I, DL, get(SP::STQFri)).addFrameIndex(FI).addImm(0) + .addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO); else llvm_unreachable("Can't store this register to stack slot"); } @@ -362,9 +407,14 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, else if (RC == &SP::FPRegsRegClass) BuildMI(MBB, I, DL, get(SP::LDFri), DestReg).addFrameIndex(FI).addImm(0) .addMemOperand(MMO); - else if (RC == &SP::DFPRegsRegClass) + else if (SP::DFPRegsRegClass.hasSubClassEq(RC)) BuildMI(MBB, I, DL, get(SP::LDDFri), DestReg).addFrameIndex(FI).addImm(0) .addMemOperand(MMO); + else if (SP::QFPRegsRegClass.hasSubClassEq(RC)) + // Use LDQFri irrespective of its legality. If LDQ is not legal, it will be + // lowered into two LDDs in eliminateFrameIndex. + BuildMI(MBB, I, DL, get(SP::LDQFri), DestReg).addFrameIndex(FI).addImm(0) + .addMemOperand(MMO); else llvm_unreachable("Can't load this register from stack slot"); } diff --git a/lib/Target/Sparc/SparcInstrInfo.h b/lib/Target/Sparc/SparcInstrInfo.h index d0b220b..a86cbcb 100644 --- a/lib/Target/Sparc/SparcInstrInfo.h +++ b/lib/Target/Sparc/SparcInstrInfo.h @@ -37,6 +37,7 @@ namespace SPII { class SparcInstrInfo : public SparcGenInstrInfo { const SparcRegisterInfo RI; const SparcSubtarget& Subtarget; + virtual void anchor(); public: explicit SparcInstrInfo(SparcSubtarget &ST); diff --git a/lib/Target/Sparc/SparcInstrInfo.td b/lib/Target/Sparc/SparcInstrInfo.td index d4cac4d..ef7a114 100644 --- a/lib/Target/Sparc/SparcInstrInfo.td +++ b/lib/Target/Sparc/SparcInstrInfo.td @@ -39,6 +39,10 @@ def HasNoV9 : Predicate<"!Subtarget.isV9()">; // HasVIS - This is true when the target processor has VIS extensions. def HasVIS : Predicate<"Subtarget.isVIS()">; +// HasHardQuad - This is true when the target processor supports quad floating +// point instructions. +def HasHardQuad : Predicate<"Subtarget.hasHardQuad()">; + // UseDeprecatedInsts - This predicate is true when the target processor is a // V8, or when it is V9 but the V8 deprecated instructions are efficient enough // to use when appropriate. In either of these cases, the instruction selector @@ -81,6 +85,8 @@ def MEMri : Operand<iPTR> { let MIOperandInfo = (ops ptr_rc, i32imm); } +def TLSSym : Operand<iPTR>; + // Branch targets have OtherVT type. def brtarget : Operand<OtherVT>; def calltarget : Operand<i32>; @@ -101,6 +107,15 @@ def SDTSPFTOI : SDTypeProfile<1, 1, [SDTCisVT<0, f32>, SDTCisFP<1>]>; def SDTSPITOF : SDTypeProfile<1, 1, [SDTCisFP<0>, SDTCisVT<1, f32>]>; +def SDTSPFTOX : +SDTypeProfile<1, 1, [SDTCisVT<0, f64>, SDTCisFP<1>]>; +def SDTSPXTOF : +SDTypeProfile<1, 1, [SDTCisFP<0>, SDTCisVT<1, f64>]>; + +def SDTSPtlsadd : +SDTypeProfile<1, 3, [SDTCisInt<0>, SDTCisSameAs<0, 1>, SDTCisPtrTy<2>]>; +def SDTSPtlsld : +SDTypeProfile<1, 2, [SDTCisPtrTy<0>, SDTCisPtrTy<1>]>; def SPcmpicc : SDNode<"SPISD::CMPICC", SDTSPcmpicc, [SDNPOutGlue]>; def SPcmpfcc : SDNode<"SPISD::CMPFCC", SDTSPcmpfcc, [SDNPOutGlue]>; @@ -113,6 +128,8 @@ def SPlo : SDNode<"SPISD::Lo", SDTIntUnaryOp>; def SPftoi : SDNode<"SPISD::FTOI", SDTSPFTOI>; def SPitof : SDNode<"SPISD::ITOF", SDTSPITOF>; +def SPftox : SDNode<"SPISD::FTOX", SDTSPFTOX>; +def SPxtof : SDNode<"SPISD::XTOF", SDTSPXTOF>; def SPselecticc : SDNode<"SPISD::SELECT_ICC", SDTSPselectcc, [SDNPInGlue]>; def SPselectxcc : SDNode<"SPISD::SELECT_XCC", SDTSPselectcc, [SDNPInGlue]>; @@ -140,6 +157,12 @@ def retflag : SDNode<"SPISD::RET_FLAG", SDT_SPRet, def flushw : SDNode<"SPISD::FLUSHW", SDTNone, [SDNPHasChain, SDNPSideEffect, SDNPMayStore]>; +def tlsadd : SDNode<"SPISD::TLS_ADD", SDTSPtlsadd>; +def tlsld : SDNode<"SPISD::TLS_LD", SDTSPtlsld>; +def tlscall : SDNode<"SPISD::TLS_CALL", SDT_SPCall, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, + SDNPVariadic]>; + def getPCX : Operand<i32> { let PrintMethod = "printGetPCX"; } @@ -242,8 +265,9 @@ let hasSideEffects = 1, mayStore = 1 in { [(flushw)]>; } -def UNIMP : F2_1<0b000, (outs), (ins i32imm:$val), - "unimp $val", []>; +let rd = 0 in + def UNIMP : F2_1<0b000, (outs), (ins i32imm:$val), + "unimp $val", []>; // SELECT_CC_* - Used to implement the SELECT_CC DAG operation. Expanded after // instruction selection into a branch sequence. This has to handle all @@ -263,6 +287,11 @@ let Uses = [ICC], usesCustomInserter = 1 in { : Pseudo<(outs DFPRegs:$dst), (ins DFPRegs:$T, DFPRegs:$F, i32imm:$Cond), "; SELECT_CC_DFP_ICC PSEUDO!", [(set f64:$dst, (SPselecticc f64:$T, f64:$F, imm:$Cond))]>; + + def SELECT_CC_QFP_ICC + : Pseudo<(outs QFPRegs:$dst), (ins QFPRegs:$T, QFPRegs:$F, i32imm:$Cond), + "; SELECT_CC_QFP_ICC PSEUDO!", + [(set f128:$dst, (SPselecticc f128:$T, f128:$F, imm:$Cond))]>; } let usesCustomInserter = 1, Uses = [FCC] in { @@ -280,17 +309,21 @@ let usesCustomInserter = 1, Uses = [FCC] in { : Pseudo<(outs DFPRegs:$dst), (ins DFPRegs:$T, DFPRegs:$F, i32imm:$Cond), "; SELECT_CC_DFP_FCC PSEUDO!", [(set f64:$dst, (SPselectfcc f64:$T, f64:$F, imm:$Cond))]>; + def SELECT_CC_QFP_FCC + : Pseudo<(outs QFPRegs:$dst), (ins QFPRegs:$T, QFPRegs:$F, i32imm:$Cond), + "; SELECT_CC_QFP_FCC PSEUDO!", + [(set f128:$dst, (SPselectfcc f128:$T, f128:$F, imm:$Cond))]>; } // Section A.3 - Synthetic Instructions, p. 85 // special cases of JMPL: let isReturn = 1, isTerminator = 1, hasDelaySlot = 1, isBarrier = 1 in { - let rd = O7.Num, rs1 = G0.Num in + let rd = 0, rs1 = 15 in def RETL: F3_2<2, 0b111000, (outs), (ins i32imm:$val), "jmp %o7+$val", [(retflag simm13:$val)]>; - let rd = I7.Num, rs1 = G0.Num in + let rd = 0, rs1 = 31 in def RET: F3_2<2, 0b111000, (outs), (ins i32imm:$val), "jmp %i7+$val", []>; } @@ -354,56 +387,76 @@ def LDDFri : F3_2<3, 0b100011, (outs DFPRegs:$dst), (ins MEMri:$addr), "ldd [$addr], $dst", [(set f64:$dst, (load ADDRri:$addr))]>; +def LDQFrr : F3_1<3, 0b100010, + (outs QFPRegs:$dst), (ins MEMrr:$addr), + "ldq [$addr], $dst", + [(set f128:$dst, (load ADDRrr:$addr))]>, + Requires<[HasV9, HasHardQuad]>; +def LDQFri : F3_2<3, 0b100010, + (outs QFPRegs:$dst), (ins MEMri:$addr), + "ldq [$addr], $dst", + [(set f128:$dst, (load ADDRri:$addr))]>, + Requires<[HasV9, HasHardQuad]>; // Section B.4 - Store Integer Instructions, p. 95 def STBrr : F3_1<3, 0b000101, - (outs), (ins MEMrr:$addr, IntRegs:$src), - "stb $src, [$addr]", - [(truncstorei8 i32:$src, ADDRrr:$addr)]>; + (outs), (ins MEMrr:$addr, IntRegs:$rd), + "stb $rd, [$addr]", + [(truncstorei8 i32:$rd, ADDRrr:$addr)]>; def STBri : F3_2<3, 0b000101, - (outs), (ins MEMri:$addr, IntRegs:$src), - "stb $src, [$addr]", - [(truncstorei8 i32:$src, ADDRri:$addr)]>; + (outs), (ins MEMri:$addr, IntRegs:$rd), + "stb $rd, [$addr]", + [(truncstorei8 i32:$rd, ADDRri:$addr)]>; def STHrr : F3_1<3, 0b000110, - (outs), (ins MEMrr:$addr, IntRegs:$src), - "sth $src, [$addr]", - [(truncstorei16 i32:$src, ADDRrr:$addr)]>; + (outs), (ins MEMrr:$addr, IntRegs:$rd), + "sth $rd, [$addr]", + [(truncstorei16 i32:$rd, ADDRrr:$addr)]>; def STHri : F3_2<3, 0b000110, - (outs), (ins MEMri:$addr, IntRegs:$src), - "sth $src, [$addr]", - [(truncstorei16 i32:$src, ADDRri:$addr)]>; + (outs), (ins MEMri:$addr, IntRegs:$rd), + "sth $rd, [$addr]", + [(truncstorei16 i32:$rd, ADDRri:$addr)]>; def STrr : F3_1<3, 0b000100, - (outs), (ins MEMrr:$addr, IntRegs:$src), - "st $src, [$addr]", - [(store i32:$src, ADDRrr:$addr)]>; + (outs), (ins MEMrr:$addr, IntRegs:$rd), + "st $rd, [$addr]", + [(store i32:$rd, ADDRrr:$addr)]>; def STri : F3_2<3, 0b000100, - (outs), (ins MEMri:$addr, IntRegs:$src), - "st $src, [$addr]", - [(store i32:$src, ADDRri:$addr)]>; + (outs), (ins MEMri:$addr, IntRegs:$rd), + "st $rd, [$addr]", + [(store i32:$rd, ADDRri:$addr)]>; // Section B.5 - Store Floating-point Instructions, p. 97 def STFrr : F3_1<3, 0b100100, - (outs), (ins MEMrr:$addr, FPRegs:$src), - "st $src, [$addr]", - [(store f32:$src, ADDRrr:$addr)]>; + (outs), (ins MEMrr:$addr, FPRegs:$rd), + "st $rd, [$addr]", + [(store f32:$rd, ADDRrr:$addr)]>; def STFri : F3_2<3, 0b100100, - (outs), (ins MEMri:$addr, FPRegs:$src), - "st $src, [$addr]", - [(store f32:$src, ADDRri:$addr)]>; + (outs), (ins MEMri:$addr, FPRegs:$rd), + "st $rd, [$addr]", + [(store f32:$rd, ADDRri:$addr)]>; def STDFrr : F3_1<3, 0b100111, - (outs), (ins MEMrr:$addr, DFPRegs:$src), - "std $src, [$addr]", - [(store f64:$src, ADDRrr:$addr)]>; + (outs), (ins MEMrr:$addr, DFPRegs:$rd), + "std $rd, [$addr]", + [(store f64:$rd, ADDRrr:$addr)]>; def STDFri : F3_2<3, 0b100111, - (outs), (ins MEMri:$addr, DFPRegs:$src), - "std $src, [$addr]", - [(store f64:$src, ADDRri:$addr)]>; + (outs), (ins MEMri:$addr, DFPRegs:$rd), + "std $rd, [$addr]", + [(store f64:$rd, ADDRri:$addr)]>; +def STQFrr : F3_1<3, 0b100110, + (outs), (ins MEMrr:$addr, QFPRegs:$rd), + "stq $rd, [$addr]", + [(store f128:$rd, ADDRrr:$addr)]>, + Requires<[HasV9, HasHardQuad]>; +def STQFri : F3_2<3, 0b100110, + (outs), (ins MEMri:$addr, QFPRegs:$rd), + "stq $rd, [$addr]", + [(store f128:$rd, ADDRri:$addr)]>, + Requires<[HasV9, HasHardQuad]>; // Section B.9 - SETHI Instruction, p. 104 def SETHIi: F2_1<0b100, - (outs IntRegs:$dst), (ins i32imm:$src), - "sethi $src, $dst", - [(set i32:$dst, SETHIimm:$src)]>; + (outs IntRegs:$rd), (ins i32imm:$imm22), + "sethi $imm22, $rd", + [(set i32:$rd, SETHIimm:$imm22)]>; // Section B.10 - NOP Instruction, p. 105 // (It's a special case of SETHI) @@ -449,30 +502,32 @@ defm SRA : F3_12<"sra", 0b100111, sra>; defm ADD : F3_12<"add", 0b000000, add>; // "LEA" forms of add (patterns to make tblgen happy) -def LEA_ADDri : F3_2<2, 0b000000, - (outs IntRegs:$dst), (ins MEMri:$addr), - "add ${addr:arith}, $dst", - [(set iPTR:$dst, ADDRri:$addr)]>; +let Predicates = [Is32Bit] in + def LEA_ADDri : F3_2<2, 0b000000, + (outs IntRegs:$dst), (ins MEMri:$addr), + "add ${addr:arith}, $dst", + [(set iPTR:$dst, ADDRri:$addr)]>; let Defs = [ICC] in defm ADDCC : F3_12<"addcc", 0b010000, addc>; -let Uses = [ICC] in - defm ADDX : F3_12<"addx", 0b001000, adde>; +let Uses = [ICC], Defs = [ICC] in + defm ADDX : F3_12<"addxcc", 0b011000, adde>; // Section B.15 - Subtract Instructions, p. 110 defm SUB : F3_12 <"sub" , 0b000100, sub>; -let Uses = [ICC] in - defm SUBX : F3_12 <"subx" , 0b001100, sube>; +let Uses = [ICC], Defs = [ICC] in + defm SUBX : F3_12 <"subxcc" , 0b011100, sube>; -let Defs = [ICC] in { +let Defs = [ICC] in defm SUBCC : F3_12 <"subcc", 0b010100, subc>; +let Defs = [ICC], rd = 0 in { def CMPrr : F3_1<2, 0b010100, (outs), (ins IntRegs:$b, IntRegs:$c), "cmp $b, $c", [(SPcmpicc i32:$b, i32:$c)]>; - def CMPri : F3_1<2, 0b010100, + def CMPri : F3_2<2, 0b010100, (outs), (ins IntRegs:$b, i32imm:$c), "cmp $b, $c", [(SPcmpicc i32:$b, (i32 simm13:$c))]>; @@ -502,23 +557,30 @@ defm RESTORE : F3_12np<"restore", 0b111101>; // Section B.21 - Branch on Integer Condition Codes Instructions, p. 119 +// unconditional branch class. +class BranchAlways<dag ins, string asmstr, list<dag> pattern> + : F2_2<0b010, (outs), ins, asmstr, pattern> { + let isBranch = 1; + let isTerminator = 1; + let hasDelaySlot = 1; + let isBarrier = 1; +} + +let cond = 8 in + def BA : BranchAlways<(ins brtarget:$imm22), "ba $imm22", [(br bb:$imm22)]>; + // conditional branch class: -class BranchSP<bits<4> cc, dag ins, string asmstr, list<dag> pattern> - : F2_2<cc, 0b010, (outs), ins, asmstr, pattern> { +class BranchSP<dag ins, string asmstr, list<dag> pattern> + : F2_2<0b010, (outs), ins, asmstr, pattern> { let isBranch = 1; let isTerminator = 1; let hasDelaySlot = 1; } -let isBarrier = 1 in - def BA : BranchSP<0b1000, (ins brtarget:$dst), - "ba $dst", - [(br bb:$dst)]>; - // Indirect branch instructions. let isTerminator = 1, isBarrier = 1, hasDelaySlot = 1, isBranch =1, - isIndirectBranch = 1 in { + isIndirectBranch = 1, rd = 0 in { def BINDrr : F3_1<2, 0b111000, (outs), (ins MEMrr:$ptr), "jmp $ptr", @@ -529,37 +591,31 @@ let isTerminator = 1, isBarrier = 1, [(brind ADDRri:$ptr)]>; } -// FIXME: the encoding for the JIT should look at the condition field. let Uses = [ICC] in - def BCOND : BranchSP<0, (ins brtarget:$dst, CCOp:$cc), - "b$cc $dst", - [(SPbricc bb:$dst, imm:$cc)]>; - + def BCOND : BranchSP<(ins brtarget:$imm22, CCOp:$cond), + "b$cond $imm22", + [(SPbricc bb:$imm22, imm:$cond)]>; // Section B.22 - Branch on Floating-point Condition Codes Instructions, p. 121 // floating-point conditional branch class: -class FPBranchSP<bits<4> cc, dag ins, string asmstr, list<dag> pattern> - : F2_2<cc, 0b110, (outs), ins, asmstr, pattern> { +class FPBranchSP<dag ins, string asmstr, list<dag> pattern> + : F2_2<0b110, (outs), ins, asmstr, pattern> { let isBranch = 1; let isTerminator = 1; let hasDelaySlot = 1; } -// FIXME: the encoding for the JIT should look at the condition field. let Uses = [FCC] in - def FBCOND : FPBranchSP<0, (ins brtarget:$dst, CCOp:$cc), - "fb$cc $dst", - [(SPbrfcc bb:$dst, imm:$cc)]>; + def FBCOND : FPBranchSP<(ins brtarget:$imm22, CCOp:$cond), + "fb$cond $imm22", + [(SPbrfcc bb:$imm22, imm:$cond)]>; // Section B.24 - Call and Link Instruction, p. 125 // This is the only Format 1 instruction let Uses = [O6], - hasDelaySlot = 1, isCall = 1, - Defs = [O0, O1, O2, O3, O4, O5, O7, G1, G2, G3, G4, G5, G6, G7, - D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, - ICC, FCC, Y] in { + hasDelaySlot = 1, isCall = 1 in { def CALL : InstSP<(outs), (ins calltarget:$dst, variable_ops), "call $dst", []> { bits<30> disp; @@ -571,21 +627,21 @@ let Uses = [O6], def JMPLrr : F3_1<2, 0b111000, (outs), (ins MEMrr:$ptr, variable_ops), "call $ptr", - [(call ADDRrr:$ptr)]>; + [(call ADDRrr:$ptr)]> { let rd = 15; } def JMPLri : F3_2<2, 0b111000, (outs), (ins MEMri:$ptr, variable_ops), "call $ptr", - [(call ADDRri:$ptr)]>; + [(call ADDRri:$ptr)]> { let rd = 15; } } // Section B.28 - Read State Register Instructions -let Uses = [Y] in +let Uses = [Y], rs1 = 0, rs2 = 0 in def RDY : F3_1<2, 0b101000, (outs IntRegs:$dst), (ins), "rd %y, $dst", []>; // Section B.29 - Write State Register Instructions -let Defs = [Y] in { +let Defs = [Y], rd = 0 in { def WRYrr : F3_1<2, 0b110000, (outs), (ins IntRegs:$b, IntRegs:$c), "wr $b, $c, %y", []>; @@ -594,58 +650,93 @@ let Defs = [Y] in { "wr $b, $c, %y", []>; } // Convert Integer to Floating-point Instructions, p. 141 -def FITOS : F3_3<2, 0b110100, 0b011000100, +def FITOS : F3_3u<2, 0b110100, 0b011000100, (outs FPRegs:$dst), (ins FPRegs:$src), "fitos $src, $dst", [(set FPRegs:$dst, (SPitof FPRegs:$src))]>; -def FITOD : F3_3<2, 0b110100, 0b011001000, +def FITOD : F3_3u<2, 0b110100, 0b011001000, (outs DFPRegs:$dst), (ins FPRegs:$src), "fitod $src, $dst", [(set DFPRegs:$dst, (SPitof FPRegs:$src))]>; +def FITOQ : F3_3u<2, 0b110100, 0b011001100, + (outs QFPRegs:$dst), (ins FPRegs:$src), + "fitoq $src, $dst", + [(set QFPRegs:$dst, (SPitof FPRegs:$src))]>, + Requires<[HasHardQuad]>; // Convert Floating-point to Integer Instructions, p. 142 -def FSTOI : F3_3<2, 0b110100, 0b011010001, +def FSTOI : F3_3u<2, 0b110100, 0b011010001, (outs FPRegs:$dst), (ins FPRegs:$src), "fstoi $src, $dst", [(set FPRegs:$dst, (SPftoi FPRegs:$src))]>; -def FDTOI : F3_3<2, 0b110100, 0b011010010, +def FDTOI : F3_3u<2, 0b110100, 0b011010010, (outs FPRegs:$dst), (ins DFPRegs:$src), "fdtoi $src, $dst", [(set FPRegs:$dst, (SPftoi DFPRegs:$src))]>; +def FQTOI : F3_3u<2, 0b110100, 0b011010011, + (outs FPRegs:$dst), (ins QFPRegs:$src), + "fqtoi $src, $dst", + [(set FPRegs:$dst, (SPftoi QFPRegs:$src))]>, + Requires<[HasHardQuad]>; // Convert between Floating-point Formats Instructions, p. 143 -def FSTOD : F3_3<2, 0b110100, 0b011001001, +def FSTOD : F3_3u<2, 0b110100, 0b011001001, (outs DFPRegs:$dst), (ins FPRegs:$src), "fstod $src, $dst", [(set f64:$dst, (fextend f32:$src))]>; -def FDTOS : F3_3<2, 0b110100, 0b011000110, +def FSTOQ : F3_3u<2, 0b110100, 0b011001101, + (outs QFPRegs:$dst), (ins FPRegs:$src), + "fstoq $src, $dst", + [(set f128:$dst, (fextend f32:$src))]>, + Requires<[HasHardQuad]>; +def FDTOS : F3_3u<2, 0b110100, 0b011000110, (outs FPRegs:$dst), (ins DFPRegs:$src), "fdtos $src, $dst", [(set f32:$dst, (fround f64:$src))]>; +def FDTOQ : F3_3u<2, 0b110100, 0b01101110, + (outs QFPRegs:$dst), (ins DFPRegs:$src), + "fdtoq $src, $dst", + [(set f128:$dst, (fextend f64:$src))]>, + Requires<[HasHardQuad]>; +def FQTOS : F3_3u<2, 0b110100, 0b011000111, + (outs FPRegs:$dst), (ins QFPRegs:$src), + "fqtos $src, $dst", + [(set f32:$dst, (fround f128:$src))]>, + Requires<[HasHardQuad]>; +def FQTOD : F3_3u<2, 0b110100, 0b011001011, + (outs DFPRegs:$dst), (ins QFPRegs:$src), + "fqtod $src, $dst", + [(set f64:$dst, (fround f128:$src))]>, + Requires<[HasHardQuad]>; // Floating-point Move Instructions, p. 144 -def FMOVS : F3_3<2, 0b110100, 0b000000001, +def FMOVS : F3_3u<2, 0b110100, 0b000000001, (outs FPRegs:$dst), (ins FPRegs:$src), "fmovs $src, $dst", []>; -def FNEGS : F3_3<2, 0b110100, 0b000000101, +def FNEGS : F3_3u<2, 0b110100, 0b000000101, (outs FPRegs:$dst), (ins FPRegs:$src), "fnegs $src, $dst", [(set f32:$dst, (fneg f32:$src))]>; -def FABSS : F3_3<2, 0b110100, 0b000001001, +def FABSS : F3_3u<2, 0b110100, 0b000001001, (outs FPRegs:$dst), (ins FPRegs:$src), "fabss $src, $dst", [(set f32:$dst, (fabs f32:$src))]>; // Floating-point Square Root Instructions, p.145 -def FSQRTS : F3_3<2, 0b110100, 0b000101001, +def FSQRTS : F3_3u<2, 0b110100, 0b000101001, (outs FPRegs:$dst), (ins FPRegs:$src), "fsqrts $src, $dst", [(set f32:$dst, (fsqrt f32:$src))]>; -def FSQRTD : F3_3<2, 0b110100, 0b000101010, +def FSQRTD : F3_3u<2, 0b110100, 0b000101010, (outs DFPRegs:$dst), (ins DFPRegs:$src), "fsqrtd $src, $dst", [(set f64:$dst, (fsqrt f64:$src))]>; +def FSQRTQ : F3_3u<2, 0b110100, 0b000101011, + (outs QFPRegs:$dst), (ins QFPRegs:$src), + "fsqrtq $src, $dst", + [(set f128:$dst, (fsqrt f128:$src))]>, + Requires<[HasHardQuad]>; @@ -658,6 +749,12 @@ def FADDD : F3_3<2, 0b110100, 0b001000010, (outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2), "faddd $src1, $src2, $dst", [(set f64:$dst, (fadd f64:$src1, f64:$src2))]>; +def FADDQ : F3_3<2, 0b110100, 0b001000011, + (outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2), + "faddq $src1, $src2, $dst", + [(set f128:$dst, (fadd f128:$src1, f128:$src2))]>, + Requires<[HasHardQuad]>; + def FSUBS : F3_3<2, 0b110100, 0b001000101, (outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2), "fsubs $src1, $src2, $dst", @@ -666,6 +763,12 @@ def FSUBD : F3_3<2, 0b110100, 0b001000110, (outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2), "fsubd $src1, $src2, $dst", [(set f64:$dst, (fsub f64:$src1, f64:$src2))]>; +def FSUBQ : F3_3<2, 0b110100, 0b001000111, + (outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2), + "fsubq $src1, $src2, $dst", + [(set f128:$dst, (fsub f128:$src1, f128:$src2))]>, + Requires<[HasHardQuad]>; + // Floating-point Multiply and Divide Instructions, p. 147 def FMULS : F3_3<2, 0b110100, 0b001001001, @@ -676,11 +779,24 @@ def FMULD : F3_3<2, 0b110100, 0b001001010, (outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2), "fmuld $src1, $src2, $dst", [(set f64:$dst, (fmul f64:$src1, f64:$src2))]>; +def FMULQ : F3_3<2, 0b110100, 0b001001011, + (outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2), + "fmulq $src1, $src2, $dst", + [(set f128:$dst, (fmul f128:$src1, f128:$src2))]>, + Requires<[HasHardQuad]>; + def FSMULD : F3_3<2, 0b110100, 0b001101001, (outs DFPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2), "fsmuld $src1, $src2, $dst", [(set f64:$dst, (fmul (fextend f32:$src1), (fextend f32:$src2)))]>; +def FDMULQ : F3_3<2, 0b110100, 0b001101110, + (outs QFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2), + "fdmulq $src1, $src2, $dst", + [(set f128:$dst, (fmul (fextend f64:$src1), + (fextend f64:$src2)))]>, + Requires<[HasHardQuad]>; + def FDIVS : F3_3<2, 0b110100, 0b001001101, (outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2), "fdivs $src1, $src2, $dst", @@ -689,21 +805,61 @@ def FDIVD : F3_3<2, 0b110100, 0b001001110, (outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2), "fdivd $src1, $src2, $dst", [(set f64:$dst, (fdiv f64:$src1, f64:$src2))]>; +def FDIVQ : F3_3<2, 0b110100, 0b001001111, + (outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2), + "fdivq $src1, $src2, $dst", + [(set f128:$dst, (fdiv f128:$src1, f128:$src2))]>, + Requires<[HasHardQuad]>; // Floating-point Compare Instructions, p. 148 // Note: the 2nd template arg is different for these guys. // Note 2: the result of a FCMP is not available until the 2nd cycle -// after the instr is retired, but there is no interlock. This behavior -// is modelled with a forced noop after the instruction. +// after the instr is retired, but there is no interlock in Sparc V8. +// This behavior is modeled with a forced noop after the instruction in +// DelaySlotFiller. + let Defs = [FCC] in { - def FCMPS : F3_3<2, 0b110101, 0b001010001, + def FCMPS : F3_3c<2, 0b110101, 0b001010001, (outs), (ins FPRegs:$src1, FPRegs:$src2), - "fcmps $src1, $src2\n\tnop", + "fcmps $src1, $src2", [(SPcmpfcc f32:$src1, f32:$src2)]>; - def FCMPD : F3_3<2, 0b110101, 0b001010010, + def FCMPD : F3_3c<2, 0b110101, 0b001010010, (outs), (ins DFPRegs:$src1, DFPRegs:$src2), - "fcmpd $src1, $src2\n\tnop", + "fcmpd $src1, $src2", [(SPcmpfcc f64:$src1, f64:$src2)]>; + def FCMPQ : F3_3c<2, 0b110101, 0b001010011, + (outs), (ins QFPRegs:$src1, QFPRegs:$src2), + "fcmpq $src1, $src2", + [(SPcmpfcc f128:$src1, f128:$src2)]>, + Requires<[HasHardQuad]>; +} + +//===----------------------------------------------------------------------===// +// Instructions for Thread Local Storage(TLS). +//===----------------------------------------------------------------------===// + +def TLS_ADDrr : F3_1<2, 0b000000, + (outs IntRegs:$rd), + (ins IntRegs:$rs1, IntRegs:$rs2, TLSSym:$sym), + "add $rs1, $rs2, $rd, $sym", + [(set i32:$rd, + (tlsadd i32:$rs1, i32:$rs2, tglobaltlsaddr:$sym))]>; + +let mayLoad = 1 in + def TLS_LDrr : F3_1<3, 0b000000, + (outs IntRegs:$dst), (ins MEMrr:$addr, TLSSym:$sym), + "ld [$addr], $dst, $sym", + [(set i32:$dst, + (tlsld ADDRrr:$addr, tglobaltlsaddr:$sym))]>; + +let Uses = [O6], isCall = 1, hasDelaySlot = 1 in + def TLS_CALL : InstSP<(outs), + (ins calltarget:$disp, TLSSym:$sym, variable_ops), + "call $disp, $sym", + [(tlscall texternalsym:$disp, tglobaltlsaddr:$sym)]> { + bits<30> disp; + let op = 1; + let Inst{29-0} = disp; } //===----------------------------------------------------------------------===// @@ -713,73 +869,108 @@ let Defs = [FCC] in { // V9 Conditional Moves. let Predicates = [HasV9], Constraints = "$f = $rd" in { // Move Integer Register on Condition (MOVcc) p. 194 of the V9 manual. - // FIXME: Add instruction encodings for the JIT some day. - let Uses = [ICC] in { + let Uses = [ICC], cc = 0b100 in { def MOVICCrr - : Pseudo<(outs IntRegs:$rd), (ins IntRegs:$rs2, IntRegs:$f, CCOp:$cc), - "mov$cc %icc, $rs2, $rd", - [(set i32:$rd, (SPselecticc i32:$rs2, i32:$f, imm:$cc))]>; + : F4_1<0b101100, (outs IntRegs:$rd), + (ins IntRegs:$rs2, IntRegs:$f, CCOp:$cond), + "mov$cond %icc, $rs2, $rd", + [(set i32:$rd, (SPselecticc i32:$rs2, i32:$f, imm:$cond))]>; + def MOVICCri - : Pseudo<(outs IntRegs:$rd), (ins i32imm:$i, IntRegs:$f, CCOp:$cc), - "mov$cc %icc, $i, $rd", - [(set i32:$rd, (SPselecticc simm11:$i, i32:$f, imm:$cc))]>; + : F4_2<0b101100, (outs IntRegs:$rd), + (ins i32imm:$simm11, IntRegs:$f, CCOp:$cond), + "mov$cond %icc, $simm11, $rd", + [(set i32:$rd, + (SPselecticc simm11:$simm11, i32:$f, imm:$cond))]>; } - let Uses = [FCC] in { + let Uses = [FCC], cc = 0b000 in { def MOVFCCrr - : Pseudo<(outs IntRegs:$rd), (ins IntRegs:$rs2, IntRegs:$f, CCOp:$cc), - "mov$cc %fcc0, $rs2, $rd", - [(set i32:$rd, (SPselectfcc i32:$rs2, i32:$f, imm:$cc))]>; + : F4_1<0b101100, (outs IntRegs:$rd), + (ins IntRegs:$rs2, IntRegs:$f, CCOp:$cond), + "mov$cond %fcc0, $rs2, $rd", + [(set i32:$rd, (SPselectfcc i32:$rs2, i32:$f, imm:$cond))]>; def MOVFCCri - : Pseudo<(outs IntRegs:$rd), (ins i32imm:$i, IntRegs:$f, CCOp:$cc), - "mov$cc %fcc0, $i, $rd", - [(set i32:$rd, (SPselectfcc simm11:$i, i32:$f, imm:$cc))]>; + : F4_2<0b101100, (outs IntRegs:$rd), + (ins i32imm:$simm11, IntRegs:$f, CCOp:$cond), + "mov$cond %fcc0, $simm11, $rd", + [(set i32:$rd, + (SPselectfcc simm11:$simm11, i32:$f, imm:$cond))]>; } - let Uses = [ICC] in { + let Uses = [ICC], opf_cc = 0b100 in { def FMOVS_ICC - : Pseudo<(outs FPRegs:$rd), (ins FPRegs:$rs2, FPRegs:$f, CCOp:$cc), - "fmovs$cc %icc, $rs2, $rd", - [(set f32:$rd, (SPselecticc f32:$rs2, f32:$f, imm:$cc))]>; + : F4_3<0b110101, 0b000001, (outs FPRegs:$rd), + (ins FPRegs:$rs2, FPRegs:$f, CCOp:$cond), + "fmovs$cond %icc, $rs2, $rd", + [(set f32:$rd, (SPselecticc f32:$rs2, f32:$f, imm:$cond))]>; def FMOVD_ICC - : Pseudo<(outs DFPRegs:$rd), (ins DFPRegs:$rs2, DFPRegs:$f, CCOp:$cc), - "fmovd$cc %icc, $rs2, $rd", - [(set f64:$rd, (SPselecticc f64:$rs2, f64:$f, imm:$cc))]>; + : F4_3<0b110101, 0b000010, (outs DFPRegs:$rd), + (ins DFPRegs:$rs2, DFPRegs:$f, CCOp:$cond), + "fmovd$cond %icc, $rs2, $rd", + [(set f64:$rd, (SPselecticc f64:$rs2, f64:$f, imm:$cond))]>; + def FMOVQ_ICC + : F4_3<0b110101, 0b000011, (outs QFPRegs:$rd), + (ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond), + "fmovd$cond %icc, $rs2, $rd", + [(set f128:$rd, (SPselecticc f128:$rs2, f128:$f, imm:$cond))]>; } - let Uses = [FCC] in { + let Uses = [FCC], opf_cc = 0b000 in { def FMOVS_FCC - : Pseudo<(outs FPRegs:$rd), (ins FPRegs:$rs2, FPRegs:$f, CCOp:$cc), - "fmovs$cc %fcc0, $rs2, $rd", - [(set f32:$rd, (SPselectfcc f32:$rs2, f32:$f, imm:$cc))]>; + : F4_3<0b110101, 0b000001, (outs FPRegs:$rd), + (ins FPRegs:$rs2, FPRegs:$f, CCOp:$cond), + "fmovs$cond %fcc0, $rs2, $rd", + [(set f32:$rd, (SPselectfcc f32:$rs2, f32:$f, imm:$cond))]>; def FMOVD_FCC - : Pseudo<(outs DFPRegs:$rd), (ins DFPRegs:$rs2, DFPRegs:$f, CCOp:$cc), - "fmovd$cc %fcc0, $rs2, $rd", - [(set f64:$rd, (SPselectfcc f64:$rs2, f64:$f, imm:$cc))]>; + : F4_3<0b110101, 0b000010, (outs DFPRegs:$rd), + (ins DFPRegs:$rs2, DFPRegs:$f, CCOp:$cond), + "fmovd$cond %fcc0, $rs2, $rd", + [(set f64:$rd, (SPselectfcc f64:$rs2, f64:$f, imm:$cond))]>; + def FMOVQ_FCC + : F4_3<0b110101, 0b000011, (outs QFPRegs:$rd), + (ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond), + "fmovd$cond %fcc0, $rs2, $rd", + [(set f128:$rd, (SPselectfcc f128:$rs2, f128:$f, imm:$cond))]>; } } // Floating-Point Move Instructions, p. 164 of the V9 manual. let Predicates = [HasV9] in { - def FMOVD : F3_3<2, 0b110100, 0b000000010, + def FMOVD : F3_3u<2, 0b110100, 0b000000010, (outs DFPRegs:$dst), (ins DFPRegs:$src), "fmovd $src, $dst", []>; - def FNEGD : F3_3<2, 0b110100, 0b000000110, + def FMOVQ : F3_3u<2, 0b110100, 0b000000011, + (outs QFPRegs:$dst), (ins QFPRegs:$src), + "fmovq $src, $dst", []>, + Requires<[HasHardQuad]>; + def FNEGD : F3_3u<2, 0b110100, 0b000000110, (outs DFPRegs:$dst), (ins DFPRegs:$src), "fnegd $src, $dst", [(set f64:$dst, (fneg f64:$src))]>; - def FABSD : F3_3<2, 0b110100, 0b000001010, + def FNEGQ : F3_3u<2, 0b110100, 0b000000111, + (outs QFPRegs:$dst), (ins QFPRegs:$src), + "fnegq $src, $dst", + [(set f128:$dst, (fneg f128:$src))]>, + Requires<[HasHardQuad]>; + def FABSD : F3_3u<2, 0b110100, 0b000001010, (outs DFPRegs:$dst), (ins DFPRegs:$src), "fabsd $src, $dst", [(set f64:$dst, (fabs f64:$src))]>; + def FABSQ : F3_3u<2, 0b110100, 0b000001011, + (outs QFPRegs:$dst), (ins QFPRegs:$src), + "fabsq $src, $dst", + [(set f128:$dst, (fabs f128:$src))]>, + Requires<[HasHardQuad]>; } // POPCrr - This does a ctpop of a 64-bit register. As such, we have to clear // the top 32-bits before using it. To do this clearing, we use a SLLri X,0. -def POPCrr : F3_1<2, 0b101110, - (outs IntRegs:$dst), (ins IntRegs:$src), - "popc $src, $dst", []>, Requires<[HasV9]>; +let rs1 = 0 in + def POPCrr : F3_1<2, 0b101110, + (outs IntRegs:$dst), (ins IntRegs:$src), + "popc $src, $dst", []>, Requires<[HasV9]>; def : Pat<(ctpop i32:$src), (POPCrr (SLLri $src, 0))>; @@ -801,6 +992,14 @@ def : Pat<(SPlo tglobaladdr:$in), (ORri (i32 G0), tglobaladdr:$in)>; def : Pat<(SPhi tconstpool:$in), (SETHIi tconstpool:$in)>; def : Pat<(SPlo tconstpool:$in), (ORri (i32 G0), tconstpool:$in)>; +// GlobalTLS addresses +def : Pat<(SPhi tglobaltlsaddr:$in), (SETHIi tglobaltlsaddr:$in)>; +def : Pat<(SPlo tglobaltlsaddr:$in), (ORri (i32 G0), tglobaltlsaddr:$in)>; +def : Pat<(add (SPhi tglobaltlsaddr:$in1), (SPlo tglobaltlsaddr:$in2)), + (ADDri (SETHIi tglobaltlsaddr:$in1), (tglobaltlsaddr:$in2))>; +def : Pat<(xor (SPhi tglobaltlsaddr:$in1), (SPlo tglobaltlsaddr:$in2)), + (XORri (SETHIi tglobaltlsaddr:$in1), (tglobaltlsaddr:$in2))>; + // Blockaddress def : Pat<(SPhi tblockaddress:$in), (SETHIi tblockaddress:$in)>; def : Pat<(SPlo tblockaddress:$in), (ORri (i32 G0), tblockaddress:$in)>; diff --git a/lib/Target/Sparc/SparcJITInfo.cpp b/lib/Target/Sparc/SparcJITInfo.cpp new file mode 100644 index 0000000..6493c7d --- /dev/null +++ b/lib/Target/Sparc/SparcJITInfo.cpp @@ -0,0 +1,165 @@ +//===-- SparcJITInfo.cpp - Implement the Sparc JIT Interface --------------===// +// +// 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 JIT interfaces for the Sparc target. +// +//===----------------------------------------------------------------------===// +#define DEBUG_TYPE "jit" +#include "SparcJITInfo.h" +#include "SparcRelocations.h" + +#include "llvm/CodeGen/JITCodeEmitter.h" +#include "llvm/Support/Memory.h" + +using namespace llvm; + +/// JITCompilerFunction - This contains the address of the JIT function used to +/// compile a function lazily. +static TargetJITInfo::JITCompilerFn JITCompilerFunction; + +extern "C" void SparcCompilationCallback(); + +extern "C" { +#if defined (__sparc__) + asm( + ".text\n" + "\t.align 4\n" + "\t.global SparcCompilationCallback\n" + "\t.type SparcCompilationCallback, #function\n" + "SparcCompilationCallback:\n" + // Save current register window. + "\tsave %sp, -192, %sp\n" + // stubaddr+4 is in %g1. + "\tcall SparcCompilationCallbackC\n" + "\t sub %g1, 4, %o0\n" + // restore original register window and + // copy %o0 to %g1 + "\t restore %o0, 0, %g1\n" + // call the new stub + "\tjmp %g1\n" + "\t nop\n" + "\t.size SparcCompilationCallback, .-SparcCompilationCallback" + ); + +#else + void SparcCompilationCallback() { + llvm_unreachable( + "Cannot call SparcCompilationCallback() on a non-sparc arch!"); + } +#endif +} + +#define HI(Val) (((unsigned)(Val)) >> 10) +#define LO(Val) (((unsigned)(Val)) & 0x3FF) + +#define SETHI_INST(imm, rd) (0x01000000 | ((rd) << 25) | ((imm) & 0x3FFFFF)) +#define JMP_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x38 << 19) \ + | ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF)) +#define NOP_INST SETHI_INST(0, 0) + +extern "C" void *SparcCompilationCallbackC(intptr_t StubAddr) { + // Get the address of the compiled code for this function. + intptr_t NewVal = (intptr_t) JITCompilerFunction((void*) StubAddr); + + // Rewrite the function stub so that we don't end up here every time we + // execute the call. We're replacing the first three instructions of the + // stub with code that jumps to the compiled function: + // sethi %hi(NewVal), %g1 + // jmp %g1+%lo(NewVal) + // nop + + *(intptr_t *)(StubAddr) = SETHI_INST(HI(NewVal), 1); + *(intptr_t *)(StubAddr + 4) = JMP_INST(1, LO(NewVal), 0); + *(intptr_t *)(StubAddr + 8) = NOP_INST; + + sys::Memory::InvalidateInstructionCache((void*) StubAddr, 12); + return (void*)StubAddr; +} + +void SparcJITInfo::replaceMachineCodeForFunction(void *Old, void *New) { + assert(0 && "FIXME: Implement SparcJITInfo::replaceMachineCodeForFunction"); +} + + +TargetJITInfo::StubLayout SparcJITInfo::getStubLayout() { + // The stub contains 3 4-byte instructions, aligned at 4 bytes. See + // emitFunctionStub for details. + + StubLayout Result = { 3*4, 4 }; + return Result; +} + +void *SparcJITInfo::emitFunctionStub(const Function *F, void *Fn, + JITCodeEmitter &JCE) +{ + JCE.emitAlignment(4); + void *Addr = (void*) (JCE.getCurrentPCValue()); + if (!sys::Memory::setRangeWritable(Addr, 12)) + llvm_unreachable("ERROR: Unable to mark stub writable."); + + intptr_t EmittedAddr; + if (Fn != (void*)(intptr_t)SparcCompilationCallback) + EmittedAddr = (intptr_t)Fn; + else + EmittedAddr = (intptr_t)SparcCompilationCallback; + + // sethi %hi(EmittedAddr), %g1 + // jmp %g1+%lo(EmittedAddr), %g1 + // nop + + JCE.emitWordBE(SETHI_INST(HI(EmittedAddr), 1)); + JCE.emitWordBE(JMP_INST(1, LO(EmittedAddr), 1)); + JCE.emitWordBE(NOP_INST); + + sys::Memory::InvalidateInstructionCache(Addr, 12); + if (!sys::Memory::setRangeExecutable(Addr, 12)) + llvm_unreachable("ERROR: Unable to mark stub executable."); + + return Addr; +} + +TargetJITInfo::LazyResolverFn +SparcJITInfo::getLazyResolverFunction(JITCompilerFn F) { + JITCompilerFunction = F; + return SparcCompilationCallback; +} + +/// relocate - Before the JIT can run a block of code that has been emitted, +/// it must rewrite the code to contain the actual addresses of any +/// referenced global symbols. +void SparcJITInfo::relocate(void *Function, MachineRelocation *MR, + unsigned NumRelocs, unsigned char *GOTBase) { + for (unsigned i = 0; i != NumRelocs; ++i, ++MR) { + void *RelocPos = (char*) Function + MR->getMachineCodeOffset(); + intptr_t ResultPtr = (intptr_t) MR->getResultPointer(); + + switch ((SP::RelocationType) MR->getRelocationType()) { + case SP::reloc_sparc_hi: + ResultPtr = (ResultPtr >> 10) & 0x3fffff; + break; + + case SP::reloc_sparc_lo: + ResultPtr = (ResultPtr & 0x3ff); + break; + + case SP::reloc_sparc_pc30: + ResultPtr = ((ResultPtr - (intptr_t)RelocPos) >> 2) & 0x3fffffff; + break; + + case SP::reloc_sparc_pc22: + ResultPtr = ((ResultPtr - (intptr_t)RelocPos) >> 2) & 0x3fffff; + break; + + case SP::reloc_sparc_pc19: + ResultPtr = ((ResultPtr - (intptr_t)RelocPos) >> 2) & 0x7ffff; + break; + } + *((unsigned*) RelocPos) |= (unsigned) ResultPtr; + } +} diff --git a/lib/Target/Sparc/SparcJITInfo.h b/lib/Target/Sparc/SparcJITInfo.h new file mode 100644 index 0000000..9c6e488 --- /dev/null +++ b/lib/Target/Sparc/SparcJITInfo.h @@ -0,0 +1,67 @@ +//==- SparcJITInfo.h - Sparc Implementation of the JIT Interface -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declaration of the SparcJITInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef SPARCJITINFO_H +#define SPARCJITINFO_H + +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/Target/TargetJITInfo.h" + +namespace llvm { +class SparcTargetMachine; + +class SparcJITInfo : public TargetJITInfo { + + bool IsPIC; + + public: + explicit SparcJITInfo() + : IsPIC(false) {} + + /// replaceMachineCodeForFunction - Make it so that calling the function + /// whose machine code is at OLD turns into a call to NEW, perhaps by + /// overwriting OLD with a branch to NEW. This is used for self-modifying + /// code. + /// + virtual void replaceMachineCodeForFunction(void *Old, void *New); + + // getStubLayout - Returns the size and alignment of the largest call stub + // on Sparc. + virtual StubLayout getStubLayout(); + + + /// emitFunctionStub - Use the specified JITCodeEmitter object to emit a + /// small native function that simply calls the function at the specified + /// address. + virtual void *emitFunctionStub(const Function *F, void *Fn, + JITCodeEmitter &JCE); + + /// getLazyResolverFunction - Expose the lazy resolver to the JIT. + virtual LazyResolverFn getLazyResolverFunction(JITCompilerFn); + + /// relocate - Before the JIT can run a block of code that has been emitted, + /// it must rewrite the code to contain the actual addresses of any + /// referenced global symbols. + virtual void relocate(void *Function, MachineRelocation *MR, + unsigned NumRelocs, unsigned char *GOTBase); + + /// Initialize - Initialize internal stage for the function being JITted. + void Initialize(const MachineFunction &MF, bool isPIC) { + IsPIC = isPIC; + } + +}; +} + +#endif diff --git a/lib/Target/Sparc/SparcRegisterInfo.cpp b/lib/Target/Sparc/SparcRegisterInfo.cpp index dc97f06..c98613a 100644 --- a/lib/Target/Sparc/SparcRegisterInfo.cpp +++ b/lib/Target/Sparc/SparcRegisterInfo.cpp @@ -40,8 +40,17 @@ SparcRegisterInfo::SparcRegisterInfo(SparcSubtarget &st) const uint16_t* SparcRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { - static const uint16_t CalleeSavedRegs[] = { 0 }; - return CalleeSavedRegs; + return CSR_SaveList; +} + +const uint32_t* +SparcRegisterInfo::getCallPreservedMask(CallingConv::ID CC) const { + return CSR_RegMask; +} + +const uint32_t* +SparcRegisterInfo::getRTCallPreservedMask(CallingConv::ID CC) const { + return RTCSR_RegMask; } BitVector SparcRegisterInfo::getReservedRegs(const MachineFunction &MF) const { @@ -65,6 +74,15 @@ BitVector SparcRegisterInfo::getReservedRegs(const MachineFunction &MF) const { Reserved.set(SP::G0); Reserved.set(SP::G6); Reserved.set(SP::G7); + + // Unaliased double registers are not available in non-V9 targets. + if (!Subtarget.isV9()) { + for (unsigned n = 0; n != 16; ++n) { + for (MCRegAliasIterator AI(SP::D16 + n, this, true); AI.isValid(); ++AI) + Reserved.set(*AI); + } + } + return Reserved; } @@ -74,6 +92,62 @@ SparcRegisterInfo::getPointerRegClass(const MachineFunction &MF, return Subtarget.is64Bit() ? &SP::I64RegsRegClass : &SP::IntRegsRegClass; } +static void replaceFI(MachineFunction &MF, + MachineBasicBlock::iterator II, + MachineInstr &MI, + DebugLoc dl, + unsigned FIOperandNum, int Offset, + unsigned FramePtr) +{ + // Replace frame index with a frame pointer reference. + if (Offset >= -4096 && Offset <= 4095) { + // If the offset is small enough to fit in the immediate field, directly + // encode it. + MI.getOperand(FIOperandNum).ChangeToRegister(FramePtr, false); + MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); + return; + } + + const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); + + // FIXME: it would be better to scavenge a register here instead of + // reserving G1 all of the time. + if (Offset >= 0) { + // Emit nonnegaive immediates with sethi + or. + // sethi %hi(Offset), %g1 + // add %g1, %fp, %g1 + // Insert G1+%lo(offset) into the user. + BuildMI(*MI.getParent(), II, dl, TII.get(SP::SETHIi), SP::G1) + .addImm(HI22(Offset)); + + + // Emit G1 = G1 + I6 + BuildMI(*MI.getParent(), II, dl, TII.get(SP::ADDrr), SP::G1).addReg(SP::G1) + .addReg(FramePtr); + // Insert: G1+%lo(offset) into the user. + MI.getOperand(FIOperandNum).ChangeToRegister(SP::G1, false); + MI.getOperand(FIOperandNum + 1).ChangeToImmediate(LO10(Offset)); + return; + } + + // Emit Negative numbers with sethi + xor + // sethi %hix(Offset), %g1 + // xor %g1, %lox(offset), %g1 + // add %g1, %fp, %g1 + // Insert: G1 + 0 into the user. + BuildMI(*MI.getParent(), II, dl, TII.get(SP::SETHIi), SP::G1) + .addImm(HIX22(Offset)); + BuildMI(*MI.getParent(), II, dl, TII.get(SP::XORri), SP::G1) + .addReg(SP::G1).addImm(LOX10(Offset)); + + BuildMI(*MI.getParent(), II, dl, TII.get(SP::ADDrr), SP::G1).addReg(SP::G1) + .addReg(FramePtr); + // Insert: G1+%lo(offset) into the user. + MI.getOperand(FIOperandNum).ChangeToRegister(SP::G1, false); + MI.getOperand(FIOperandNum + 1).ChangeToImmediate(0); +} + + void SparcRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, unsigned FIOperandNum, @@ -98,35 +172,40 @@ SparcRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, Offset += (stackSize) ? Subtarget.getAdjustedFrameSize(stackSize) : 0 ; } - // Replace frame index with a frame pointer reference. - if (Offset >= -4096 && Offset <= 4095) { - // If the offset is small enough to fit in the immediate field, directly - // encode it. - MI.getOperand(FIOperandNum).ChangeToRegister(FramePtr, false); - MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); - } else { - // Otherwise, emit a G1 = SETHI %hi(offset). FIXME: it would be better to - // scavenge a register here instead of reserving G1 all of the time. - const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); - unsigned OffHi = (unsigned)Offset >> 10U; - BuildMI(*MI.getParent(), II, dl, TII.get(SP::SETHIi), SP::G1).addImm(OffHi); - // Emit G1 = G1 + I6 - BuildMI(*MI.getParent(), II, dl, TII.get(SP::ADDrr), SP::G1).addReg(SP::G1) - .addReg(FramePtr); - // Insert: G1+%lo(offset) into the user. - MI.getOperand(FIOperandNum).ChangeToRegister(SP::G1, false); - MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset & ((1 << 10)-1)); + if (!Subtarget.isV9() || !Subtarget.hasHardQuad()) { + if (MI.getOpcode() == SP::STQFri) { + const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); + unsigned SrcReg = MI.getOperand(2).getReg(); + unsigned SrcEvenReg = getSubReg(SrcReg, SP::sub_even64); + unsigned SrcOddReg = getSubReg(SrcReg, SP::sub_odd64); + MachineInstr *StMI = + BuildMI(*MI.getParent(), II, dl, TII.get(SP::STDFri)) + .addReg(FramePtr).addImm(0).addReg(SrcEvenReg); + replaceFI(MF, II, *StMI, dl, 0, Offset, FramePtr); + MI.setDesc(TII.get(SP::STDFri)); + MI.getOperand(2).setReg(SrcOddReg); + Offset += 8; + } else if (MI.getOpcode() == SP::LDQFri) { + const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); + unsigned DestReg = MI.getOperand(0).getReg(); + unsigned DestEvenReg = getSubReg(DestReg, SP::sub_even64); + unsigned DestOddReg = getSubReg(DestReg, SP::sub_odd64); + MachineInstr *StMI = + BuildMI(*MI.getParent(), II, dl, TII.get(SP::LDDFri), DestEvenReg) + .addReg(FramePtr).addImm(0); + replaceFI(MF, II, *StMI, dl, 1, Offset, FramePtr); + + MI.setDesc(TII.get(SP::LDDFri)); + MI.getOperand(0).setReg(DestOddReg); + Offset += 8; + } } + + replaceFI(MF, II, MI, dl, FIOperandNum, Offset, FramePtr); + } unsigned SparcRegisterInfo::getFrameRegister(const MachineFunction &MF) const { return SP::I6; } -unsigned SparcRegisterInfo::getEHExceptionRegister() const { - llvm_unreachable("What is the exception register"); -} - -unsigned SparcRegisterInfo::getEHHandlerRegister() const { - llvm_unreachable("What is the exception handler register"); -} diff --git a/lib/Target/Sparc/SparcRegisterInfo.h b/lib/Target/Sparc/SparcRegisterInfo.h index 6b77d4e..00b5a98 100644 --- a/lib/Target/Sparc/SparcRegisterInfo.h +++ b/lib/Target/Sparc/SparcRegisterInfo.h @@ -32,6 +32,9 @@ struct SparcRegisterInfo : public SparcGenRegisterInfo { /// Code Generation virtual methods... const uint16_t *getCalleeSavedRegs(const MachineFunction *MF = 0) const; + const uint32_t* getCallPreservedMask(CallingConv::ID CC) const; + + const uint32_t* getRTCallPreservedMask(CallingConv::ID CC) const; BitVector getReservedRegs(const MachineFunction &MF) const; @@ -47,10 +50,6 @@ struct SparcRegisterInfo : public SparcGenRegisterInfo { // Debug information queries. unsigned getFrameRegister(const MachineFunction &MF) const; - - // Exception handling queries. - unsigned getEHExceptionRegister() const; - unsigned getEHHandlerRegister() const; }; } // end namespace llvm diff --git a/lib/Target/Sparc/SparcRegisterInfo.td b/lib/Target/Sparc/SparcRegisterInfo.td index a59c442..2a575c0 100644 --- a/lib/Target/Sparc/SparcRegisterInfo.td +++ b/lib/Target/Sparc/SparcRegisterInfo.td @@ -11,8 +11,8 @@ // Declarations that describe the Sparc register file //===----------------------------------------------------------------------===// -class SparcReg<string n> : Register<n> { - field bits<5> Num; +class SparcReg<bits<16> Enc, string n> : Register<n> { + let HWEncoding = Enc; let Namespace = "SP"; } @@ -23,25 +23,31 @@ class SparcCtrlReg<string n>: Register<n> { let Namespace = "SP" in { def sub_even : SubRegIndex<32>; def sub_odd : SubRegIndex<32, 32>; +def sub_even64 : SubRegIndex<64>; +def sub_odd64 : SubRegIndex<64, 64>; } // Registers are identified with 5-bit ID numbers. // Ri - 32-bit integer registers -class Ri<bits<5> num, string n> : SparcReg<n> { - let Num = num; -} +class Ri<bits<16> Enc, string n> : SparcReg<Enc, n>; + // Rf - 32-bit floating-point registers -class Rf<bits<5> num, string n> : SparcReg<n> { - let Num = num; -} +class Rf<bits<16> Enc, string n> : SparcReg<Enc, n>; + // Rd - Slots in the FP register file for 64-bit floating-point values. -class Rd<bits<5> num, string n, list<Register> subregs> : SparcReg<n> { - let Num = num; +class Rd<bits<16> Enc, string n, list<Register> subregs> : SparcReg<Enc, n> { let SubRegs = subregs; let SubRegIndices = [sub_even, sub_odd]; let CoveredBySubRegs = 1; } +// Rq - Slots in the FP register file for 128-bit floating-point values. +class Rq<bits<16> Enc, string n, list<Register> subregs> : SparcReg<Enc, n> { + let SubRegs = subregs; + let SubRegIndices = [sub_even64, sub_odd64]; + let CoveredBySubRegs = 1; +} + // Control Registers def ICC : SparcCtrlReg<"ICC">; // This represents icc and xcc in 64-bit code. def FCC : SparcCtrlReg<"FCC">; @@ -135,6 +141,43 @@ def D13 : Rd<26, "F26", [F26, F27]>, DwarfRegNum<[85]>; def D14 : Rd<28, "F28", [F28, F29]>, DwarfRegNum<[86]>; def D15 : Rd<30, "F30", [F30, F31]>, DwarfRegNum<[87]>; +// Unaliased double precision floating point registers. +// FIXME: Define DwarfRegNum for these registers. +def D16 : SparcReg< 1, "F32">; +def D17 : SparcReg< 3, "F34">; +def D18 : SparcReg< 5, "F36">; +def D19 : SparcReg< 7, "F38">; +def D20 : SparcReg< 9, "F40">; +def D21 : SparcReg<11, "F42">; +def D22 : SparcReg<13, "F44">; +def D23 : SparcReg<15, "F46">; +def D24 : SparcReg<17, "F48">; +def D25 : SparcReg<19, "F50">; +def D26 : SparcReg<21, "F52">; +def D27 : SparcReg<23, "F54">; +def D28 : SparcReg<25, "F56">; +def D29 : SparcReg<27, "F58">; +def D30 : SparcReg<29, "F60">; +def D31 : SparcReg<31, "F62">; + +// Aliases of the F* registers used to hold 128-bit for values (long doubles). +def Q0 : Rq< 0, "F0", [D0, D1]>; +def Q1 : Rq< 4, "F4", [D2, D3]>; +def Q2 : Rq< 8, "F8", [D4, D5]>; +def Q3 : Rq<12, "F12", [D6, D7]>; +def Q4 : Rq<16, "F16", [D8, D9]>; +def Q5 : Rq<20, "F20", [D10, D11]>; +def Q6 : Rq<24, "F24", [D12, D13]>; +def Q7 : Rq<28, "F28", [D14, D15]>; +def Q8 : Rq< 1, "F32", [D16, D17]>; +def Q9 : Rq< 5, "F36", [D18, D19]>; +def Q10 : Rq< 9, "F40", [D20, D21]>; +def Q11 : Rq<13, "F44", [D22, D23]>; +def Q12 : Rq<17, "F48", [D24, D25]>; +def Q13 : Rq<21, "F52", [D26, D27]>; +def Q14 : Rq<25, "F56", [D28, D29]>; +def Q15 : Rq<29, "F60", [D30, D31]>; + // Register classes. // // FIXME: the register order should be defined in terms of the preferred @@ -158,4 +201,6 @@ def I64Regs : RegisterClass<"SP", [i64], 64, (add IntRegs)>; // Floating point register classes. def FPRegs : RegisterClass<"SP", [f32], 32, (sequence "F%u", 0, 31)>; -def DFPRegs : RegisterClass<"SP", [f64], 64, (sequence "D%u", 0, 15)>; +def DFPRegs : RegisterClass<"SP", [f64], 64, (sequence "D%u", 0, 31)>; + +def QFPRegs : RegisterClass<"SP", [f128], 128, (sequence "Q%u", 0, 15)>; diff --git a/lib/Target/Sparc/SparcRelocations.h b/lib/Target/Sparc/SparcRelocations.h new file mode 100644 index 0000000..388cfe7 --- /dev/null +++ b/lib/Target/Sparc/SparcRelocations.h @@ -0,0 +1,41 @@ +//===-- SparcRelocations.h - Sparc 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 Sparc target-specific relocation types +// (for relocation-model=static). +// +//===----------------------------------------------------------------------===// + +#ifndef SPARC_RELOCATIONS_H +#define SPARC_RELOCATIONS_H + +#include "llvm/CodeGen/MachineRelocation.h" + +namespace llvm { + namespace SP { + enum RelocationType { + // reloc_sparc_hi - upper 22 bits + reloc_sparc_hi = 1, + + // reloc_sparc_lo - lower 10 bits + reloc_sparc_lo = 2, + + // reloc_sparc_pc30 - pc rel. 30 bits for call + reloc_sparc_pc30 = 3, + + // reloc_sparc_pc22 - pc rel. 22 bits for branch + reloc_sparc_pc22 = 4, + + // reloc_sparc_pc22 - pc rel. 19 bits for branch with icc/xcc + reloc_sparc_pc19 = 5 + }; + } +} + +#endif diff --git a/lib/Target/Sparc/SparcSubtarget.cpp b/lib/Target/Sparc/SparcSubtarget.cpp index f9ce098..7d09d0e 100644 --- a/lib/Target/Sparc/SparcSubtarget.cpp +++ b/lib/Target/Sparc/SparcSubtarget.cpp @@ -30,7 +30,8 @@ SparcSubtarget::SparcSubtarget(const std::string &TT, const std::string &CPU, IsV9(false), V8DeprecatedInsts(false), IsVIS(false), - Is64Bit(is64Bit) { + Is64Bit(is64Bit), + HasHardQuad(false) { // Determine default and user specified characteristics std::string CPUName = CPU; diff --git a/lib/Target/Sparc/SparcSubtarget.h b/lib/Target/Sparc/SparcSubtarget.h index 2bf599d..0f81cc9 100644 --- a/lib/Target/Sparc/SparcSubtarget.h +++ b/lib/Target/Sparc/SparcSubtarget.h @@ -29,6 +29,7 @@ class SparcSubtarget : public SparcGenSubtargetInfo { bool V8DeprecatedInsts; bool IsVIS; bool Is64Bit; + bool HasHardQuad; public: SparcSubtarget(const std::string &TT, const std::string &CPU, @@ -37,6 +38,7 @@ public: bool isV9() const { return IsV9; } bool isVIS() const { return IsVIS; } bool useDeprecatedV8Instructions() const { return V8DeprecatedInsts; } + bool hasHardQuad() const { return HasHardQuad; } /// ParseSubtargetFeatures - Parses features string setting specified /// subtarget options. Definition of function is auto generated by tblgen. diff --git a/lib/Target/Sparc/SparcTargetMachine.cpp b/lib/Target/Sparc/SparcTargetMachine.cpp index a7355f4..0f93674 100644 --- a/lib/Target/Sparc/SparcTargetMachine.cpp +++ b/lib/Target/Sparc/SparcTargetMachine.cpp @@ -65,6 +65,13 @@ bool SparcPassConfig::addInstSelector() { return false; } +bool SparcTargetMachine::addCodeEmitter(PassManagerBase &PM, + JITCodeEmitter &JCE) { + // Machine code emitter pass for Sparc. + PM.add(createSparcJITCodeEmitterPass(*this, JCE)); + return false; +} + /// addPreEmitPass - This pass may be implemented by targets that want to run /// passes immediately before machine code is emitted. This should return /// true if -print-machineinstrs should print out the code after the passes. diff --git a/lib/Target/Sparc/SparcTargetMachine.h b/lib/Target/Sparc/SparcTargetMachine.h index 081075d..8c9bcd3 100644 --- a/lib/Target/Sparc/SparcTargetMachine.h +++ b/lib/Target/Sparc/SparcTargetMachine.h @@ -17,6 +17,7 @@ #include "SparcFrameLowering.h" #include "SparcISelLowering.h" #include "SparcInstrInfo.h" +#include "SparcJITInfo.h" #include "SparcSelectionDAGInfo.h" #include "SparcSubtarget.h" #include "llvm/IR/DataLayout.h" @@ -32,6 +33,7 @@ class SparcTargetMachine : public LLVMTargetMachine { SparcTargetLowering TLInfo; SparcSelectionDAGInfo TSInfo; SparcFrameLowering FrameLowering; + SparcJITInfo JITInfo; public: SparcTargetMachine(const Target &T, StringRef TT, StringRef CPU, StringRef FS, const TargetOptions &Options, @@ -52,10 +54,14 @@ public: virtual const SparcSelectionDAGInfo* getSelectionDAGInfo() const { return &TSInfo; } + virtual SparcJITInfo *getJITInfo() { + return &JITInfo; + } virtual const DataLayout *getDataLayout() const { return &DL; } // Pass Pipeline Configuration virtual TargetPassConfig *createPassConfig(PassManagerBase &PM); + virtual bool addCodeEmitter(PassManagerBase &PM, JITCodeEmitter &JCE); }; /// SparcV8TargetMachine - Sparc 32-bit target machine diff --git a/lib/Target/Sparc/TargetInfo/SparcTargetInfo.cpp b/lib/Target/Sparc/TargetInfo/SparcTargetInfo.cpp index bb71463..4eea163 100644 --- a/lib/Target/Sparc/TargetInfo/SparcTargetInfo.cpp +++ b/lib/Target/Sparc/TargetInfo/SparcTargetInfo.cpp @@ -15,7 +15,9 @@ using namespace llvm; Target llvm::TheSparcTarget; Target llvm::TheSparcV9Target; -extern "C" void LLVMInitializeSparcTargetInfo() { - RegisterTarget<Triple::sparc> X(TheSparcTarget, "sparc", "Sparc"); - RegisterTarget<Triple::sparcv9> Y(TheSparcV9Target, "sparcv9", "Sparc V9"); +extern "C" void LLVMInitializeSparcTargetInfo() { + RegisterTarget<Triple::sparc, /*HasJIT=*/ true> + X(TheSparcTarget, "sparc", "Sparc"); + RegisterTarget<Triple::sparcv9, /*HasJIT=*/ true> + Y(TheSparcV9Target, "sparcv9", "Sparc V9"); } |