[mips] Improve encapsulation of the .MIPS.abiflags implementation and limit scope of related enums

Summary:
Follow on to r212519 to improve the encapsulation and limit the scope of the enums.

Also merged two very similar parser functions, fixed a bug where ASE's
were not being reported, and marked CPR1's as being 128-bit when MSA is
enabled.

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


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@212522 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Daniel Sanders 2014-07-08 10:11:38 +00:00
parent aebcee661e
commit fbdb8e1eac
8 changed files with 393 additions and 300 deletions

View File

@ -38,7 +38,7 @@ class MCInstrInfo;
namespace {
class MipsAssemblerOptions {
public:
MipsAssemblerOptions() : aTReg(1), reorder(true), macro(true), fpAbiMode(0) {}
MipsAssemblerOptions() : aTReg(1), reorder(true), macro(true) {}
unsigned getATRegNum() { return aTReg; }
bool setATReg(unsigned Reg);
@ -46,18 +46,15 @@ public:
bool isReorder() { return reorder; }
void setReorder() { reorder = true; }
void setNoreorder() { reorder = false; }
void setFpAbiMode(int Mode) { fpAbiMode = Mode; }
bool isMacro() { return macro; }
void setMacro() { macro = true; }
void setNomacro() { macro = false; }
int getFpAbiMode() { return fpAbiMode; }
private:
unsigned aTReg;
bool reorder;
bool macro;
int fpAbiMode;
};
}
@ -136,8 +133,8 @@ class MipsAsmParser : public MCTargetAsmParser {
void expandMemInst(MCInst &Inst, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions, bool isLoad,
bool isImmOpnd);
bool reportParseError(StringRef ErrorMsg);
bool reportParseError(SMLoc Loc, StringRef ErrorMsg);
bool reportParseError(Twine ErrorMsg);
bool reportParseError(SMLoc Loc, Twine ErrorMsg);
bool parseMemOffset(const MCExpr *&Res, bool isParenExpr);
bool parseRelocOperand(const MCExpr *&Res);
@ -167,6 +164,8 @@ class MipsAsmParser : public MCTargetAsmParser {
bool parseDirectiveGpWord();
bool parseDirectiveGpDWord();
bool parseDirectiveModule();
bool parseDirectiveModuleFP();
bool parseFpABIValue(Val_GNU_MIPS_ABI &FpABI, StringRef Directive);
MCSymbolRefExpr::VariantKind getVariantKind(StringRef Symbol);
@ -2304,13 +2303,13 @@ bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
return false;
}
bool MipsAsmParser::reportParseError(StringRef ErrorMsg) {
bool MipsAsmParser::reportParseError(Twine ErrorMsg) {
SMLoc Loc = getLexer().getLoc();
Parser.eatToEndOfStatement();
return Error(Loc, ErrorMsg);
}
bool MipsAsmParser::reportParseError(SMLoc Loc, StringRef ErrorMsg) {
bool MipsAsmParser::reportParseError(SMLoc Loc, Twine ErrorMsg) {
return Error(Loc, ErrorMsg);
}
@ -2445,7 +2444,7 @@ bool MipsAsmParser::parseSetNoMips16Directive() {
}
bool MipsAsmParser::parseSetFpDirective() {
int FpAbiMode;
Val_GNU_MIPS_ABI FpAbiVal;
// Line can be: .set fp=32
// .set fp=xx
// .set fp=64
@ -2457,43 +2456,15 @@ bool MipsAsmParser::parseSetFpDirective() {
}
Parser.Lex(); // Eat '=' token.
Tok = Parser.getTok();
if (Tok.is(AsmToken::Identifier)) {
StringRef XX = Tok.getString();
if (XX != "xx") {
reportParseError("unsupported option");
return false;
}
if (!isABI_O32()) {
reportParseError("'set fp=xx'option requires O32 ABI");
return false;
}
FpAbiMode = Val_GNU_MIPS_ABI_FP_XX;
} else if (Tok.is(AsmToken::Integer)) {
unsigned Value = Tok.getIntVal();
if (Value != 32 && Value != 64) {
reportParseError("unsupported option");
return false;
}
if (Value == 32) {
if (!isABI_O32()) {
reportParseError("'set fp=32'option requires O32 ABI");
return false;
}
FpAbiMode = Val_GNU_MIPS_ABI_FP_DOUBLE;
} else {
if (isABI_N32() || isABI_N64())
FpAbiMode = Val_GNU_MIPS_ABI_FP_DOUBLE;
else if (isABI_O32())
FpAbiMode = Val_GNU_MIPS_ABI_FP_64;
}
}
Parser.Lex(); // Eat option token.
if (!parseFpABIValue(FpAbiVal, ".set"))
return false;
if (getLexer().isNot(AsmToken::EndOfStatement)) {
reportParseError("unexpected token in statement");
return false;
}
Options.setFpAbiMode(FpAbiMode);
getTargetStreamer().emitDirectiveSetFp(FpAbiMode, isABI_O32());
getTargetStreamer().emitDirectiveSetFp(FpAbiVal, isABI_O32());
Parser.Lex(); // Consume the EndOfStatement.
return false;
}
@ -2817,7 +2788,6 @@ bool MipsAsmParser::parseDirectiveModule() {
// Line can be: .module fp=32
// .module fp=xx
// .module fp=64
unsigned FpAbiVal = 0;
if (!getTargetStreamer().getCanHaveModuleDir()) {
// TODO : get a better message.
reportParseError(".module directive must appear before any code");
@ -2835,39 +2805,76 @@ bool MipsAsmParser::parseDirectiveModule() {
return false;
}
Parser.Lex(); // Eat '=' token.
Tok = Parser.getTok();
if (Tok.is(AsmToken::Identifier)) {
StringRef XX = Tok.getString();
if (XX != "xx") {
reportParseError("unsupported option");
return false;
}
FpAbiVal = Val_GNU_MIPS_ABI_FP_XX;
} else if (Tok.is(AsmToken::Integer)) {
unsigned Value = Tok.getIntVal();
if (Value != 32 && Value != 64) {
reportParseError("unsupported value, expected 32 or 64");
return false;
}
if (Value == 64) {
if (isABI_N32() || isABI_N64())
FpAbiVal = Val_GNU_MIPS_ABI_FP_DOUBLE;
else if (isABI_O32())
FpAbiVal = Val_GNU_MIPS_ABI_FP_64;
} else if (isABI_O32())
FpAbiVal = Val_GNU_MIPS_ABI_FP_DOUBLE;
}
Parser.Lex(); // Eat option token.
Val_GNU_MIPS_ABI FpABI;
if (!parseFpABIValue(FpABI, ".module"))
return false;
if (getLexer().isNot(AsmToken::EndOfStatement)) {
reportParseError("unexpected token in statement");
return false;
}
// Emit appropriate flags.
getTargetStreamer().emitDirectiveModule(FpAbiVal, isABI_O32());
getTargetStreamer().setFpABI(FpAbiVal);
Parser.Lex(); // Consume the EndOfStatement.
return false;
}
bool MipsAsmParser::parseFpABIValue(Val_GNU_MIPS_ABI &FpABI,
StringRef Directive) {
MCAsmLexer &Lexer = getLexer();
if (Lexer.is(AsmToken::Identifier)) {
StringRef Value = Parser.getTok().getString();
Parser.Lex();
if (Value != "xx") {
reportParseError("unsupported value, expected 'xx', '32' or '64'");
return false;
}
if (!isABI_O32()) {
reportParseError("'" + Directive + " fp=xx' requires the O32 ABI");
return false;
}
FpABI = MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_XX;
return true;
}
if (Lexer.is(AsmToken::Integer)) {
unsigned Value = Parser.getTok().getIntVal();
Parser.Lex();
if (Value != 32 && Value != 64) {
reportParseError("unsupported value, expected 'xx', '32' or '64'");
return false;
}
if (Value == 32) {
if (!isABI_O32()) {
reportParseError("'" + Directive + " fp=32' requires the O32 ABI");
return false;
}
FpABI = MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_DOUBLE;
return true;
} else {
if (isABI_N32() || isABI_N64()) {
FpABI = MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_DOUBLE;
return true;
}
if (isABI_O32()) {
FpABI = MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_64;
return true;
}
llvm_unreachable("Unknown ABI");
}
}
return false;
}
bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) {
StringRef IDVal = DirectiveID.getString();

View File

@ -1,4 +1,5 @@
add_llvm_library(LLVMMipsDesc
MipsABIFlagsSection.cpp
MipsAsmBackend.cpp
MipsELFObjectWriter.cpp
MipsELFStreamer.cpp

View File

@ -0,0 +1,46 @@
//===-- MipsABIFlagsSection.cpp - Mips ELF ABI Flags Section ---*- C++ -*--===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "MipsABIFlagsSection.h"
using namespace llvm;
StringRef MipsABIFlagsSection::getFpABIString(Val_GNU_MIPS_ABI Value,
bool Is32BitAbi) {
switch (Value) {
case MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_XX:
return "xx";
case MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_64:
return "64";
case MipsABIFlagsSection::Val_GNU_MIPS_ABI_FP_DOUBLE:
if (Is32BitAbi)
return "32";
return "64";
default:
llvm_unreachable("unsupported fp abi value");
}
}
namespace llvm {
MCStreamer &operator<<(MCStreamer &OS, MipsABIFlagsSection &ABIFlagsSection) {
// Write out a Elf_Internal_ABIFlags_v0 struct
OS.EmitIntValue(ABIFlagsSection.getVersion(), 2); // version
OS.EmitIntValue(ABIFlagsSection.getISALevel(), 1); // isa_level
OS.EmitIntValue(ABIFlagsSection.getISARevision(), 1); // isa_rev
OS.EmitIntValue(ABIFlagsSection.getGPRSize(), 1); // gpr_size
OS.EmitIntValue(ABIFlagsSection.getCPR1Size(), 1); // cpr1_size
OS.EmitIntValue(ABIFlagsSection.getCPR2Size(), 1); // cpr2_size
OS.EmitIntValue(ABIFlagsSection.getFpABI(), 1); // fp_abi
OS.EmitIntValue(ABIFlagsSection.getISAExtensionSet(), 4); // isa_ext
OS.EmitIntValue(ABIFlagsSection.getASESet(), 4); // ases
OS.EmitIntValue(ABIFlagsSection.getFlags1(), 4); // flags1
OS.EmitIntValue(ABIFlagsSection.getFlags2(), 4); // flags2
return OS;
}
}

View File

@ -0,0 +1,206 @@
//===-- MipsABIFlagsSection.h - Mips ELF ABI Flags Section -----*- C++ -*--===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef MIPSABIFLAGSSECTION_H
#define MIPSABIFLAGSSECTION_H
#include "llvm/MC/MCStreamer.h"
namespace llvm {
class MCStreamer;
struct MipsABIFlagsSection {
// Values for the xxx_size bytes of an ABI flags structure.
enum AFL_REG {
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 {
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 {
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 {
Val_GNU_MIPS_ABI_FP_ANY = 0,
Val_GNU_MIPS_ABI_FP_DOUBLE = 1,
Val_GNU_MIPS_ABI_FP_XX = 5,
Val_GNU_MIPS_ABI_FP_64 = 6
};
// Version of flags structure.
uint16_t Version;
// The level of the ISA: 1-5, 32, 64.
uint8_t ISALevel;
// The revision of ISA: 0 for MIPS V and below, 1-n otherwise.
uint8_t ISARevision;
// The size of general purpose registers.
AFL_REG GPRSize;
// The size of co-processor 1 registers.
AFL_REG CPR1Size;
// The size of co-processor 2 registers.
AFL_REG CPR2Size;
// The floating-point ABI.
Val_GNU_MIPS_ABI FpABI;
// Processor-specific extension.
uint32_t ISAExtensionSet;
// Mask of ASEs used.
uint32_t ASESet;
MipsABIFlagsSection()
: Version(0), ISALevel(0), ISARevision(0), GPRSize(AFL_REG_NONE),
CPR1Size(AFL_REG_NONE), CPR2Size(AFL_REG_NONE),
FpABI(Val_GNU_MIPS_ABI_FP_ANY), ISAExtensionSet(0), ASESet(0) {}
uint16_t getVersion() { return (uint16_t)Version; }
uint8_t getISALevel() { return (uint8_t)ISALevel; }
uint8_t getISARevision() { return (uint8_t)ISARevision; }
uint8_t getGPRSize() { return (uint8_t)GPRSize; }
uint8_t getCPR1Size() { return (uint8_t)CPR1Size; }
uint8_t getCPR2Size() { return (uint8_t)CPR2Size; }
uint8_t getFpABI() { return (uint8_t)FpABI; }
uint32_t getISAExtensionSet() { return (uint32_t)ISAExtensionSet; }
uint32_t getASESet() { return (uint32_t)ASESet; }
uint32_t getFlags1() { return 0; }
uint32_t getFlags2() { return 0; }
StringRef getFpABIString(Val_GNU_MIPS_ABI Value, bool Is32BitAbi);
template <class PredicateLibrary>
void setISALevelAndRevisionFromPredicates(const PredicateLibrary &P) {
if (P.hasMips64()) {
ISALevel = 64;
if (P.hasMips64r6())
ISARevision = 6;
else if (P.hasMips64r2())
ISARevision = 2;
else
ISARevision = 1;
} else if (P.hasMips32()) {
ISALevel = 32;
if (P.hasMips32r6())
ISARevision = 6;
else if (P.hasMips32r2())
ISARevision = 2;
else
ISARevision = 1;
} else {
ISARevision = 0;
if (P.hasMips5())
ISALevel = 5;
else if (P.hasMips4())
ISALevel = 4;
else if (P.hasMips3())
ISALevel = 3;
else if (P.hasMips2())
ISALevel = 2;
else if (P.hasMips1())
ISALevel = 1;
else
llvm_unreachable("Unknown ISA level!");
}
}
template <class PredicateLibrary>
void setGPRSizeFromPredicates(const PredicateLibrary &P) {
GPRSize = P.isGP64bit() ? AFL_REG_64 : AFL_REG_32;
}
template <class PredicateLibrary>
void setCPR1SizeFromPredicates(const PredicateLibrary &P) {
if (P.mipsSEUsesSoftFloat())
CPR1Size = AFL_REG_NONE;
else if (P.hasMSA())
CPR1Size = AFL_REG_128;
else
CPR1Size = P.isFP64bit() ? AFL_REG_64 : AFL_REG_32;
}
template <class PredicateLibrary>
void setASESetFromPredicates(const PredicateLibrary &P) {
ASESet = 0;
if (P.hasDSP())
ASESet |= AFL_ASE_DSP;
if (P.hasDSPR2())
ASESet |= AFL_ASE_DSPR2;
if (P.hasMSA())
ASESet |= AFL_ASE_MSA;
if (P.inMicroMipsMode())
ASESet |= AFL_ASE_MICROMIPS;
if (P.inMips16Mode())
ASESet |= AFL_ASE_MIPS16;
}
template <class PredicateLibrary>
void setFpAbiFromPredicates(const PredicateLibrary &P) {
FpABI = Val_GNU_MIPS_ABI_FP_ANY;
if (P.isABI_N32() || P.isABI_N64())
FpABI = Val_GNU_MIPS_ABI_FP_DOUBLE;
else if (P.isABI_O32()) {
if (P.isFP64bit())
FpABI = Val_GNU_MIPS_ABI_FP_64;
else if (P.isABI_FPXX())
FpABI = Val_GNU_MIPS_ABI_FP_XX;
else
FpABI = Val_GNU_MIPS_ABI_FP_DOUBLE;
}
}
template <class PredicateLibrary>
void setAllFromPredicates(const PredicateLibrary &P) {
setISALevelAndRevisionFromPredicates(P);
setGPRSizeFromPredicates(P);
setCPR1SizeFromPredicates(P);
setASESetFromPredicates(P);
setFpAbiFromPredicates(P);
}
};
MCStreamer &operator<<(MCStreamer &OS, MipsABIFlagsSection &ABIFlagsSection);
}
#endif

View File

@ -211,50 +211,20 @@ void MipsTargetAsmStreamer::emitDirectiveCpsetup(unsigned RegNo,
setCanHaveModuleDir(false);
}
void MipsTargetAsmStreamer::emitDirectiveModule(unsigned Value,
bool is32BitAbi) {
void MipsTargetAsmStreamer::emitDirectiveModuleFP(Val_GNU_MIPS_ABI Value,
bool Is32BitAbi) {
MipsTargetStreamer::emitDirectiveModuleFP(Value, 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";
OS << ABIFlagsSection.getFpABIString(Value, Is32BitAbi) << "\n";
}
void MipsTargetAsmStreamer::emitDirectiveSetFp(unsigned Value,
bool is32BitAbi) {
void MipsTargetAsmStreamer::emitDirectiveSetFp(Val_GNU_MIPS_ABI 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";
OS << ABIFlagsSection.getFpABIString(Value, Is32BitAbi) << "\n";
}
void MipsTargetAsmStreamer::emitMipsAbiFlags() {
@ -661,15 +631,5 @@ void MipsTargetELFStreamer::emitMipsAbiFlags() {
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
OS << ABIFlagsSection;
}

View File

@ -94,6 +94,7 @@ bool MipsAsmPrinter::lowerOperand(const MachineOperand &MO, MCOperand &MCOp) {
void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) {
MipsTargetStreamer &TS = getTargetStreamer();
TS.setCanHaveModuleDir(false);
if (MI->isDebugValue()) {
SmallString<128> Str;
raw_svector_ostream OS(Str);
@ -660,18 +661,8 @@ void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) {
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());
getTargetStreamer().emitDirectiveModuleFP(
getTargetStreamer().getABIFlagsSection().FpABI, Subtarget->isABI_O32());
}
void MipsAsmPrinter::EmitJal(MCSymbol *Symbol) {

View File

@ -12,89 +12,13 @@
#include "llvm/MC/MCELFStreamer.h"
#include "llvm/MC/MCStreamer.h"
#include "MCTargetDesc/MipsABIFlagsSection.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) {}
};
class MipsABIFlagsSection;
// 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
};
using Val_GNU_MIPS_ABI = MipsABIFlagsSection::Val_GNU_MIPS_ABI;
class MipsTargetStreamer : public MCTargetStreamer {
public:
@ -133,105 +57,25 @@ public:
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 emitDirectiveModuleFP(Val_GNU_MIPS_ABI Value, bool Is32BitAbi) {
ABIFlagsSection.FpABI = Value;
}
virtual void emitDirectiveSetFp(Val_GNU_MIPS_ABI 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.
ABIFlagsSection.setAllFromPredicates(P);
}
MipsABIFlagsSection &getABIFlagsSection() { return ABIFlagsSection; }
protected:
Elf_Internal_ABIFlags_v0 MipsABIFlags;
MipsABIFlagsSection ABIFlagsSection;
private:
bool canHaveModuleDirective;
@ -278,8 +122,8 @@ public:
const MCSymbol &Sym, bool IsReg) override;
// ABI Flags
void emitDirectiveModule(unsigned Value, bool is32BitAbi) override;
void emitDirectiveSetFp(unsigned Value, bool is32BitAbi) override;
void emitDirectiveModuleFP(Val_GNU_MIPS_ABI Value, bool Is32BitAbi) override;
void emitDirectiveSetFp(Val_GNU_MIPS_ABI Value, bool Is32BitAbi) override;
void emitMipsAbiFlags() override;
};

View File

@ -0,0 +1,38 @@
# RUN: llvm-mc %s -arch=mips -mcpu=mips32r2 -mattr=+msa | \
# RUN: FileCheck %s -check-prefix=CHECK-ASM
#
# RUN: llvm-mc %s -arch=mips -mcpu=mips32r2 -mattr=+msa -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 01030001 00000000 00000200 |.. .............|
# 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.