X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FTarget%2FMips%2FMCTargetDesc%2FMipsTargetStreamer.cpp;h=3aa4027613b195210aa14b243c0cb2145a937dae;hp=825c164472231edae6e40a4ef261af9c3ace56f0;hb=4b5e7542df8563beb97407317e857439fa7544c8;hpb=ac9f143a696f5d17bb97aee2230de67c002105b2 diff --git a/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp b/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp index 825c1644722..3aa4027613b 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp @@ -12,14 +12,14 @@ //===----------------------------------------------------------------------===// #include "InstPrinter/MipsInstPrinter.h" +#include "MipsMCTargetDesc.h" #include "MipsTargetObjectFile.h" #include "MipsTargetStreamer.h" -#include "MipsMCTargetDesc.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCELF.h" #include "llvm/MC/MCSectionELF.h" -#include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ELF.h" #include "llvm/Support/ErrorHandling.h" @@ -27,10 +27,43 @@ using namespace llvm; -// Pin vtable to this file. -void MipsTargetStreamer::anchor() {} - -MipsTargetStreamer::MipsTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {} +MipsTargetStreamer::MipsTargetStreamer(MCStreamer &S) + : MCTargetStreamer(S), canHaveModuleDirective(true) {} +void MipsTargetStreamer::emitDirectiveSetMicroMips() {} +void MipsTargetStreamer::emitDirectiveSetNoMicroMips() {} +void MipsTargetStreamer::emitDirectiveSetMips16() {} +void MipsTargetStreamer::emitDirectiveSetNoMips16() {} +void MipsTargetStreamer::emitDirectiveSetReorder() {} +void MipsTargetStreamer::emitDirectiveSetNoReorder() {} +void MipsTargetStreamer::emitDirectiveSetMacro() {} +void MipsTargetStreamer::emitDirectiveSetNoMacro() {} +void MipsTargetStreamer::emitDirectiveSetAt() {} +void MipsTargetStreamer::emitDirectiveSetNoAt() {} +void MipsTargetStreamer::emitDirectiveEnd(StringRef Name) {} +void MipsTargetStreamer::emitDirectiveEnt(const MCSymbol &Symbol) {} +void MipsTargetStreamer::emitDirectiveAbiCalls() {} +void MipsTargetStreamer::emitDirectiveNaN2008() {} +void MipsTargetStreamer::emitDirectiveNaNLegacy() {} +void MipsTargetStreamer::emitDirectiveOptionPic0() {} +void MipsTargetStreamer::emitDirectiveOptionPic2() {} +void MipsTargetStreamer::emitFrame(unsigned StackReg, unsigned StackSize, + unsigned ReturnReg) {} +void MipsTargetStreamer::emitMask(unsigned CPUBitmask, int CPUTopSavedRegOff) {} +void MipsTargetStreamer::emitFMask(unsigned FPUBitmask, int FPUTopSavedRegOff) { +} +void MipsTargetStreamer::emitDirectiveSetMips32R2() {} +void MipsTargetStreamer::emitDirectiveSetMips64() {} +void MipsTargetStreamer::emitDirectiveSetMips64R2() {} +void MipsTargetStreamer::emitDirectiveSetDsp() {} +void MipsTargetStreamer::emitDirectiveCpload(unsigned RegNo) {} +void MipsTargetStreamer::emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, + const MCSymbol &Sym, bool IsReg) { +} +void MipsTargetStreamer::emitDirectiveModuleOddSPReg(bool Enabled, + bool IsO32ABI) { + if (!Enabled && !IsO32ABI) + report_fatal_error("+nooddspreg is only valid for O32"); +} MipsTargetAsmStreamer::MipsTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS) @@ -38,42 +71,52 @@ MipsTargetAsmStreamer::MipsTargetAsmStreamer(MCStreamer &S, void MipsTargetAsmStreamer::emitDirectiveSetMicroMips() { OS << "\t.set\tmicromips\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetNoMicroMips() { OS << "\t.set\tnomicromips\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetMips16() { OS << "\t.set\tmips16\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetNoMips16() { OS << "\t.set\tnomips16\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetReorder() { OS << "\t.set\treorder\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetNoReorder() { OS << "\t.set\tnoreorder\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetMacro() { OS << "\t.set\tmacro\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetNoMacro() { OS << "\t.set\tnomacro\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetAt() { OS << "\t.set\tat\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveSetNoAt() { OS << "\t.set\tnoat\n"; + setCanHaveModuleDir(false); } void MipsTargetAsmStreamer::emitDirectiveEnd(StringRef Name) { @@ -85,10 +128,21 @@ void MipsTargetAsmStreamer::emitDirectiveEnt(const MCSymbol &Symbol) { } void MipsTargetAsmStreamer::emitDirectiveAbiCalls() { OS << "\t.abicalls\n"; } + +void MipsTargetAsmStreamer::emitDirectiveNaN2008() { OS << "\t.nan\t2008\n"; } + +void MipsTargetAsmStreamer::emitDirectiveNaNLegacy() { + OS << "\t.nan\tlegacy\n"; +} + void MipsTargetAsmStreamer::emitDirectiveOptionPic0() { OS << "\t.option\tpic0\n"; } +void MipsTargetAsmStreamer::emitDirectiveOptionPic2() { + OS << "\t.option\tpic2\n"; +} + void MipsTargetAsmStreamer::emitFrame(unsigned StackReg, unsigned StackSize, unsigned ReturnReg) { OS << "\t.frame\t$" @@ -97,11 +151,30 @@ void MipsTargetAsmStreamer::emitFrame(unsigned StackReg, unsigned StackSize, << StringRef(MipsInstPrinter::getRegisterName(ReturnReg)).lower() << '\n'; } +void MipsTargetAsmStreamer::emitDirectiveSetMips32R2() { + OS << "\t.set\tmips32r2\n"; + setCanHaveModuleDir(false); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips64() { + OS << "\t.set\tmips64\n"; + setCanHaveModuleDir(false); +} + +void MipsTargetAsmStreamer::emitDirectiveSetMips64R2() { + OS << "\t.set\tmips64r2\n"; + setCanHaveModuleDir(false); +} + +void MipsTargetAsmStreamer::emitDirectiveSetDsp() { + OS << "\t.set\tdsp\n"; + setCanHaveModuleDir(false); +} // Print a 32 bit hex number with all numbers. static void printHex32(unsigned Value, raw_ostream &OS) { OS << "0x"; for (int i = 7; i >= 0; i--) - OS.write_hex((Value & (0xF << (i*4))) >> (i*4)); + OS.write_hex((Value & (0xF << (i * 4))) >> (i * 4)); } void MipsTargetAsmStreamer::emitMask(unsigned CPUBitmask, @@ -118,6 +191,58 @@ void MipsTargetAsmStreamer::emitFMask(unsigned FPUBitmask, OS << "," << FPUTopSavedRegOff << '\n'; } +void MipsTargetAsmStreamer::emitDirectiveCpload(unsigned RegNo) { + OS << "\t.cpload\t$" + << StringRef(MipsInstPrinter::getRegisterName(RegNo)).lower() << "\n"; + setCanHaveModuleDir(false); +} + +void MipsTargetAsmStreamer::emitDirectiveCpsetup(unsigned RegNo, + int RegOrOffset, + const MCSymbol &Sym, + bool IsReg) { + OS << "\t.cpsetup\t$" + << StringRef(MipsInstPrinter::getRegisterName(RegNo)).lower() << ", "; + + if (IsReg) + OS << "$" + << StringRef(MipsInstPrinter::getRegisterName(RegOrOffset)).lower(); + else + OS << RegOrOffset; + + OS << ", "; + + OS << Sym.getName() << "\n"; + setCanHaveModuleDir(false); +} + +void MipsTargetAsmStreamer::emitDirectiveModuleFP( + MipsABIFlagsSection::FpABIKind Value, bool Is32BitABI) { + MipsTargetStreamer::emitDirectiveModuleFP(Value, Is32BitABI); + + StringRef ModuleValue; + OS << "\t.module\tfp="; + OS << ABIFlagsSection.getFpABIString(Value) << "\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveSetFp( + MipsABIFlagsSection::FpABIKind Value) { + StringRef ModuleValue; + OS << "\t.set\tfp="; + OS << ABIFlagsSection.getFpABIString(Value) << "\n"; +} + +void MipsTargetAsmStreamer::emitMipsAbiFlags() { + // No action required for text output. +} + +void MipsTargetAsmStreamer::emitDirectiveModuleOddSPReg(bool Enabled, + bool IsO32ABI) { + MipsTargetStreamer::emitDirectiveModuleOddSPReg(Enabled, IsO32ABI); + + OS << "\t.module\t" << (Enabled ? "" : "no") << "oddspreg\n"; +} + // This part is for ELF object output. MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI) @@ -125,19 +250,36 @@ MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S, MCAssembler &MCA = getStreamer().getAssembler(); uint64_t Features = STI.getFeatureBits(); Triple T(STI.getTargetTriple()); + Pic = (MCA.getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_) + ? true + : false; // Update e_header flags unsigned EFlags = 0; // Architecture - if (Features & Mips::FeatureMips64r2) + if (Features & Mips::FeatureMips64r6) + EFlags |= ELF::EF_MIPS_ARCH_64R6; + else if (Features & Mips::FeatureMips64r2) EFlags |= ELF::EF_MIPS_ARCH_64R2; else if (Features & Mips::FeatureMips64) EFlags |= ELF::EF_MIPS_ARCH_64; + else if (Features & Mips::FeatureMips5) + EFlags |= ELF::EF_MIPS_ARCH_5; + else if (Features & Mips::FeatureMips4) + EFlags |= ELF::EF_MIPS_ARCH_4; + else if (Features & Mips::FeatureMips3) + EFlags |= ELF::EF_MIPS_ARCH_3; + else if (Features & Mips::FeatureMips32r6) + EFlags |= ELF::EF_MIPS_ARCH_32R6; else if (Features & Mips::FeatureMips32r2) EFlags |= ELF::EF_MIPS_ARCH_32R2; else if (Features & Mips::FeatureMips32) EFlags |= ELF::EF_MIPS_ARCH_32; + else if (Features & Mips::FeatureMips2) + EFlags |= ELF::EF_MIPS_ARCH_2; + else + EFlags |= ELF::EF_MIPS_ARCH_1; if (T.isArch64Bit()) { if (Features & Mips::FeatureN32) @@ -156,6 +298,16 @@ MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S, EFlags |= ELF::EF_MIPS_ABI_O32; } + // Other options. + if (Features & Mips::FeatureNaN2008) + EFlags |= ELF::EF_MIPS_NAN2008; + + // -mabicalls and -mplt are not implemented but we should act as if they were + // given. + EFlags |= ELF::EF_MIPS_CPIC; + if (Features & Mips::FeatureN64) + EFlags |= ELF::EF_MIPS_PIC; + MCA.setELFHeaderEFlags(EFlags); } @@ -177,30 +329,48 @@ void MipsTargetELFStreamer::finish() { MCAssembler &MCA = getStreamer().getAssembler(); MCContext &Context = MCA.getContext(); MCStreamer &OS = getStreamer(); + const MCObjectFileInfo &OFI = *Context.getObjectFileInfo(); Triple T(STI.getTargetTriple()); uint64_t Features = STI.getFeatureBits(); + // .bss, .text and .data are always at least 16-byte aligned. + MCSectionData &TextSectionData = + MCA.getOrCreateSectionData(*OFI.getTextSection()); + MCSectionData &DataSectionData = + MCA.getOrCreateSectionData(*OFI.getDataSection()); + MCSectionData &BSSSectionData = + MCA.getOrCreateSectionData(*OFI.getBSSSection()); + + TextSectionData.setAlignment(std::max(16u, TextSectionData.getAlignment())); + DataSectionData.setAlignment(std::max(16u, DataSectionData.getAlignment())); + BSSSectionData.setAlignment(std::max(16u, BSSSectionData.getAlignment())); + if (T.isArch64Bit() && (Features & Mips::FeatureN64)) { - const MCSectionELF *Sec = Context.getELFSection( - ".MIPS.options", ELF::SHT_MIPS_OPTIONS, - ELF::SHF_ALLOC | ELF::SHF_MIPS_NOSTRIP, SectionKind::getMetadata()); + // The EntrySize value of 1 seems strange since the records are neither + // 1-byte long nor fixed length but it matches the value GAS emits. + const MCSectionELF *Sec = + Context.getELFSection(".MIPS.options", ELF::SHT_MIPS_OPTIONS, + ELF::SHF_ALLOC | ELF::SHF_MIPS_NOSTRIP, + SectionKind::getMetadata(), 1, ""); + MCA.getOrCreateSectionData(*Sec).setAlignment(8); OS.SwitchSection(Sec); - OS.EmitIntValue(1, 1); // kind + OS.EmitIntValue(1, 1); // kind OS.EmitIntValue(40, 1); // size - OS.EmitIntValue(0, 2); // section - OS.EmitIntValue(0, 4); // info - OS.EmitIntValue(0, 4); // ri_gprmask - OS.EmitIntValue(0, 4); // pad - OS.EmitIntValue(0, 4); // ri_cpr[0]mask - OS.EmitIntValue(0, 4); // ri_cpr[1]mask - OS.EmitIntValue(0, 4); // ri_cpr[2]mask - OS.EmitIntValue(0, 4); // ri_cpr[3]mask - OS.EmitIntValue(0, 8); // ri_gp_value + OS.EmitIntValue(0, 2); // section + OS.EmitIntValue(0, 4); // info + OS.EmitIntValue(0, 4); // ri_gprmask + OS.EmitIntValue(0, 4); // pad + OS.EmitIntValue(0, 4); // ri_cpr[0]mask + OS.EmitIntValue(0, 4); // ri_cpr[1]mask + OS.EmitIntValue(0, 4); // ri_cpr[2]mask + OS.EmitIntValue(0, 4); // ri_cpr[3]mask + OS.EmitIntValue(0, 8); // ri_gp_value } else { const MCSectionELF *Sec = Context.getELFSection(".reginfo", ELF::SHT_MIPS_REGINFO, ELF::SHF_ALLOC, - SectionKind::getMetadata()); + SectionKind::getMetadata(), 24, ""); + MCA.getOrCreateSectionData(*Sec).setAlignment(4); OS.SwitchSection(Sec); OS.EmitIntValue(0, 4); // ri_gprmask @@ -210,6 +380,27 @@ void MipsTargetELFStreamer::finish() { OS.EmitIntValue(0, 4); // ri_cpr[3]mask OS.EmitIntValue(0, 4); // ri_gp_value } + emitMipsAbiFlags(); +} + +void MipsTargetELFStreamer::emitAssignment(MCSymbol *Symbol, + const MCExpr *Value) { + // If on rhs is micromips symbol then mark Symbol as microMips. + if (Value->getKind() != MCExpr::SymbolRef) + return; + const MCSymbol &RhsSym = + static_cast(Value)->getSymbol(); + MCSymbolData &Data = getStreamer().getOrCreateSymbolData(&RhsSym); + uint8_t Type = MCELF::GetType(Data); + if ((Type != ELF::STT_FUNC) || + !(MCELF::getOther(Data) & (ELF::STO_MIPS_MICROMIPS >> 2))) + return; + + MCSymbolData &SymbolData = getStreamer().getOrCreateSymbolData(Symbol); + // The "other" values are stored in the last 6 bits of the second byte. + // The traditional defines for STO values assume the full byte and thus + // the shift to pack it. + MCELF::setOther(SymbolData, ELF::STO_MIPS_MICROMIPS >> 2); } MCELFStreamer &MipsTargetELFStreamer::getStreamer() { @@ -227,6 +418,7 @@ void MipsTargetELFStreamer::emitDirectiveSetMicroMips() { void MipsTargetELFStreamer::emitDirectiveSetNoMicroMips() { MicroMipsEnabled = false; + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveSetMips16() { @@ -234,14 +426,17 @@ void MipsTargetELFStreamer::emitDirectiveSetMips16() { unsigned Flags = MCA.getELFHeaderEFlags(); Flags |= ELF::EF_MIPS_ARCH_ASE_M16; MCA.setELFHeaderEFlags(Flags); + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveSetNoMips16() { // FIXME: implement. + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveSetReorder() { // FIXME: implement. + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveSetNoReorder() { @@ -249,22 +444,27 @@ void MipsTargetELFStreamer::emitDirectiveSetNoReorder() { unsigned Flags = MCA.getELFHeaderEFlags(); Flags |= ELF::EF_MIPS_NOREORDER; MCA.setELFHeaderEFlags(Flags); + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveSetMacro() { // FIXME: implement. + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveSetNoMacro() { // FIXME: implement. + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveSetAt() { // FIXME: implement. + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveSetNoAt() { // FIXME: implement. + setCanHaveModuleDir(false); } void MipsTargetELFStreamer::emitDirectiveEnd(StringRef Name) { @@ -281,13 +481,42 @@ void MipsTargetELFStreamer::emitDirectiveAbiCalls() { Flags |= ELF::EF_MIPS_CPIC | ELF::EF_MIPS_PIC; MCA.setELFHeaderEFlags(Flags); } + +void MipsTargetELFStreamer::emitDirectiveNaN2008() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags |= ELF::EF_MIPS_NAN2008; + MCA.setELFHeaderEFlags(Flags); +} + +void MipsTargetELFStreamer::emitDirectiveNaNLegacy() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags &= ~ELF::EF_MIPS_NAN2008; + MCA.setELFHeaderEFlags(Flags); +} + void MipsTargetELFStreamer::emitDirectiveOptionPic0() { MCAssembler &MCA = getStreamer().getAssembler(); unsigned Flags = MCA.getELFHeaderEFlags(); + // This option overrides other PIC options like -KPIC. + Pic = false; Flags &= ~ELF::EF_MIPS_PIC; MCA.setELFHeaderEFlags(Flags); } +void MipsTargetELFStreamer::emitDirectiveOptionPic2() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Pic = true; + // NOTE: We are following the GAS behaviour here which means the directive + // 'pic2' also sets the CPIC bit in the ELF header. This is different from + // what is stated in the SYSV ABI which consider the bits EF_MIPS_PIC and + // EF_MIPS_CPIC to be mutually exclusive. + Flags |= ELF::EF_MIPS_PIC | ELF::EF_MIPS_CPIC; + MCA.setELFHeaderEFlags(Flags); +} + void MipsTargetELFStreamer::emitFrame(unsigned StackReg, unsigned StackSize, unsigned ReturnReg) { // FIXME: implement. @@ -302,3 +531,148 @@ void MipsTargetELFStreamer::emitFMask(unsigned FPUBitmask, int FPUTopSavedRegOff) { // FIXME: implement. } + +void MipsTargetELFStreamer::emitDirectiveSetMips32R2() { + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitDirectiveSetMips64() { + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitDirectiveSetMips64R2() { + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitDirectiveSetDsp() { + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitDirectiveCpload(unsigned RegNo) { + // .cpload $reg + // This directive expands to: + // lui $gp, %hi(_gp_disp) + // addui $gp, $gp, %lo(_gp_disp) + // addu $gp, $gp, $reg + // when support for position independent code is enabled. + if (!Pic || (isN32() || isN64())) + return; + + // There's a GNU extension controlled by -mno-shared that allows + // locally-binding symbols to be accessed using absolute addresses. + // This is currently not supported. When supported -mno-shared makes + // .cpload expand to: + // lui $gp, %hi(__gnu_local_gp) + // addiu $gp, $gp, %lo(__gnu_local_gp) + + StringRef SymName("_gp_disp"); + MCAssembler &MCA = getStreamer().getAssembler(); + MCSymbol *GP_Disp = MCA.getContext().GetOrCreateSymbol(SymName); + MCA.getOrCreateSymbolData(*GP_Disp); + + MCInst TmpInst; + TmpInst.setOpcode(Mips::LUi); + TmpInst.addOperand(MCOperand::CreateReg(Mips::GP)); + const MCSymbolRefExpr *HiSym = MCSymbolRefExpr::Create( + "_gp_disp", MCSymbolRefExpr::VK_Mips_ABS_HI, MCA.getContext()); + TmpInst.addOperand(MCOperand::CreateExpr(HiSym)); + getStreamer().EmitInstruction(TmpInst, STI); + + TmpInst.clear(); + + TmpInst.setOpcode(Mips::ADDiu); + TmpInst.addOperand(MCOperand::CreateReg(Mips::GP)); + TmpInst.addOperand(MCOperand::CreateReg(Mips::GP)); + const MCSymbolRefExpr *LoSym = MCSymbolRefExpr::Create( + "_gp_disp", MCSymbolRefExpr::VK_Mips_ABS_LO, MCA.getContext()); + TmpInst.addOperand(MCOperand::CreateExpr(LoSym)); + getStreamer().EmitInstruction(TmpInst, STI); + + TmpInst.clear(); + + TmpInst.setOpcode(Mips::ADDu); + TmpInst.addOperand(MCOperand::CreateReg(Mips::GP)); + TmpInst.addOperand(MCOperand::CreateReg(Mips::GP)); + TmpInst.addOperand(MCOperand::CreateReg(RegNo)); + getStreamer().EmitInstruction(TmpInst, STI); + + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo, + int RegOrOffset, + const MCSymbol &Sym, + bool IsReg) { + // Only N32 and N64 emit anything for .cpsetup iff PIC is set. + if (!Pic || !(isN32() || isN64())) + return; + + MCAssembler &MCA = getStreamer().getAssembler(); + MCInst Inst; + + // Either store the old $gp in a register or on the stack + if (IsReg) { + // move $save, $gpreg + Inst.setOpcode(Mips::DADDu); + Inst.addOperand(MCOperand::CreateReg(RegOrOffset)); + Inst.addOperand(MCOperand::CreateReg(Mips::GP)); + Inst.addOperand(MCOperand::CreateReg(Mips::ZERO)); + } else { + // sd $gpreg, offset($sp) + Inst.setOpcode(Mips::SD); + Inst.addOperand(MCOperand::CreateReg(Mips::GP)); + Inst.addOperand(MCOperand::CreateReg(Mips::SP)); + Inst.addOperand(MCOperand::CreateImm(RegOrOffset)); + } + getStreamer().EmitInstruction(Inst, STI); + Inst.clear(); + + const MCSymbolRefExpr *HiExpr = MCSymbolRefExpr::Create( + Sym.getName(), MCSymbolRefExpr::VK_Mips_GPOFF_HI, MCA.getContext()); + const MCSymbolRefExpr *LoExpr = MCSymbolRefExpr::Create( + Sym.getName(), MCSymbolRefExpr::VK_Mips_GPOFF_LO, MCA.getContext()); + // lui $gp, %hi(%neg(%gp_rel(funcSym))) + Inst.setOpcode(Mips::LUi); + Inst.addOperand(MCOperand::CreateReg(Mips::GP)); + Inst.addOperand(MCOperand::CreateExpr(HiExpr)); + getStreamer().EmitInstruction(Inst, STI); + Inst.clear(); + + // addiu $gp, $gp, %lo(%neg(%gp_rel(funcSym))) + Inst.setOpcode(Mips::ADDiu); + Inst.addOperand(MCOperand::CreateReg(Mips::GP)); + Inst.addOperand(MCOperand::CreateReg(Mips::GP)); + Inst.addOperand(MCOperand::CreateExpr(LoExpr)); + getStreamer().EmitInstruction(Inst, STI); + Inst.clear(); + + // daddu $gp, $gp, $funcreg + Inst.setOpcode(Mips::DADDu); + Inst.addOperand(MCOperand::CreateReg(Mips::GP)); + Inst.addOperand(MCOperand::CreateReg(Mips::GP)); + Inst.addOperand(MCOperand::CreateReg(RegNo)); + getStreamer().EmitInstruction(Inst, STI); + + setCanHaveModuleDir(false); +} + +void MipsTargetELFStreamer::emitMipsAbiFlags() { + MCAssembler &MCA = getStreamer().getAssembler(); + MCContext &Context = MCA.getContext(); + MCStreamer &OS = getStreamer(); + const MCSectionELF *Sec = + Context.getELFSection(".MIPS.abiflags", ELF::SHT_MIPS_ABIFLAGS, + ELF::SHF_ALLOC, SectionKind::getMetadata(), 24, ""); + MCSectionData &ABIShndxSD = MCA.getOrCreateSectionData(*Sec); + ABIShndxSD.setAlignment(8); + OS.SwitchSection(Sec); + + OS << ABIFlagsSection; +} + +void MipsTargetELFStreamer::emitDirectiveModuleOddSPReg(bool Enabled, + bool IsO32ABI) { + MipsTargetStreamer::emitDirectiveModuleOddSPReg(Enabled, IsO32ABI); + + ABIFlagsSection.OddSPReg = Enabled; +}