X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FMips%2FMipsAsmPrinter.cpp;h=43ef379080200c8e56ace805abed84aabc05df23;hb=e1610162fb298e43a9bb1c94cadc0579ff31160d;hp=2bd6df7fd3fafd5b26e295ae735f7f2495ade5f7;hpb=3c733ea0649665b81947de596d410a5c4f42f5f4;p=oota-llvm.git diff --git a/lib/Target/Mips/MipsAsmPrinter.cpp b/lib/Target/Mips/MipsAsmPrinter.cpp index 2bd6df7fd3f..43ef3790802 100644 --- a/lib/Target/Mips/MipsAsmPrinter.cpp +++ b/lib/Target/Mips/MipsAsmPrinter.cpp @@ -12,9 +12,9 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "mips-asm-printer" #include "InstPrinter/MipsInstPrinter.h" #include "MCTargetDesc/MipsBaseInfo.h" +#include "MCTargetDesc/MipsMCNaCl.h" #include "Mips.h" #include "MipsAsmPrinter.h" #include "MipsInstrInfo.h" @@ -27,6 +27,7 @@ #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/DataLayout.h" @@ -34,28 +35,53 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/Mangler.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCELFStreamer.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/ELF.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetOptions.h" +#include using namespace llvm; +#define DEBUG_TYPE "mips-asm-printer" + MipsTargetStreamer &MipsAsmPrinter::getTargetStreamer() { return static_cast(*OutStreamer.getTargetStreamer()); } bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) { + Subtarget = &TM.getSubtarget(); + // Initialize TargetLoweringObjectFile. - if (Subtarget->allowMixed16_32()) - const_cast(getObjFileLowering()) + const_cast(getObjFileLowering()) .Initialize(OutContext, TM); + MipsFI = MF.getInfo(); + if (Subtarget->inMips16Mode()) + for (std::map< + const char *, + const llvm::Mips16HardFloatInfo::FuncSignature *>::const_iterator + it = MipsFI->StubsNeeded.begin(); + it != MipsFI->StubsNeeded.end(); ++it) { + const char *Symbol = it->first; + const llvm::Mips16HardFloatInfo::FuncSignature *Signature = it->second; + if (StubsNeeded.find(Symbol) == StubsNeeded.end()) + StubsNeeded[Symbol] = Signature; + } MCP = MF.getConstantPool(); + + // In NaCl, all indirect jump targets must be aligned to bundle size. + if (Subtarget->isTargetNaCl()) + NaClAlignIndirectJumpTargets(MF); + AsmPrinter::runOnMachineFunction(MF); return true; } @@ -67,7 +93,46 @@ bool MipsAsmPrinter::lowerOperand(const MachineOperand &MO, MCOperand &MCOp) { #include "MipsGenMCPseudoLowering.inc" +// Lower PseudoReturn/PseudoIndirectBranch/PseudoIndirectBranch64 to JR, JR_MM, +// JALR, or JALR64 as appropriate for the target +void MipsAsmPrinter::emitPseudoIndirectBranch(MCStreamer &OutStreamer, + const MachineInstr *MI) { + bool HasLinkReg = false; + MCInst TmpInst0; + + if (Subtarget->hasMips64r6()) { + // MIPS64r6 should use (JALR64 ZERO_64, $rs) + TmpInst0.setOpcode(Mips::JALR64); + HasLinkReg = true; + } else if (Subtarget->hasMips32r6()) { + // MIPS32r6 should use (JALR ZERO, $rs) + TmpInst0.setOpcode(Mips::JALR); + HasLinkReg = true; + } else if (Subtarget->inMicroMipsMode()) + // microMIPS should use (JR_MM $rs) + TmpInst0.setOpcode(Mips::JR_MM); + else { + // Everything else should use (JR $rs) + TmpInst0.setOpcode(Mips::JR); + } + + MCOperand MCOp; + + if (HasLinkReg) { + unsigned ZeroReg = Subtarget->isGP64bit() ? Mips::ZERO_64 : Mips::ZERO; + TmpInst0.addOperand(MCOperand::CreateReg(ZeroReg)); + } + + lowerOperand(MI->getOperand(0), MCOp); + TmpInst0.addOperand(MCOp); + + EmitToStreamer(OutStreamer, TmpInst0); +} + void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { + MipsTargetStreamer &TS = getTargetStreamer(); + TS.forbidModuleDirective(); + if (MI->isDebugValue()) { SmallString<128> Str; raw_svector_ostream OS(Str); @@ -117,6 +182,14 @@ void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { if (emitPseudoExpansionLowering(OutStreamer, &*I)) continue; + if (I->getOpcode() == Mips::PseudoReturn || + I->getOpcode() == Mips::PseudoReturn64 || + I->getOpcode() == Mips::PseudoIndirectBranch || + I->getOpcode() == Mips::PseudoIndirectBranch64) { + emitPseudoIndirectBranch(OutStreamer, &*I); + continue; + } + // The inMips16Mode() test is not permanent. // Some instructions are marked as pseudo right now which // would make the test fail for the wrong reason but @@ -124,12 +197,13 @@ void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { // removing another test for this situation downstream in the // callchain. // - if (I->isPseudo() && !Subtarget->inMips16Mode()) + if (I->isPseudo() && !Subtarget->inMips16Mode() + && !isLongBranchPseudo(I->getOpcode())) llvm_unreachable("Pseudo opcode found in EmitInstruction()"); MCInst TmpInst0; MCInstLowering.Lower(I, TmpInst0); - OutStreamer.EmitInstruction(TmpInst0); + EmitToStreamer(OutStreamer, TmpInst0); } while ((++I != E) && I->isInsideBundle()); // Delay slot check } @@ -170,7 +244,7 @@ void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { // Create a bitmask with all callee saved registers for CPU or Floating Point // registers. For CPU registers consider RA, GP and FP for saving if necessary. -void MipsAsmPrinter::printSavedRegsBitmask(raw_ostream &O) { +void MipsAsmPrinter::printSavedRegsBitmask() { // CPU and FPU Saved Registers Bitmasks unsigned CPUBitmask = 0, FPUBitmask = 0; int CPUTopSavedRegOff, FPUTopSavedRegOff; @@ -192,7 +266,8 @@ void MipsAsmPrinter::printSavedRegsBitmask(raw_ostream &O) { if (Mips::GPR32RegClass.contains(Reg)) break; - unsigned RegNum = TM.getRegisterInfo()->getEncodingValue(Reg); + unsigned RegNum = + TM.getSubtargetImpl()->getRegisterInfo()->getEncodingValue(Reg); if (Mips::AFGR64RegClass.contains(Reg)) { FPUBitmask |= (3 << RegNum); CSFPRegsSize += AFGR64RegSize; @@ -207,7 +282,8 @@ void MipsAsmPrinter::printSavedRegsBitmask(raw_ostream &O) { // Set CPU Bitmask. for (; i != e; ++i) { unsigned Reg = CSI[i].getReg(); - unsigned RegNum = TM.getRegisterInfo()->getEncodingValue(Reg); + unsigned RegNum = + TM.getSubtargetImpl()->getRegisterInfo()->getEncodingValue(Reg); CPUBitmask |= (1 << RegNum); } @@ -218,20 +294,12 @@ void MipsAsmPrinter::printSavedRegsBitmask(raw_ostream &O) { // CPU Regs are saved below FP Regs. CPUTopSavedRegOff = CPUBitmask ? -CSFPRegsSize - CPURegSize : 0; + MipsTargetStreamer &TS = getTargetStreamer(); // Print CPUBitmask - O << "\t.mask \t"; printHex32(CPUBitmask, O); - O << ',' << CPUTopSavedRegOff << '\n'; + TS.emitMask(CPUBitmask, CPUTopSavedRegOff); // Print FPUBitmask - O << "\t.fmask\t"; printHex32(FPUBitmask, O); - O << "," << FPUTopSavedRegOff << '\n'; -} - -// Print a 32 bit hex number with all numbers. -void MipsAsmPrinter::printHex32(unsigned Value, raw_ostream &O) { - O << "0x"; - for (int i = 7; i >= 0; i--) - O.write_hex((Value & (0xF << (i*4))) >> (i*4)); + TS.emitFMask(FPUBitmask, FPUTopSavedRegOff); } //===----------------------------------------------------------------------===// @@ -240,50 +308,53 @@ void MipsAsmPrinter::printHex32(unsigned Value, raw_ostream &O) { /// Frame Directive void MipsAsmPrinter::emitFrameDirective() { - const TargetRegisterInfo &RI = *TM.getRegisterInfo(); + const TargetRegisterInfo &RI = *TM.getSubtargetImpl()->getRegisterInfo(); unsigned stackReg = RI.getFrameRegister(*MF); unsigned returnReg = RI.getRARegister(); unsigned stackSize = MF->getFrameInfo()->getStackSize(); - if (OutStreamer.hasRawTextSupport()) - OutStreamer.EmitRawText("\t.frame\t$" + - StringRef(MipsInstPrinter::getRegisterName(stackReg)).lower() + - "," + Twine(stackSize) + ",$" + - StringRef(MipsInstPrinter::getRegisterName(returnReg)).lower()); + getTargetStreamer().emitFrame(stackReg, stackSize, returnReg); } /// Emit Set directives. const char *MipsAsmPrinter::getCurrentABIString() const { - switch (Subtarget->getTargetABI()) { - case MipsSubtarget::O32: return "abi32"; - case MipsSubtarget::N32: return "abiN32"; - case MipsSubtarget::N64: return "abi64"; - case MipsSubtarget::EABI: return "eabi32"; // TODO: handle eabi64 + switch (Subtarget->getABI().GetEnumValue()) { + case MipsABIInfo::ABI::O32: return "abi32"; + case MipsABIInfo::ABI::N32: return "abiN32"; + case MipsABIInfo::ABI::N64: return "abi64"; + case MipsABIInfo::ABI::EABI: return "eabi32"; // TODO: handle eabi64 default: llvm_unreachable("Unknown Mips ABI"); } } void MipsAsmPrinter::EmitFunctionEntryLabel() { + MipsTargetStreamer &TS = getTargetStreamer(); + + // NaCl sandboxing requires that indirect call instructions are masked. + // This means that function entry points should be bundle-aligned. + if (Subtarget->isTargetNaCl()) + EmitAlignment(std::max(MF->getAlignment(), MIPS_NACL_BUNDLE_ALIGN)); + if (Subtarget->inMicroMipsMode()) - getTargetStreamer().emitDirectiveSetMicroMips(); + TS.emitDirectiveSetMicroMips(); + else + TS.emitDirectiveSetNoMicroMips(); - if (OutStreamer.hasRawTextSupport()) { - if (Subtarget->inMips16Mode()) - OutStreamer.EmitRawText(StringRef("\t.set\tmips16")); - else - OutStreamer.EmitRawText(StringRef("\t.set\tnomips16")); - // leave out until FSF available gas has micromips changes - // OutStreamer.EmitRawText(StringRef("\t.set\tnomicromips")); - OutStreamer.EmitRawText("\t.ent\t" + Twine(CurrentFnSym->getName())); - } + if (Subtarget->inMips16Mode()) + TS.emitDirectiveSetMips16(); + else + TS.emitDirectiveSetNoMips16(); + TS.emitDirectiveEnt(*CurrentFnSym); OutStreamer.EmitLabel(CurrentFnSym); } /// EmitFunctionBodyStart - Targets can override this to emit stuff before /// the first basic block in the function. void MipsAsmPrinter::EmitFunctionBodyStart() { + MipsTargetStreamer &TS = getTargetStreamer(); + MCInstLowering.Initialize(&MF->getContext()); bool IsNakedFunction = @@ -293,34 +364,30 @@ void MipsAsmPrinter::EmitFunctionBodyStart() { if (!IsNakedFunction) emitFrameDirective(); - if (OutStreamer.hasRawTextSupport()) { - SmallString<128> Str; - raw_svector_ostream OS(Str); - if (!IsNakedFunction) - printSavedRegsBitmask(OS); - OutStreamer.EmitRawText(OS.str()); - if (!Subtarget->inMips16Mode()) { - OutStreamer.EmitRawText(StringRef("\t.set\tnoreorder")); - OutStreamer.EmitRawText(StringRef("\t.set\tnomacro")); - OutStreamer.EmitRawText(StringRef("\t.set\tnoat")); - } + if (!IsNakedFunction) + printSavedRegsBitmask(); + + if (!Subtarget->inMips16Mode()) { + TS.emitDirectiveSetNoReorder(); + TS.emitDirectiveSetNoMacro(); + TS.emitDirectiveSetNoAt(); } } /// EmitFunctionBodyEnd - Targets can override this to emit stuff after /// the last basic block in the function. void MipsAsmPrinter::EmitFunctionBodyEnd() { + MipsTargetStreamer &TS = getTargetStreamer(); + // There are instruction for this macros, but they must // always be at the function end, and we can't emit and // break with BB logic. - if (OutStreamer.hasRawTextSupport()) { - if (!Subtarget->inMips16Mode()) { - OutStreamer.EmitRawText(StringRef("\t.set\tat")); - OutStreamer.EmitRawText(StringRef("\t.set\tmacro")); - OutStreamer.EmitRawText(StringRef("\t.set\treorder")); - } - OutStreamer.EmitRawText("\t.end\t" + Twine(CurrentFnSym->getName())); + if (!Subtarget->inMips16Mode()) { + TS.emitDirectiveSetAt(); + TS.emitDirectiveSetMacro(); + TS.emitDirectiveSetReorder(); } + TS.emitDirectiveEnd(CurrentFnSym->getName()); // Make sure to terminate any constant pools that were at the end // of the function. if (!InConstantPool) @@ -495,7 +562,7 @@ bool MipsAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum, raw_ostream &O) { - const DataLayout *DL = TM.getDataLayout(); + const DataLayout *DL = TM.getSubtargetImpl()->getDataLayout(); const MachineOperand &MO = MI->getOperand(opNum); bool closeP = false; @@ -604,84 +671,327 @@ printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O, } void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) { - // FIXME: Use SwitchSection. - - // TODO: Need to add -mabicalls and -mno-abicalls flags. - // Currently we assume that -mabicalls is the default. - getTargetStreamer().emitDirectiveAbiCalls(); - Reloc::Model RM = Subtarget->getRelocationModel(); - if (RM == Reloc::Static && !Subtarget->hasMips64()) - getTargetStreamer().emitDirectiveOptionPic0(); + bool IsABICalls = Subtarget->isABICalls(); + if (IsABICalls) { + getTargetStreamer().emitDirectiveAbiCalls(); + Reloc::Model RM = TM.getRelocationModel(); + // FIXME: This condition should be a lot more complicated that it is here. + // Ideally it should test for properties of the ABI and not the ABI + // itself. + // For the moment, I'm only correcting enough to make MIPS-IV work. + if (RM == Reloc::Static && !Subtarget->isABI_N64()) + getTargetStreamer().emitDirectiveOptionPic0(); + } // Tell the assembler which ABI we are using - if (OutStreamer.hasRawTextSupport()) - OutStreamer.EmitRawText("\t.section .mdebug." + - Twine(getCurrentABIString())); + std::string SectionName = std::string(".mdebug.") + getCurrentABIString(); + OutStreamer.SwitchSection(OutContext.getELFSection( + SectionName, ELF::SHT_PROGBITS, 0, SectionKind::getDataRel())); + + // NaN: At the moment we only support: + // 1. .nan legacy (default) + // 2. .nan 2008 + Subtarget->isNaN2008() ? getTargetStreamer().emitDirectiveNaN2008() + : getTargetStreamer().emitDirectiveNaNLegacy(); // TODO: handle O64 ABI - if (OutStreamer.hasRawTextSupport()) { - if (Subtarget->isABI_EABI()) { - if (Subtarget->isGP32bit()) - OutStreamer.EmitRawText(StringRef("\t.section .gcc_compiled_long32")); - else - OutStreamer.EmitRawText(StringRef("\t.section .gcc_compiled_long64")); - } + + if (Subtarget->isABI_EABI()) { + if (Subtarget->isGP32bit()) + OutStreamer.SwitchSection( + OutContext.getELFSection(".gcc_compiled_long32", ELF::SHT_PROGBITS, 0, + SectionKind::getDataRel())); + else + OutStreamer.SwitchSection( + OutContext.getELFSection(".gcc_compiled_long64", ELF::SHT_PROGBITS, 0, + SectionKind::getDataRel())); } - // return to previous section - if (OutStreamer.hasRawTextSupport()) - OutStreamer.EmitRawText(StringRef("\t.previous")); + getTargetStreamer().updateABIInfo(*Subtarget); + + // We should always emit a '.module fp=...' but binutils 2.24 does not accept + // it. We therefore emit it when it contradicts the ABI defaults (-mfpxx or + // -mfp64) and omit it otherwise. + if (Subtarget->isABI_O32() && (Subtarget->isABI_FPXX() || + Subtarget->isFP64bit())) + getTargetStreamer().emitDirectiveModuleFP(); + + // We should always emit a '.module [no]oddspreg' but binutils 2.24 does not + // accept it. We therefore emit it when it contradicts the default or an + // option has changed the default (i.e. FPXX) and omit it otherwise. + if (Subtarget->isABI_O32() && (!Subtarget->useOddSPReg() || + Subtarget->isABI_FPXX())) + getTargetStreamer().emitDirectiveModuleOddSPReg(Subtarget->useOddSPReg(), + Subtarget->isABI_O32()); +} +void MipsAsmPrinter::EmitJal(MCSymbol *Symbol) { + MCInst I; + I.setOpcode(Mips::JAL); + I.addOperand( + MCOperand::CreateExpr(MCSymbolRefExpr::Create(Symbol, OutContext))); + OutStreamer.EmitInstruction(I, getSubtargetInfo()); } -static void emitELFHeaderFlagsCG(MipsTargetStreamer &TargetStreamer, - const MipsSubtarget &Subtarget) { - // Update e_header flags - unsigned EFlags = 0; +void MipsAsmPrinter::EmitInstrReg(unsigned Opcode, unsigned Reg) { + MCInst I; + I.setOpcode(Opcode); + I.addOperand(MCOperand::CreateReg(Reg)); + OutStreamer.EmitInstruction(I, getSubtargetInfo()); +} - // TODO: Need to add -mabicalls and -mno-abicalls flags. - // Currently we assume that -mabicalls is the default. - EFlags |= ELF::EF_MIPS_CPIC; +void MipsAsmPrinter::EmitInstrRegReg(unsigned Opcode, unsigned Reg1, + unsigned Reg2) { + MCInst I; + // + // Because of the current td files for Mips32, the operands for MTC1 + // appear backwards from their normal assembly order. It's not a trivial + // change to fix this in the td file so we adjust for it here. + // + if (Opcode == Mips::MTC1) { + unsigned Temp = Reg1; + Reg1 = Reg2; + Reg2 = Temp; + } + I.setOpcode(Opcode); + I.addOperand(MCOperand::CreateReg(Reg1)); + I.addOperand(MCOperand::CreateReg(Reg2)); + OutStreamer.EmitInstruction(I, getSubtargetInfo()); +} - if (Subtarget.inMips16Mode()) - EFlags |= ELF::EF_MIPS_ARCH_ASE_M16; - else - EFlags |= ELF::EF_MIPS_NOREORDER; - - // Architecture - if (Subtarget.hasMips64r2()) - EFlags |= ELF::EF_MIPS_ARCH_64R2; - else if (Subtarget.hasMips64()) - EFlags |= ELF::EF_MIPS_ARCH_64; - else if (Subtarget.hasMips32r2()) - EFlags |= ELF::EF_MIPS_ARCH_32R2; - else - EFlags |= ELF::EF_MIPS_ARCH_32; +void MipsAsmPrinter::EmitInstrRegRegReg(unsigned Opcode, unsigned Reg1, + unsigned Reg2, unsigned Reg3) { + MCInst I; + I.setOpcode(Opcode); + I.addOperand(MCOperand::CreateReg(Reg1)); + I.addOperand(MCOperand::CreateReg(Reg2)); + I.addOperand(MCOperand::CreateReg(Reg3)); + OutStreamer.EmitInstruction(I, getSubtargetInfo()); +} - if (Subtarget.inMicroMipsMode()) - EFlags |= ELF::EF_MIPS_MICROMIPS; +void MipsAsmPrinter::EmitMovFPIntPair(unsigned MovOpc, unsigned Reg1, + unsigned Reg2, unsigned FPReg1, + unsigned FPReg2, bool LE) { + if (!LE) { + unsigned temp = Reg1; + Reg1 = Reg2; + Reg2 = temp; + } + EmitInstrRegReg(MovOpc, Reg1, FPReg1); + EmitInstrRegReg(MovOpc, Reg2, FPReg2); +} - // ABI - if (Subtarget.isABI_O32()) - EFlags |= ELF::EF_MIPS_ABI_O32; +void MipsAsmPrinter::EmitSwapFPIntParams(Mips16HardFloatInfo::FPParamVariant PV, + bool LE, bool ToFP) { + using namespace Mips16HardFloatInfo; + unsigned MovOpc = ToFP ? Mips::MTC1 : Mips::MFC1; + switch (PV) { + case FSig: + EmitInstrRegReg(MovOpc, Mips::A0, Mips::F12); + break; + case FFSig: + EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F14, LE); + break; + case FDSig: + EmitInstrRegReg(MovOpc, Mips::A0, Mips::F12); + EmitMovFPIntPair(MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE); + break; + case DSig: + EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); + break; + case DDSig: + EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); + EmitMovFPIntPair(MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE); + break; + case DFSig: + EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); + EmitInstrRegReg(MovOpc, Mips::A2, Mips::F14); + break; + case NoSig: + return; + } +} - // Relocation Model - Reloc::Model RM = Subtarget.getRelocationModel(); - if (RM == Reloc::PIC_ || RM == Reloc::Default) - EFlags |= ELF::EF_MIPS_PIC; - else if (RM == Reloc::Static) - ; // Do nothing for Reloc::Static - else - llvm_unreachable("Unsupported relocation model for e_flags"); +void +MipsAsmPrinter::EmitSwapFPIntRetval(Mips16HardFloatInfo::FPReturnVariant RV, + bool LE) { + using namespace Mips16HardFloatInfo; + unsigned MovOpc = Mips::MFC1; + switch (RV) { + case FRet: + EmitInstrRegReg(MovOpc, Mips::V0, Mips::F0); + break; + case DRet: + EmitMovFPIntPair(MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); + break; + case CFRet: + EmitMovFPIntPair(MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); + break; + case CDRet: + EmitMovFPIntPair(MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); + EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F2, Mips::F3, LE); + break; + case NoFPRet: + break; + } +} - TargetStreamer.emitMipsHackELFFlags(EFlags); +void MipsAsmPrinter::EmitFPCallStub( + const char *Symbol, const Mips16HardFloatInfo::FuncSignature *Signature) { + MCSymbol *MSymbol = OutContext.GetOrCreateSymbol(StringRef(Symbol)); + using namespace Mips16HardFloatInfo; + bool LE = Subtarget->isLittle(); + // + // .global xxxx + // + OutStreamer.EmitSymbolAttribute(MSymbol, MCSA_Global); + const char *RetType; + // + // make the comment field identifying the return and parameter + // types of the floating point stub + // # Stub function to call rettype xxxx (params) + // + switch (Signature->RetSig) { + case FRet: + RetType = "float"; + break; + case DRet: + RetType = "double"; + break; + case CFRet: + RetType = "complex"; + break; + case CDRet: + RetType = "double complex"; + break; + case NoFPRet: + RetType = ""; + break; + } + const char *Parms; + switch (Signature->ParamSig) { + case FSig: + Parms = "float"; + break; + case FFSig: + Parms = "float, float"; + break; + case FDSig: + Parms = "float, double"; + break; + case DSig: + Parms = "double"; + break; + case DDSig: + Parms = "double, double"; + break; + case DFSig: + Parms = "double, float"; + break; + case NoSig: + Parms = ""; + break; + } + OutStreamer.AddComment("\t# Stub function to call " + Twine(RetType) + " " + + Twine(Symbol) + " (" + Twine(Parms) + ")"); + // + // probably not necessary but we save and restore the current section state + // + OutStreamer.PushSection(); + // + // .section mips16.call.fpxxxx,"ax",@progbits + // + const MCSectionELF *M = OutContext.getELFSection( + ".mips16.call.fp." + std::string(Symbol), ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | ELF::SHF_EXECINSTR, SectionKind::getText()); + OutStreamer.SwitchSection(M, nullptr); + // + // .align 2 + // + OutStreamer.EmitValueToAlignment(4); + MipsTargetStreamer &TS = getTargetStreamer(); + // + // .set nomips16 + // .set nomicromips + // + TS.emitDirectiveSetNoMips16(); + TS.emitDirectiveSetNoMicroMips(); + // + // .ent __call_stub_fp_xxxx + // .type __call_stub_fp_xxxx,@function + // __call_stub_fp_xxxx: + // + std::string x = "__call_stub_fp_" + std::string(Symbol); + MCSymbol *Stub = OutContext.GetOrCreateSymbol(StringRef(x)); + TS.emitDirectiveEnt(*Stub); + MCSymbol *MType = + OutContext.GetOrCreateSymbol("__call_stub_fp_" + Twine(Symbol)); + OutStreamer.EmitSymbolAttribute(MType, MCSA_ELF_TypeFunction); + OutStreamer.EmitLabel(Stub); + // + // we just handle non pic for now. these function will not be + // called otherwise. when the full stub generation is moved here + // we need to deal with pic. + // + if (Subtarget->getRelocationModel() == Reloc::PIC_) + llvm_unreachable("should not be here if we are compiling pic"); + TS.emitDirectiveSetReorder(); + // + // We need to add a MipsMCExpr class to MCTargetDesc to fully implement + // stubs without raw text but this current patch is for compiler generated + // functions and they all return some value. + // The calling sequence for non pic is different in that case and we need + // to implement %lo and %hi in order to handle the case of no return value + // See the corresponding method in Mips16HardFloat for details. + // + // mov the return address to S2. + // we have no stack space to store it and we are about to make another call. + // We need to make sure that the enclosing function knows to save S2 + // This should have already been handled. + // + // Mov $18, $31 + + EmitInstrRegRegReg(Mips::ADDu, Mips::S2, Mips::RA, Mips::ZERO); + + EmitSwapFPIntParams(Signature->ParamSig, LE, true); + + // Jal xxxx + // + EmitJal(MSymbol); + + // fix return values + EmitSwapFPIntRetval(Signature->RetSig, LE); + // + // do the return + // if (Signature->RetSig == NoFPRet) + // llvm_unreachable("should not be any stubs here with no return value"); + // else + EmitInstrReg(Mips::JR, Mips::S2); + + MCSymbol *Tmp = OutContext.CreateTempSymbol(); + OutStreamer.EmitLabel(Tmp); + const MCSymbolRefExpr *E = MCSymbolRefExpr::Create(Stub, OutContext); + const MCSymbolRefExpr *T = MCSymbolRefExpr::Create(Tmp, OutContext); + const MCExpr *T_min_E = MCBinaryExpr::CreateSub(T, E, OutContext); + OutStreamer.EmitELFSize(Stub, T_min_E); + TS.emitDirectiveEnd(x); + OutStreamer.PopSection(); } void MipsAsmPrinter::EmitEndOfAsmFile(Module &M) { - // Emit Mips ELF register info - Subtarget->getMReginfo().emitMipsReginfoSectionCG( - OutStreamer, getObjFileLowering(), *Subtarget); - emitELFHeaderFlagsCG(getTargetStreamer(), *Subtarget); + // Emit needed stubs + // + for (std::map< + const char *, + const llvm::Mips16HardFloatInfo::FuncSignature *>::const_iterator + it = StubsNeeded.begin(); + it != StubsNeeded.end(); ++it) { + const char *Symbol = it->first; + const llvm::Mips16HardFloatInfo::FuncSignature *Signature = it->second; + EmitFPCallStub(Symbol, Signature); + } + // return to the text section + OutStreamer.SwitchSection(OutContext.getObjectFileInfo()->getTextSection()); } void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI, @@ -689,6 +999,34 @@ void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI, // TODO: implement } +// Align all targets of indirect branches on bundle size. Used only if target +// is NaCl. +void MipsAsmPrinter::NaClAlignIndirectJumpTargets(MachineFunction &MF) { + // Align all blocks that are jumped to through jump table. + if (MachineJumpTableInfo *JtInfo = MF.getJumpTableInfo()) { + const std::vector &JT = JtInfo->getJumpTables(); + for (unsigned I = 0; I < JT.size(); ++I) { + const std::vector &MBBs = JT[I].MBBs; + + for (unsigned J = 0; J < MBBs.size(); ++J) + MBBs[J]->setAlignment(MIPS_NACL_BUNDLE_ALIGN); + } + } + + // If basic block address is taken, block can be target of indirect branch. + for (MachineFunction::iterator MBB = MF.begin(), E = MF.end(); + MBB != E; ++MBB) { + if (MBB->hasAddressTaken()) + MBB->setAlignment(MIPS_NACL_BUNDLE_ALIGN); + } +} + +bool MipsAsmPrinter::isLongBranchPseudo(int Opcode) const { + return (Opcode == Mips::LONG_BRANCH_LUi + || Opcode == Mips::LONG_BRANCH_ADDiu + || Opcode == Mips::LONG_BRANCH_DADDiu); +} + // Force static initialization. extern "C" void LLVMInitializeMipsAsmPrinter() { RegisterAsmPrinter X(TheMipsTarget);