233 changes: 189 additions & 44 deletions llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp

Large diffs are not rendered by default.

145 changes: 125 additions & 20 deletions llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@

using namespace llvm;

MipsTargetStreamer::MipsTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {}
MipsTargetStreamer::MipsTargetStreamer(MCStreamer &S)
: MCTargetStreamer(S), canHaveModuleDirective(true) {}
void MipsTargetStreamer::emitDirectiveSetMicroMips() {}
void MipsTargetStreamer::emitDirectiveSetNoMicroMips() {}
void MipsTargetStreamer::emitDirectiveSetMips16() {}
Expand Down Expand Up @@ -65,42 +66,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) {
Expand Down Expand Up @@ -137,24 +148,28 @@ void MipsTargetAsmStreamer::emitFrame(unsigned StackReg, unsigned StackSize,

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,
Expand All @@ -174,6 +189,7 @@ void MipsTargetAsmStreamer::emitFMask(unsigned FPUBitmask,
void MipsTargetAsmStreamer::emitDirectiveCpload(unsigned RegNo) {
OS << "\t.cpload\t$"
<< StringRef(MipsInstPrinter::getRegisterName(RegNo)).lower() << "\n";
setCanHaveModuleDir(false);
}

void MipsTargetAsmStreamer::emitDirectiveCpsetup(unsigned RegNo,
Expand All @@ -192,6 +208,57 @@ void MipsTargetAsmStreamer::emitDirectiveCpsetup(unsigned RegNo,
OS << ", ";

OS << Sym.getName() << "\n";
setCanHaveModuleDir(false);
}

void MipsTargetAsmStreamer::emitDirectiveModule(unsigned Value,
bool is32BitAbi) {
StringRef ModuleValue;
OS << "\t.module\tfp=";
switch (Value) {
case Val_GNU_MIPS_ABI_FP_XX:
ModuleValue = "xx";
break;
case Val_GNU_MIPS_ABI_FP_64:
ModuleValue = "64";
break;
case Val_GNU_MIPS_ABI_FP_DOUBLE:
if (is32BitAbi)
ModuleValue = "32";
else
ModuleValue = "64";
break;
default:
llvm_unreachable("unsupported .module value");
}
OS << ModuleValue << "\n";
}

void MipsTargetAsmStreamer::emitDirectiveSetFp(unsigned Value,
bool is32BitAbi) {
StringRef ModuleValue;
OS << "\t.set\tfp=";
switch (Value) {
case Val_GNU_MIPS_ABI_FP_XX:
ModuleValue = "xx";
break;
case Val_GNU_MIPS_ABI_FP_64:
ModuleValue = "64";
break;
case Val_GNU_MIPS_ABI_FP_DOUBLE:
if (is32BitAbi)
ModuleValue = "32";
else
ModuleValue = "64";
break;
default:
llvm_unreachable("unsupported .set fp value");
}
OS << ModuleValue << "\n";
}

void MipsTargetAsmStreamer::emitMipsAbiFlags() {
// No action required for text output.
}

// This part is for ELF object output.
Expand All @@ -201,7 +268,7 @@ MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S,
MCAssembler &MCA = getStreamer().getAssembler();
uint64_t Features = STI.getFeatureBits();
Triple T(STI.getTargetTriple());
Pic = (MCA.getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_)
Pic = (MCA.getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_)
? true
: false;

Expand Down Expand Up @@ -283,17 +350,17 @@ void MipsTargetELFStreamer::finish() {
ELF::SHF_ALLOC | ELF::SHF_MIPS_NOSTRIP, SectionKind::getMetadata());
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,
Expand All @@ -307,6 +374,7 @@ void MipsTargetELFStreamer::finish() {
OS.EmitIntValue(0, 4); // ri_cpr[3]mask
OS.EmitIntValue(0, 4); // ri_gp_value
}
emitMipsAbiFlags();
}

void MipsTargetELFStreamer::emitAssignment(MCSymbol *Symbol,
Expand All @@ -315,11 +383,11 @@ void MipsTargetELFStreamer::emitAssignment(MCSymbol *Symbol,
if (Value->getKind() != MCExpr::SymbolRef)
return;
const MCSymbol &RhsSym =
static_cast<const MCSymbolRefExpr *>(Value)->getSymbol();
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)))
if ((Type != ELF::STT_FUNC) ||
!(MCELF::getOther(Data) & (ELF::STO_MIPS_MICROMIPS >> 2)))
return;

MCSymbolData &SymbolData = getStreamer().getOrCreateSymbolData(Symbol);
Expand All @@ -344,44 +412,53 @@ void MipsTargetELFStreamer::emitDirectiveSetMicroMips() {

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) {
Expand Down Expand Up @@ -450,19 +527,19 @@ void MipsTargetELFStreamer::emitFMask(unsigned FPUBitmask,
}

void MipsTargetELFStreamer::emitDirectiveSetMips32R2() {
// No action required for ELF output.
setCanHaveModuleDir(false);
}

void MipsTargetELFStreamer::emitDirectiveSetMips64() {
// No action required for ELF output.
setCanHaveModuleDir(false);
}

void MipsTargetELFStreamer::emitDirectiveSetMips64R2() {
// No action required for ELF output.
setCanHaveModuleDir(false);
}

void MipsTargetELFStreamer::emitDirectiveSetDsp() {
// No action required for ELF output.
setCanHaveModuleDir(false);
}

void MipsTargetELFStreamer::emitDirectiveCpload(unsigned RegNo) {
Expand Down Expand Up @@ -512,6 +589,8 @@ void MipsTargetELFStreamer::emitDirectiveCpload(unsigned RegNo) {
TmpInst.addOperand(MCOperand::CreateReg(Mips::GP));
TmpInst.addOperand(MCOperand::CreateReg(RegNo));
getStreamer().EmitInstruction(TmpInst, STI);

setCanHaveModuleDir(false);
}

void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo,
Expand Down Expand Up @@ -567,4 +646,30 @@ void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo,
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.EmitIntValue(MipsABIFlags.version, 2); // version
OS.EmitIntValue(MipsABIFlags.isa_level, 1); // isa_level
OS.EmitIntValue(MipsABIFlags.isa_rev, 1); // isa_rev
OS.EmitIntValue(MipsABIFlags.gpr_size, 1); // gpr_size
OS.EmitIntValue(MipsABIFlags.cpr1_size, 1); // cpr1_size
OS.EmitIntValue(MipsABIFlags.cpr2_size, 1); // cpr2_size
OS.EmitIntValue(MipsABIFlags.fp_abi, 1); // fp_abi
OS.EmitIntValue(MipsABIFlags.isa_ext, 4); // isa_ext
OS.EmitIntValue(MipsABIFlags.ases, 4); // ases
OS.EmitIntValue(MipsABIFlags.flags1, 4); // flags1
OS.EmitIntValue(MipsABIFlags.flags2, 4); // flags2
}
17 changes: 16 additions & 1 deletion llvm/lib/Target/Mips/MipsAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ bool MipsAsmPrinter::lowerOperand(const MachineOperand &MO, MCOperand &MCOp) {
#include "MipsGenMCPseudoLowering.inc"

void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) {
MipsTargetStreamer &TS = getTargetStreamer();
TS.setCanHaveModuleDir(false);
if (MI->isDebugValue()) {
SmallString<128> Str;
raw_svector_ostream OS(Str);
Expand Down Expand Up @@ -657,6 +659,19 @@ void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) {
OutContext.getELFSection(".gcc_compiled_long64", ELF::SHT_PROGBITS, 0,
SectionKind::getDataRel()));
}
getTargetStreamer().updateABIInfo(*Subtarget);
unsigned FpAbiVal;
if (Subtarget->isABI_N32() || Subtarget->isABI_N64())
FpAbiVal = Val_GNU_MIPS_ABI_FP_DOUBLE;
else if(Subtarget->isABI_O32()) {
if (Subtarget->isFP64bit())
FpAbiVal = Val_GNU_MIPS_ABI_FP_64;
else if(Subtarget->isABI_FPXX())
FpAbiVal = Val_GNU_MIPS_ABI_FP_XX;
else
FpAbiVal = Val_GNU_MIPS_ABI_FP_DOUBLE;
}
getTargetStreamer().emitDirectiveModule(FpAbiVal, Subtarget->isABI_O32());
}

void MipsAsmPrinter::EmitJal(MCSymbol *Symbol) {
Expand Down Expand Up @@ -852,7 +867,7 @@ void MipsAsmPrinter::EmitFPCallStub(
TS.emitDirectiveSetNoMicroMips();
//
// .ent __call_stub_fp_xxxx
// .type __call_stub_fp_xxxx,@function
// .type __call_stub_fp_xxxx,@function
// __call_stub_fp_xxxx:
//
std::string x = "__call_stub_fp_" + std::string(Symbol);
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/Mips/MipsSubtarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ class MipsSubtarget : public MipsGenSubtargetInfo {
bool isABI_N64() const { return MipsABI == N64; }
bool isABI_N32() const { return MipsABI == N32; }
bool isABI_O32() const { return MipsABI == O32; }
bool isABI_FPXX() const { return false; } // TODO: add check for FPXX
unsigned getTargetABI() const { return MipsABI; }

/// This constructor initializes the data members to match that
Expand All @@ -174,8 +175,11 @@ class MipsSubtarget : public MipsGenSubtargetInfo {
/// subtarget options. Definition of function is auto generated by tblgen.
void ParseSubtargetFeatures(StringRef CPU, StringRef FS);

bool hasMips1() const { return MipsArchVersion >= Mips1; }
bool hasMips2() const { return MipsArchVersion >= Mips2; }
bool hasMips3() const { return MipsArchVersion >= Mips3; }
bool hasMips4() const { return MipsArchVersion >= Mips4; }
bool hasMips5() const { return MipsArchVersion >= Mips5; }
bool hasMips4_32() const { return HasMips4_32; }
bool hasMips4_32r2() const { return HasMips4_32r2; }
bool hasMips32() const {
Expand Down
193 changes: 193 additions & 0 deletions llvm/lib/Target/Mips/MipsTargetStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,88 @@
#include "llvm/MC/MCStreamer.h"

namespace llvm {
struct Elf_Internal_ABIFlags_v0 {
// Version of flags structure.
uint16_t version;
// The level of the ISA: 1-5, 32, 64.
uint8_t isa_level;
// The revision of ISA: 0 for MIPS V and below, 1-n otherwise.
uint8_t isa_rev;
// The size of general purpose registers.
uint8_t gpr_size;
// The size of co-processor 1 registers.
uint8_t cpr1_size;
// The size of co-processor 2 registers.
uint8_t cpr2_size;
// The floating-point ABI.
uint8_t fp_abi;
// Processor-specific extension.
uint32_t isa_ext;
// Mask of ASEs used.
uint32_t ases;
// Mask of general flags.
uint32_t flags1;
uint32_t flags2;

Elf_Internal_ABIFlags_v0()
: version(0), isa_level(0), isa_rev(0), gpr_size(0), cpr1_size(0),
cpr2_size(0), fp_abi(0), isa_ext(0), ases(0), flags1(0), flags2(0) {}
};

// Values for the xxx_size bytes of an ABI flags structure.
enum {
AFL_REG_NONE = 0x00, // No registers.
AFL_REG_32 = 0x01, // 32-bit registers.
AFL_REG_64 = 0x02, // 64-bit registers.
AFL_REG_128 = 0x03 // 128-bit registers.
};

// Masks for the ases word of an ABI flags structure.
enum {
AFL_ASE_DSP = 0x00000001, // DSP ASE.
AFL_ASE_DSPR2 = 0x00000002, // DSP R2 ASE.
AFL_ASE_EVA = 0x00000004, // Enhanced VA Scheme.
AFL_ASE_MCU = 0x00000008, // MCU (MicroController) ASE.
AFL_ASE_MDMX = 0x00000010, // MDMX ASE.
AFL_ASE_MIPS3D = 0x00000020, // MIPS-3D ASE.
AFL_ASE_MT = 0x00000040, // MT ASE.
AFL_ASE_SMARTMIPS = 0x00000080, // SmartMIPS ASE.
AFL_ASE_VIRT = 0x00000100, // VZ ASE.
AFL_ASE_MSA = 0x00000200, // MSA ASE.
AFL_ASE_MIPS16 = 0x00000400, // MIPS16 ASE.
AFL_ASE_MICROMIPS = 0x00000800, // MICROMIPS ASE.
AFL_ASE_XPA = 0x00001000 // XPA ASE.
};

// Values for the isa_ext word of an ABI flags structure.
enum {
AFL_EXT_XLR = 1, // RMI Xlr instruction.
AFL_EXT_OCTEON2 = 2, // Cavium Networks Octeon2.
AFL_EXT_OCTEONP = 3, // Cavium Networks OcteonP.
AFL_EXT_LOONGSON_3A = 4, // Loongson 3A.
AFL_EXT_OCTEON = 5, // Cavium Networks Octeon.
AFL_EXT_5900 = 6, // MIPS R5900 instruction.
AFL_EXT_4650 = 7, // MIPS R4650 instruction.
AFL_EXT_4010 = 8, // LSI R4010 instruction.
AFL_EXT_4100 = 9, // NEC VR4100 instruction.
AFL_EXT_3900 = 10, // Toshiba R3900 instruction.
AFL_EXT_10000 = 11, // MIPS R10000 instruction.
AFL_EXT_SB1 = 12, // Broadcom SB-1 instruction.
AFL_EXT_4111 = 13, // NEC VR4111/VR4181 instruction.
AFL_EXT_4120 = 14, // NEC VR4120 instruction.
AFL_EXT_5400 = 15, // NEC VR5400 instruction.
AFL_EXT_5500 = 16, // NEC VR5500 instruction.
AFL_EXT_LOONGSON_2E = 17, // ST Microelectronics Loongson 2E.
AFL_EXT_LOONGSON_2F = 18 // ST Microelectronics Loongson 2F.
};

// Values for the fp_abi word of an ABI flags structure.
enum {
Val_GNU_MIPS_ABI_FP_DOUBLE = 1,
Val_GNU_MIPS_ABI_FP_XX = 5,
Val_GNU_MIPS_ABI_FP_64 = 6
};

class MipsTargetStreamer : public MCTargetStreamer {
public:
MipsTargetStreamer(MCStreamer &S);
Expand Down Expand Up @@ -50,6 +132,109 @@ class MipsTargetStreamer : public MCTargetStreamer {
virtual void emitDirectiveCpload(unsigned RegNo);
virtual void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset,
const MCSymbol &Sym, bool IsReg);
// ABI Flags
virtual void emitDirectiveModule(unsigned Value, bool is32BitAbi){};
virtual void emitDirectiveSetFp(unsigned Value, bool is32BitAbi){};
virtual void emitMipsAbiFlags(){};
void setCanHaveModuleDir(bool Can) { canHaveModuleDirective = Can; }
bool getCanHaveModuleDir() { return canHaveModuleDirective; }

void setVersion(uint16_t Version) { MipsABIFlags.version = Version; }
void setISALevel(uint8_t Level) { MipsABIFlags.isa_level = Level; }
void setISARev(uint8_t Rev) { MipsABIFlags.isa_rev = Rev; }
void setGprSize(uint8_t Size) { MipsABIFlags.gpr_size = Size; }
void setCpr1Size(uint8_t Size) { MipsABIFlags.cpr1_size = Size; }
void setCpr2Size(uint8_t Size) { MipsABIFlags.cpr2_size = Size; }
void setFpABI(uint8_t Abi) { MipsABIFlags.fp_abi = Abi; }
void setIsaExt(uint32_t IsaExt) { MipsABIFlags.isa_ext = IsaExt; }
void setASEs(uint32_t Ases) { MipsABIFlags.ases = Ases; }
void setFlags1(uint32_t Flags) { MipsABIFlags.flags1 = Flags; }
void setFlags2(uint32_t Flags) { MipsABIFlags.flags2 = Flags; }

uint8_t getFPAbi() { return MipsABIFlags.fp_abi; }
// This method enables template classes to set internal abi flags
// structure values.
template <class PredicateLibrary>
void updateABIInfo(const PredicateLibrary &P) {
setVersion(0); // Version, default value is 0.

if (P.hasMips64()) { // isa_level
setISALevel(64);
if (P.hasMips64r6())
setISARev(6);
else if (P.hasMips64r2())
setISARev(2);
else
setISARev(1);
} else if (P.hasMips32()) {
setISALevel(32);
if (P.hasMips32r6())
setISARev(6);
else if (P.hasMips32r2())
setISARev(2);
else
setISARev(1);
} else {
setISARev(0);
if (P.hasMips5())
setISALevel(5);
else if (P.hasMips4())
setISALevel(4);
else if (P.hasMips3())
setISALevel(3);
else if (P.hasMips2())
setISALevel(2);
else if (P.hasMips1())
setISALevel(1);
else
llvm_unreachable("Unknown ISA level!");
}

if (P.isGP64bit()) // GPR size.
setGprSize(AFL_REG_64);
else
setGprSize(AFL_REG_32);

// TODO: check for MSA128 value.
if (P.mipsSEUsesSoftFloat())
setCpr1Size(AFL_REG_NONE);
else if (P.isFP64bit())
setCpr1Size(AFL_REG_64);
else
setCpr1Size(AFL_REG_32);
setCpr2Size(AFL_REG_NONE); // Default value.

// Set ASE.
unsigned AseFlags = 0;
if (P.hasDSP())
AseFlags |= AFL_ASE_DSP;
if (P.hasDSPR2())
AseFlags |= AFL_ASE_DSPR2;
if (P.hasMSA())
AseFlags |= AFL_ASE_MSA;
if (P.inMicroMipsMode())
AseFlags |= AFL_ASE_MICROMIPS;
if (P.inMips16Mode())
AseFlags |= AFL_ASE_MIPS16;

if (P.isABI_N32() || P.isABI_N64())
setFpABI(Val_GNU_MIPS_ABI_FP_DOUBLE);
else if (P.isABI_O32()) {
if (P.isFP64bit())
setFpABI(Val_GNU_MIPS_ABI_FP_64);
else if (P.isABI_FPXX())
setFpABI(Val_GNU_MIPS_ABI_FP_XX);
else
setFpABI(Val_GNU_MIPS_ABI_FP_DOUBLE);
} else
setFpABI(0); // Default value.
}

protected:
Elf_Internal_ABIFlags_v0 MipsABIFlags;

private:
bool canHaveModuleDirective;
};

// This part is for ascii assembly output
Expand Down Expand Up @@ -91,6 +276,11 @@ class MipsTargetAsmStreamer : public MipsTargetStreamer {
virtual void emitDirectiveCpload(unsigned RegNo);
void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset,
const MCSymbol &Sym, bool IsReg) override;

// ABI Flags
void emitDirectiveModule(unsigned Value, bool is32BitAbi) override;
void emitDirectiveSetFp(unsigned Value, bool is32BitAbi) override;
void emitMipsAbiFlags() override;
};

// This part is for ELF object output
Expand Down Expand Up @@ -142,6 +332,9 @@ class MipsTargetELFStreamer : public MipsTargetStreamer {
void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset,
const MCSymbol &Sym, bool IsReg) override;

// ABI Flags
void emitMipsAbiFlags() override;

protected:
bool isO32() const { return STI.getFeatureBits() & Mips::FeatureO32; }
bool isN32() const { return STI.getFeatureBits() & Mips::FeatureN32; }
Expand Down
6 changes: 6 additions & 0 deletions llvm/test/CodeGen/Mips/abiflags-xx.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
; RUN: llc -filetype=asm -mtriple mipsel-unknown-linux -mcpu=mips32 -mattr=fpxx %s -o - | FileCheck %s
; XFAIL: *

; CHECK: .nan legacy
; CHECK: .module fp=xx

12 changes: 12 additions & 0 deletions llvm/test/CodeGen/Mips/abiflags32.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
; RUN: llc -filetype=asm -mtriple mipsel-unknown-linux -mcpu=mips32 %s -o - | FileCheck %s
; RUN: llc -filetype=asm -mtriple mipsel-unknown-linux -mcpu=mips32 -mattr=fp64 %s -o - | FileCheck -check-prefix=CHECK-64 %s
; RUN: llc -filetype=asm -mtriple mipsel-unknown-linux -mcpu=mips64 -mattr=-n64,n32 %s -o - | FileCheck -check-prefix=CHECK-64n %s

; CHECK: .nan legacy
; CHECK: .module fp=32

; CHECK-64: .nan legacy
; CHECK-64: .module fp=64

; CHECK-64n: .nan legacy
; CHECK-64n: .module fp=64
20 changes: 20 additions & 0 deletions llvm/test/MC/Mips/mips-abi-bad.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Error checking for malformed abi related directives
# RUN: not llvm-mc -triple mips-unknown-unknown %s 2>&1 | FileCheck %s
# CHECK: .text
.module fp=3
# CHECK : mips-abi-bad.s:4:16: error: unsupported option
# CHECK-NEXT : .module fp=3
# CHECK-NEXT : ^

.set fp=xx,6
# CHECK :mips-abi-bad.s:5:15: error: unexpected token in statement
# CHECK-NEXT : .set fp=xx,6
# CHECK-NEXT : ^

# CHECK :.set mips16
.set mips16
.module fp=32

# CHECK :mips-abi-bad.s:14:13: error: .module directive must come before any code
# CHECK-NEXT : .module fp=32
# CHECK-NEXT : ^
4 changes: 2 additions & 2 deletions llvm/test/MC/Mips/mips-data-directives.s
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@

# Checking if the data and reloations were correctly emitted
# CHECK-OBJ: Section {
# CHECK-OBJ: Name: .data (51)
# CHECK-OBJ: Name: .data (66)
# CHECK-OBJ: SectionData (
# CHECK-OBJ: 0000: DEADC0DE DEADC0DE DEADBEEF 00000000
# CHECK-OBJ: 0010: 00000000 00000000
# CHECK-OBJ: )
# CHECK-OBJ: }

# CHECK-OBJ: Section {
# CHECK-OBJ: Name: .rel.data (47)
# CHECK-OBJ: Name: .rel.data (62)
# CHECK-OBJ: Relocations [
# CHECK-OBJ: 0xC R_MIPS_32 .data 0x0
# CHECK-OBJ: 0x10 R_MIPS_64 .data 0x0
Expand Down
37 changes: 37 additions & 0 deletions llvm/test/MC/Mips/mips32/abiflags.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# RUN: llvm-mc %s -arch=mips -mcpu=mips32 | \
# RUN: FileCheck %s -check-prefix=CHECK-ASM
#
# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -filetype=obj -o - | \
# RUN: llvm-readobj -sections -section-data -section-relocations - | \
# RUN: FileCheck %s -check-prefix=CHECK-OBJ

# CHECK-ASM: .module fp=32

# Checking if the Mips.abiflags were correctly emitted.
# CHECK-OBJ: Section {
# CHECK-OBJ: Index: 5
# CHECK-OBJ: Name: .MIPS.abiflags (12)
# CHECK-OBJ: Type: (0x7000002A)
# CHECK-OBJ: Flags [ (0x2)
# CHECK-OBJ: SHF_ALLOC (0x2)
# CHECK-OBJ: ]
# CHECK-OBJ: Address: 0x0
# CHECK-OBJ: Offset: 0x50
# CHECK-OBJ: Size: 24
# CHECK-OBJ: Link: 0
# CHECK-OBJ: Info: 0
# CHECK-OBJ: AddressAlignment: 8
# CHECK-OBJ: EntrySize: 0
# CHECK-OBJ: Relocations [
# CHECK-OBJ: ]
# CHECK-OBJ: SectionData (
# CHECK-OBJ: 0000: 00002001 01010001 00000000 00000000 |.. .............|
# CHECK-OBJ: 0010: 00000000 00000000 |........|
# CHECK-OBJ: )
# CHECK-OBJ: }

.module fp=32

# FIXME: Test should include gnu_attributes directive when implemented.
# An explicit .gnu_attribute must be checked against the effective
# command line options and any inconsistencies reported via a warning.
38 changes: 38 additions & 0 deletions llvm/test/MC/Mips/mips32r2/abiflags.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# RUN: llvm-mc %s -arch=mips -mcpu=mips32r2 | \
# RUN: FileCheck %s -check-prefix=CHECK-ASM
#
# RUN: llvm-mc %s -arch=mips -mcpu=mips32r2 -filetype=obj -o - | \
# RUN: llvm-readobj -sections -section-data -section-relocations - | \
# RUN: FileCheck %s -check-prefix=CHECK-OBJ

# CHECK-ASM: .module fp=32
# CHECK-ASM: .set fp=64

# Checking if the Mips.abiflags were correctly emitted.
# CHECK-OBJ: Section {
# CHECK-OBJ: Index: 5
# CHECK-OBJ: Name: .MIPS.abiflags (12)
# CHECK-OBJ: Type: (0x7000002A)
# CHECK-OBJ: Flags [ (0x2)
# CHECK-OBJ: SHF_ALLOC (0x2)
# CHECK-OBJ: ]
# CHECK-OBJ: Address: 0x0
# CHECK-OBJ: Offset: 0x50
# CHECK-OBJ: Size: 24
# CHECK-OBJ: Link: 0
# CHECK-OBJ: Info: 0
# CHECK-OBJ: AddressAlignment: 8
# CHECK-OBJ: EntrySize: 0
# CHECK-OBJ: Relocations [
# CHECK-OBJ: ]
# CHECK-OBJ: SectionData (
# CHECK-OBJ: 0000: 00002002 01010001 00000000 00000000 |.. .............|
# CHECK-OBJ: 0010: 00000000 00000000 |........|
# CHECK-OBJ: )
# CHECK-OBJ: }

.module fp=32
.set fp=64
# FIXME: Test should include gnu_attributes directive when implemented.
# An explicit .gnu_attribute must be checked against the effective
# command line options and any inconsistencies reported via a warning.
37 changes: 37 additions & 0 deletions llvm/test/MC/Mips/mips64/abiflags.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# RUN: llvm-mc %s -arch=mips -mcpu=mips64 | \
# RUN: FileCheck %s -check-prefix=CHECK-ASM
#
# RUN: llvm-mc %s -arch=mips -mcpu=mips64 -filetype=obj -o - | \
# RUN: llvm-readobj -sections -section-data -section-relocations - | \
# RUN: FileCheck %s -check-prefix=CHECK-OBJ

# CHECK-ASM: .module fp=64

# Checking if the Mips.abiflags were correctly emitted.
# CHECK-OBJ: Section {
# CHECK-OBJ: Index: 5
# CHECK-OBJ: Name: .MIPS.abiflags (12)
# CHECK-OBJ: Type: (0x7000002A)
# CHECK-OBJ: Flags [ (0x2)
# CHECK-OBJ: SHF_ALLOC (0x2)
# CHECK-OBJ: ]
# CHECK-OBJ: Address: 0x0
# CHECK-OBJ: Offset: 0x50
# CHECK-OBJ: Size: 24
# CHECK-OBJ: Link: 0
# CHECK-OBJ: Info: 0
# CHECK-OBJ: AddressAlignment: 8
# CHECK-OBJ: EntrySize: 0
# CHECK-OBJ: Relocations [
# CHECK-OBJ: ]
# CHECK-OBJ: SectionData (
# CHECK-OBJ: 0000: 00004001 02020001 00000000 00000000 |..@.............|
# CHECK-OBJ: 0010: 00000000 00000000 |........|
# CHECK-OBJ: )
# CHECK-OBJ: }

.module fp=64

# FIXME: Test should include gnu_attributes directive when implemented.
# An explicit .gnu_attribute must be checked against the effective
# command line options and any inconsistencies reported via a warning.
9 changes: 9 additions & 0 deletions llvm/test/MC/Mips/mips64r2/abi-bad.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# RUN: not llvm-mc %s -triple mips-unknown-unknown -mcpu=mips64r2 2>&1 | FileCheck %s
# CHECK: .text



.set fp=xx
# CHECK : error: 'set fp=xx'option requires O32 ABI
# CHECK : .set fp=xx
# CHECK : ^
37 changes: 37 additions & 0 deletions llvm/test/MC/Mips/mips64r2/abiflags.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# RUN: llvm-mc %s -arch=mips -mcpu=mips64r2 | \
# RUN: FileCheck %s -check-prefix=CHECK-ASM
#
# RUN: llvm-mc %s -arch=mips -mcpu=mips64r2 -filetype=obj -o - | \
# RUN: llvm-readobj -sections -section-data -section-relocations - | \
# RUN: FileCheck %s -check-prefix=CHECK-OBJ

# CHECK-ASM: .module fp=64

# Checking if the Mips.abiflags were correctly emitted.
# CHECK-OBJ: Section {
# CHECK-OBJ: Index: 5
# CHECK-OBJ: Name: .MIPS.abiflags (12)
# CHECK-OBJ: Type: (0x7000002A)
# CHECK-OBJ: Flags [ (0x2)
# CHECK-OBJ: SHF_ALLOC (0x2)
# CHECK-OBJ: ]
# CHECK-OBJ: Address: 0x0
# CHECK-OBJ: Offset: 0x50
# CHECK-OBJ: Size: 24
# CHECK-OBJ: Link: 0
# CHECK-OBJ: Info: 0
# CHECK-OBJ: AddressAlignment: 8
# CHECK-OBJ: EntrySize: 0
# CHECK-OBJ: Relocations [
# CHECK-OBJ: ]
# CHECK-OBJ: SectionData (
# CHECK-OBJ: 0000: 00004002 02020001 00000000 00000000 |..@.............|
# CHECK-OBJ: 0010: 00000000 00000000 |........|
# CHECK-OBJ: )
# CHECK-OBJ: }

.module fp=64

# FIXME: Test should include gnu_attributes directive when implemented.
# An explicit .gnu_attribute must be checked against the effective
# command line options and any inconsistencies reported via a warning.
37 changes: 37 additions & 0 deletions llvm/test/MC/Mips/mips_abi_flags_xx.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# RUN: llvm-mc %s -arch=mips -mcpu=mips32 | \
# RUN: FileCheck %s -check-prefix=CHECK-ASM
#
# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -filetype=obj -o - | \
# RUN: llvm-readobj -sections -section-data -section-relocations - | \
# RUN: FileCheck %s -check-prefix=CHECK-OBJ

# CHECK-ASM: .module fp=xx

# Checking if the Mips.abiflags were correctly emitted.
# CHECK-OBJ: Section {
# CHECK-OBJ: Index: 5
# CHECK-OBJ: Name: .MIPS.abiflags (12)
# CHECK-OBJ: Type: (0x7000002A)
# CHECK-OBJ: Flags [ (0x2)
# CHECK-OBJ: SHF_ALLOC (0x2)
# CHECK-OBJ: ]
# CHECK-OBJ: Address: 0x0
# CHECK-OBJ: Offset: 0x50
# CHECK-OBJ: Size: 24
# CHECK-OBJ: Link: 0
# CHECK-OBJ: Info: 0
# CHECK-OBJ: AddressAlignment: 8
# CHECK-OBJ: EntrySize: 0
# CHECK-OBJ: Relocations [
# CHECK-OBJ: ]
# CHECK-OBJ: SectionData (
# CHECK-OBJ: 0000: 00002001 01010005 00000000 00000000 |.. .............|
# CHECK-OBJ: 0010: 00000000 00000000 |........|
# CHECK-OBJ: )
# CHECK-OBJ: }

.module fp=xx

# FIXME: Test should include gnu_attributes directive when implemented.
# An explicit .gnu_attribute must be checked against the effective
# command line options and any inconsistencies reported via a warning.
38 changes: 38 additions & 0 deletions llvm/test/MC/Mips/mips_abi_flags_xx_set.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# RUN: llvm-mc %s -arch=mips -mcpu=mips32 | \
# RUN: FileCheck %s -check-prefix=CHECK-ASM
#
# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -filetype=obj -o - | \
# RUN: llvm-readobj -sections -section-data -section-relocations - | \
# RUN: FileCheck %s -check-prefix=CHECK-OBJ

# CHECK-ASM: .module fp=xx
# CHECK-ASM: .set fp=64

# Checking if the Mips.abiflags were correctly emitted.
# CHECK-OBJ: Section {
# CHECK-OBJ: Index: 5
# CHECK-OBJ: Name: .MIPS.abiflags (12)
# CHECK-OBJ: Type: (0x7000002A)
# CHECK-OBJ: Flags [ (0x2)
# CHECK-OBJ: SHF_ALLOC (0x2)
# CHECK-OBJ: ]
# CHECK-OBJ: Address: 0x0
# CHECK-OBJ: Offset: 0x50
# CHECK-OBJ: Size: 24
# CHECK-OBJ: Link: 0
# CHECK-OBJ: Info: 0
# CHECK-OBJ: AddressAlignment: 8
# CHECK-OBJ: EntrySize: 0
# CHECK-OBJ: Relocations [
# CHECK-OBJ: ]
# CHECK-OBJ: SectionData (
# CHECK-OBJ: 0000: 00002001 01010005 00000000 00000000 |.. .............|
# CHECK-OBJ: 0010: 00000000 00000000 |........|
# CHECK-OBJ: )
# CHECK-OBJ: }

.module fp=xx
.set fp=64
# FIXME: Test should include gnu_attributes directive when implemented.
# An explicit .gnu_attribute must be checked against the effective
# command line options and any inconsistencies reported via a warning.