1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-20 19:42:54 +02:00
llvm-mirror/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
Daniel Sanders aa92e911ca [mips] Add support for -modd-spreg/-mno-odd-spreg
Summary:
When -mno-odd-spreg is in effect, 32-bit floating point values are not
permitted in odd FPU registers. The option also prohibits 32-bit and 64-bit
floating point comparison results from being written to odd registers.

This option has three purposes:
* It allows support for certain MIPS implementations such as loongson-3a that
  do not allow the use of odd registers for single precision arithmetic.
* When using -mfpxx, -mno-odd-spreg is the default and this allows us to
  statically check that code is compliant with the O32 FPXX ABI since mtc1/mfc1
  instructions to/from odd registers are guaranteed not to appear for any
  reason. Once this has been established, the user can then re-enable
  -modd-spreg to regain the use of all 32 single-precision registers.
* When using -mfp64 and -mno-odd-spreg together, an O32 extension named
  O32 FP64A is used as the ABI. This is intended to provide almost all
  functionality of an FR=1 processor but can also be executed on a FR=0 core
  with the assistance of a hardware compatibility mode which emulates FR=0
  behaviour on an FR=1 processor.

* Added '.module oddspreg' and '.module nooddspreg' each of which update
  the .MIPS.abiflags section appropriately
* Moved setFpABI() call inside emitDirectiveModuleFP() so that the caller
  doesn't have to remember to do it.
* MipsABIFlags now calculates the flags1 and flags2 member on demand rather
  than trying to maintain them in the same format they will be emitted in.

There is one portion of the -mfp64 and -mno-odd-spreg combination that is not
implemented yet. Moves to/from odd-numbered double-precision registers must not
use mtc1. I will fix this in a follow-up.

Differential Revision: http://reviews.llvm.org/D4383

llvm-svn: 212717
2014-07-10 13:38:23 +00:00

655 lines
21 KiB
C++

//===-- MipsTargetStreamer.cpp - Mips Target Streamer Methods -------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides Mips specific target streamer methods.
//
//===----------------------------------------------------------------------===//
#include "InstPrinter/MipsInstPrinter.h"
#include "MipsMCTargetDesc.h"
#include "MipsTargetObjectFile.h"
#include "MipsTargetStreamer.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCELF.h"
#include "llvm/MC/MCSectionELF.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"
#include "llvm/Support/FormattedStream.h"
using namespace llvm;
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)
: MipsTargetStreamer(S), OS(OS) {}
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) {
OS << "\t.end\t" << Name << '\n';
}
void MipsTargetAsmStreamer::emitDirectiveEnt(const MCSymbol &Symbol) {
OS << "\t.ent\t" << Symbol.getName() << '\n';
}
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$"
<< StringRef(MipsInstPrinter::getRegisterName(StackReg)).lower() << ","
<< 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));
}
void MipsTargetAsmStreamer::emitMask(unsigned CPUBitmask,
int CPUTopSavedRegOff) {
OS << "\t.mask \t";
printHex32(CPUBitmask, OS);
OS << ',' << CPUTopSavedRegOff << '\n';
}
void MipsTargetAsmStreamer::emitFMask(unsigned FPUBitmask,
int FPUTopSavedRegOff) {
OS << "\t.fmask\t";
printHex32(FPUBitmask, OS);
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)
: MipsTargetStreamer(S), MicroMipsEnabled(false), STI(STI) {
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::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)
EFlags |= ELF::EF_MIPS_ABI2;
else if (Features & Mips::FeatureO32) {
EFlags |= ELF::EF_MIPS_ABI_O32;
EFlags |= ELF::EF_MIPS_32BITMODE; /* Compatibility Mode */
}
// No need to set any bit for N64 which is the default ABI at the moment
// for 64-bit Mips architectures.
} else {
if (Features & Mips::FeatureMips64r2 || Features & Mips::FeatureMips64)
EFlags |= ELF::EF_MIPS_32BITMODE;
// ABI
EFlags |= ELF::EF_MIPS_ABI_O32;
}
// Other options.
if (Features & Mips::FeatureNaN2008)
EFlags |= ELF::EF_MIPS_NAN2008;
MCA.setELFHeaderEFlags(EFlags);
}
void MipsTargetELFStreamer::emitLabel(MCSymbol *Symbol) {
if (!isMicroMipsEnabled())
return;
MCSymbolData &Data = getStreamer().getOrCreateSymbolData(Symbol);
uint8_t Type = MCELF::GetType(Data);
if (Type != ELF::STT_FUNC)
return;
// 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(Data, ELF::STO_MIPS_MICROMIPS >> 2);
}
void MipsTargetELFStreamer::finish() {
MCAssembler &MCA = getStreamer().getAssembler();
MCContext &Context = MCA.getContext();
MCStreamer &OS = getStreamer();
Triple T(STI.getTargetTriple());
uint64_t Features = STI.getFeatureBits();
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());
OS.SwitchSection(Sec);
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
} else {
const MCSectionELF *Sec =
Context.getELFSection(".reginfo", ELF::SHT_MIPS_REGINFO, ELF::SHF_ALLOC,
SectionKind::getMetadata());
OS.SwitchSection(Sec);
OS.EmitIntValue(0, 4); // ri_gprmask
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, 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<const MCSymbolRefExpr *>(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() {
return static_cast<MCELFStreamer &>(Streamer);
}
void MipsTargetELFStreamer::emitDirectiveSetMicroMips() {
MicroMipsEnabled = true;
MCAssembler &MCA = getStreamer().getAssembler();
unsigned Flags = MCA.getELFHeaderEFlags();
Flags |= ELF::EF_MIPS_MICROMIPS;
MCA.setELFHeaderEFlags(Flags);
}
void MipsTargetELFStreamer::emitDirectiveSetNoMicroMips() {
MicroMipsEnabled = false;
setCanHaveModuleDir(false);
}
void MipsTargetELFStreamer::emitDirectiveSetMips16() {
MCAssembler &MCA = getStreamer().getAssembler();
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() {
MCAssembler &MCA = getStreamer().getAssembler();
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) {
// FIXME: implement.
}
void MipsTargetELFStreamer::emitDirectiveEnt(const MCSymbol &Symbol) {
// FIXME: implement.
}
void MipsTargetELFStreamer::emitDirectiveAbiCalls() {
MCAssembler &MCA = getStreamer().getAssembler();
unsigned Flags = MCA.getELFHeaderEFlags();
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.
}
void MipsTargetELFStreamer::emitMask(unsigned CPUBitmask,
int CPUTopSavedRegOff) {
// FIXME: implement.
}
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());
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;
}