forked from OSchip/llvm-project
Mips.abiflags is a new implicitly generated section that will be present on all new modules. The section contains a versioned data structure which represents essentially information to allow a program loader to determine the requirements of the application. This patch implements mips.abiflags section and provides test cases for it.
llvm-svn: 212519
This commit is contained in:
parent
cc02abbb20
commit
fb8a2a95cd
|
@ -1299,6 +1299,7 @@ enum : unsigned {
|
|||
|
||||
SHT_MIPS_REGINFO = 0x70000006, // Register usage information
|
||||
SHT_MIPS_OPTIONS = 0x7000000d, // General options
|
||||
SHT_MIPS_ABIFLAGS = 0x7000002a, // ABI information.
|
||||
|
||||
SHT_HIPROC = 0x7fffffff, // Highest processor arch-specific type.
|
||||
SHT_LOUSER = 0x80000000, // Lowest type reserved for applications.
|
||||
|
@ -1616,7 +1617,8 @@ enum {
|
|||
// MIPS program header types.
|
||||
PT_MIPS_REGINFO = 0x70000000, // Register usage information.
|
||||
PT_MIPS_RTPROC = 0x70000001, // Runtime procedure table.
|
||||
PT_MIPS_OPTIONS = 0x70000002 // Options segment.
|
||||
PT_MIPS_OPTIONS = 0x70000002, // Options segment.
|
||||
PT_MIPS_ABIFLAGS = 0x70000003 // Abiflags segment.
|
||||
};
|
||||
|
||||
// Segment flag bits.
|
||||
|
|
|
@ -1565,6 +1565,7 @@ void ELFObjectWriter::WriteSection(MCAssembler &Asm,
|
|||
case ELF::SHT_X86_64_UNWIND:
|
||||
case ELF::SHT_MIPS_REGINFO:
|
||||
case ELF::SHT_MIPS_OPTIONS:
|
||||
case ELF::SHT_MIPS_ABIFLAGS:
|
||||
// Nothing to do.
|
||||
break;
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ class MCInstrInfo;
|
|||
namespace {
|
||||
class MipsAssemblerOptions {
|
||||
public:
|
||||
MipsAssemblerOptions() : aTReg(1), reorder(true), macro(true) {}
|
||||
MipsAssemblerOptions() : aTReg(1), reorder(true), macro(true), fpAbiMode(0) {}
|
||||
|
||||
unsigned getATRegNum() { return aTReg; }
|
||||
bool setATReg(unsigned Reg);
|
||||
|
@ -46,15 +46,18 @@ 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;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -156,39 +159,17 @@ class MipsAsmParser : public MCTargetAsmParser {
|
|||
bool parseSetReorderDirective();
|
||||
bool parseSetNoReorderDirective();
|
||||
bool parseSetNoMips16Directive();
|
||||
bool parseSetFpDirective();
|
||||
|
||||
bool parseSetAssignment();
|
||||
|
||||
bool parseDataDirective(unsigned Size, SMLoc L);
|
||||
bool parseDirectiveGpWord();
|
||||
bool parseDirectiveGpDWord();
|
||||
bool parseDirectiveModule();
|
||||
|
||||
MCSymbolRefExpr::VariantKind getVariantKind(StringRef Symbol);
|
||||
|
||||
bool isGP64() const {
|
||||
return (STI.getFeatureBits() & Mips::FeatureGP64Bit) != 0;
|
||||
}
|
||||
|
||||
bool isFP64() const {
|
||||
return (STI.getFeatureBits() & Mips::FeatureFP64Bit) != 0;
|
||||
}
|
||||
|
||||
bool isN32() const { return STI.getFeatureBits() & Mips::FeatureN32; }
|
||||
bool isN64() const { return STI.getFeatureBits() & Mips::FeatureN64; }
|
||||
|
||||
bool isMicroMips() const {
|
||||
return STI.getFeatureBits() & Mips::FeatureMicroMips;
|
||||
}
|
||||
|
||||
bool hasMips4() const { return STI.getFeatureBits() & Mips::FeatureMips4; }
|
||||
bool hasMips32() const { return STI.getFeatureBits() & Mips::FeatureMips32; }
|
||||
bool hasMips32r6() const {
|
||||
return STI.getFeatureBits() & Mips::FeatureMips32r6;
|
||||
}
|
||||
bool hasMips64r6() const {
|
||||
return STI.getFeatureBits() & Mips::FeatureMips64r6;
|
||||
}
|
||||
|
||||
bool eatComma(StringRef ErrorStr);
|
||||
|
||||
int matchCPURegisterName(StringRef Symbol);
|
||||
|
@ -243,12 +224,13 @@ public:
|
|||
};
|
||||
|
||||
MipsAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser,
|
||||
const MCInstrInfo &MII,
|
||||
const MCTargetOptions &Options)
|
||||
const MCInstrInfo &MII, const MCTargetOptions &Options)
|
||||
: MCTargetAsmParser(), STI(sti), Parser(parser) {
|
||||
// Initialize the set of available features.
|
||||
setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
|
||||
|
||||
getTargetStreamer().updateABIInfo(*this);
|
||||
|
||||
// Assert exactly one ABI was chosen.
|
||||
assert((((STI.getFeatureBits() & Mips::FeatureO32) != 0) +
|
||||
((STI.getFeatureBits() & Mips::FeatureEABI) != 0) +
|
||||
|
@ -262,6 +244,49 @@ public:
|
|||
/// True if all of $fcc0 - $fcc7 exist for the current ISA.
|
||||
bool hasEightFccRegisters() const { return hasMips4() || hasMips32(); }
|
||||
|
||||
bool isGP64bit() const { return STI.getFeatureBits() & Mips::FeatureGP64Bit; }
|
||||
bool isFP64bit() const { return STI.getFeatureBits() & Mips::FeatureFP64Bit; }
|
||||
bool isABI_N32() const { return STI.getFeatureBits() & Mips::FeatureN32; }
|
||||
bool isABI_N64() const { return STI.getFeatureBits() & Mips::FeatureN64; }
|
||||
bool isABI_O32() const { return STI.getFeatureBits() & Mips::FeatureO32; }
|
||||
bool isABI_FPXX() const { return false; } // TODO: add check for FeatureXX
|
||||
|
||||
bool inMicroMipsMode() const {
|
||||
return STI.getFeatureBits() & Mips::FeatureMicroMips;
|
||||
}
|
||||
bool hasMips1() const { return STI.getFeatureBits() & Mips::FeatureMips1; }
|
||||
bool hasMips2() const { return STI.getFeatureBits() & Mips::FeatureMips2; }
|
||||
bool hasMips3() const { return STI.getFeatureBits() & Mips::FeatureMips3; }
|
||||
bool hasMips4() const { return STI.getFeatureBits() & Mips::FeatureMips4; }
|
||||
bool hasMips5() const { return STI.getFeatureBits() & Mips::FeatureMips5; }
|
||||
bool hasMips32() const {
|
||||
return (STI.getFeatureBits() & Mips::FeatureMips32);
|
||||
}
|
||||
bool hasMips64() const {
|
||||
return (STI.getFeatureBits() & Mips::FeatureMips64);
|
||||
}
|
||||
bool hasMips32r2() const {
|
||||
return (STI.getFeatureBits() & Mips::FeatureMips32r2);
|
||||
}
|
||||
bool hasMips64r2() const {
|
||||
return (STI.getFeatureBits() & Mips::FeatureMips64r2);
|
||||
}
|
||||
bool hasMips32r6() const {
|
||||
return (STI.getFeatureBits() & Mips::FeatureMips32r6);
|
||||
}
|
||||
bool hasMips64r6() const {
|
||||
return (STI.getFeatureBits() & Mips::FeatureMips64r6);
|
||||
}
|
||||
bool hasDSP() const { return (STI.getFeatureBits() & Mips::FeatureDSP); }
|
||||
bool hasDSPR2() const { return (STI.getFeatureBits() & Mips::FeatureDSPR2); }
|
||||
bool hasMSA() const { return (STI.getFeatureBits() & Mips::FeatureMSA); }
|
||||
|
||||
bool inMips16Mode() const {
|
||||
return STI.getFeatureBits() & Mips::FeatureMips16;
|
||||
}
|
||||
// TODO: see how can we get this info.
|
||||
bool mipsSEUsesSoftFloat() const { return false; }
|
||||
|
||||
/// Warn if RegNo is the current assembler temporary.
|
||||
void WarnIfAssemblerTemporary(int RegNo, SMLoc Loc);
|
||||
};
|
||||
|
@ -276,9 +301,9 @@ public:
|
|||
/// Broad categories of register classes
|
||||
/// The exact class is finalized by the render method.
|
||||
enum RegKind {
|
||||
RegKind_GPR = 1, /// GPR32 and GPR64 (depending on isGP64())
|
||||
RegKind_GPR = 1, /// GPR32 and GPR64 (depending on isGP64bit())
|
||||
RegKind_FGR = 2, /// FGR32, FGR64, AFGR64 (depending on context and
|
||||
/// isFP64())
|
||||
/// isFP64bit())
|
||||
RegKind_FCC = 4, /// FCC
|
||||
RegKind_MSA128 = 8, /// MSA128[BHWD] (makes no difference which)
|
||||
RegKind_MSACtrl = 16, /// MSA control registers
|
||||
|
@ -882,9 +907,10 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
|
|||
Offset = Inst.getOperand(2);
|
||||
if (!Offset.isImm())
|
||||
break; // We'll deal with this situation later on when applying fixups.
|
||||
if (!isIntN(isMicroMips() ? 17 : 18, Offset.getImm()))
|
||||
if (!isIntN(inMicroMipsMode() ? 17 : 18, Offset.getImm()))
|
||||
return Error(IDLoc, "branch target out of range");
|
||||
if (OffsetToAlignment(Offset.getImm(), 1LL << (isMicroMips() ? 1 : 2)))
|
||||
if (OffsetToAlignment(Offset.getImm(),
|
||||
1LL << (inMicroMipsMode() ? 1 : 2)))
|
||||
return Error(IDLoc, "branch to misaligned address");
|
||||
break;
|
||||
case Mips::BGEZ:
|
||||
|
@ -907,9 +933,10 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
|
|||
Offset = Inst.getOperand(1);
|
||||
if (!Offset.isImm())
|
||||
break; // We'll deal with this situation later on when applying fixups.
|
||||
if (!isIntN(isMicroMips() ? 17 : 18, Offset.getImm()))
|
||||
if (!isIntN(inMicroMipsMode() ? 17 : 18, Offset.getImm()))
|
||||
return Error(IDLoc, "branch target out of range");
|
||||
if (OffsetToAlignment(Offset.getImm(), 1LL << (isMicroMips() ? 1 : 2)))
|
||||
if (OffsetToAlignment(Offset.getImm(),
|
||||
1LL << (inMicroMipsMode() ? 1 : 2)))
|
||||
return Error(IDLoc, "branch to misaligned address");
|
||||
break;
|
||||
}
|
||||
|
@ -994,12 +1021,13 @@ bool MipsAsmParser::needsExpansion(MCInst &Inst) {
|
|||
bool MipsAsmParser::expandInstruction(MCInst &Inst, SMLoc IDLoc,
|
||||
SmallVectorImpl<MCInst> &Instructions) {
|
||||
switch (Inst.getOpcode()) {
|
||||
default: assert(0 && "unimplemented expansion");
|
||||
default:
|
||||
assert(0 && "unimplemented expansion");
|
||||
return true;
|
||||
case Mips::LoadImm32Reg:
|
||||
return expandLoadImm(Inst, IDLoc, Instructions);
|
||||
case Mips::LoadImm64Reg:
|
||||
if (!isGP64()) {
|
||||
if (!isGP64bit()) {
|
||||
Error(IDLoc, "instruction requires a CPU feature not currently enabled");
|
||||
return true;
|
||||
}
|
||||
|
@ -1074,7 +1102,7 @@ bool MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc,
|
|||
Instructions.push_back(tmpInst);
|
||||
createShiftOr<0, false>(ImmValue, RegOp.getReg(), IDLoc, Instructions);
|
||||
} else if ((ImmValue & (0xffffLL << 48)) == 0) {
|
||||
if (!isGP64()) {
|
||||
if (!isGP64bit()) {
|
||||
Error(IDLoc, "instruction requires a CPU feature not currently enabled");
|
||||
return true;
|
||||
}
|
||||
|
@ -1101,7 +1129,7 @@ bool MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc,
|
|||
createShiftOr<16, false>(ImmValue, RegOp.getReg(), IDLoc, Instructions);
|
||||
createShiftOr<0, true>(ImmValue, RegOp.getReg(), IDLoc, Instructions);
|
||||
} else {
|
||||
if (!isGP64()) {
|
||||
if (!isGP64bit()) {
|
||||
Error(IDLoc, "instruction requires a CPU feature not currently enabled");
|
||||
return true;
|
||||
}
|
||||
|
@ -1274,8 +1302,8 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc,
|
|||
// not available.
|
||||
if (!AT)
|
||||
return;
|
||||
TmpRegNum =
|
||||
getReg((isGP64()) ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, AT);
|
||||
TmpRegNum = getReg(
|
||||
(isGP64bit()) ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, AT);
|
||||
}
|
||||
|
||||
TempInst.setOpcode(Mips::LUi);
|
||||
|
@ -1433,7 +1461,7 @@ int MipsAsmParser::matchCPURegisterName(StringRef Name) {
|
|||
.Case("t9", 25)
|
||||
.Default(-1);
|
||||
|
||||
if (isN32() || isN64()) {
|
||||
if (isABI_N32() || isABI_N64()) {
|
||||
// Although SGI documentation just cuts out t0-t3 for n32/n64,
|
||||
// GNU pushes the values of t0-t3 to override the o32/o64 values for t4-t7
|
||||
// We are supporting both cases, so for t0-t3 we'll just push them to t4-t7.
|
||||
|
@ -1546,7 +1574,7 @@ unsigned MipsAsmParser::getReg(int RC, int RegNo) {
|
|||
}
|
||||
|
||||
unsigned MipsAsmParser::getGPR(int RegNo) {
|
||||
return getReg(isGP64() ? Mips::GPR64RegClassID : Mips::GPR32RegClassID,
|
||||
return getReg(isGP64bit() ? Mips::GPR64RegClassID : Mips::GPR32RegClassID,
|
||||
RegNo);
|
||||
}
|
||||
|
||||
|
@ -1771,7 +1799,7 @@ bool MipsAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
|
|||
// register is a parse error.
|
||||
if (Operand.isGPRAsmReg()) {
|
||||
// Resolve to GPR32 or GPR64 appropriately.
|
||||
RegNo = isGP64() ? Operand.getGPR64Reg() : Operand.getGPR32Reg();
|
||||
RegNo = isGP64bit() ? Operand.getGPR64Reg() : Operand.getGPR32Reg();
|
||||
}
|
||||
|
||||
return (RegNo == (unsigned)-1);
|
||||
|
@ -2227,6 +2255,9 @@ bool MipsAsmParser::ParseBracketSuffix(StringRef Name,
|
|||
bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
|
||||
SMLoc NameLoc, OperandVector &Operands) {
|
||||
DEBUG(dbgs() << "ParseInstruction\n");
|
||||
// We have reached first instruction, module directive after
|
||||
// this is forbidden.
|
||||
getTargetStreamer().setCanHaveModuleDir(false);
|
||||
// Check if we have valid mnemonic
|
||||
if (!mnemonicIsValid(Name, 0)) {
|
||||
Parser.eatToEndOfStatement();
|
||||
|
@ -2413,6 +2444,60 @@ bool MipsAsmParser::parseSetNoMips16Directive() {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool MipsAsmParser::parseSetFpDirective() {
|
||||
int FpAbiMode;
|
||||
// Line can be: .set fp=32
|
||||
// .set fp=xx
|
||||
// .set fp=64
|
||||
Parser.Lex(); // Eat fp token
|
||||
AsmToken Tok = Parser.getTok();
|
||||
if (Tok.isNot(AsmToken::Equal)) {
|
||||
reportParseError("unexpected token in statement");
|
||||
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;
|
||||
}
|
||||
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 (getLexer().isNot(AsmToken::EndOfStatement)) {
|
||||
reportParseError("unexpected token in statement");
|
||||
return false;
|
||||
}
|
||||
Options.setFpAbiMode(FpAbiMode);
|
||||
getTargetStreamer().emitDirectiveSetFp(FpAbiMode, isABI_O32());
|
||||
Parser.Lex(); // Consume the EndOfStatement.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MipsAsmParser::parseSetAssignment() {
|
||||
StringRef Name;
|
||||
const MCExpr *Value;
|
||||
|
@ -2594,6 +2679,8 @@ bool MipsAsmParser::parseDirectiveSet() {
|
|||
return parseSetNoAtDirective();
|
||||
} else if (Tok.getString() == "at") {
|
||||
return parseSetAtDirective();
|
||||
} else if (Tok.getString() == "fp") {
|
||||
return parseSetFpDirective();
|
||||
} else if (Tok.getString() == "reorder") {
|
||||
return parseSetReorderDirective();
|
||||
} else if (Tok.getString() == "noreorder") {
|
||||
|
@ -2726,6 +2813,61 @@ bool MipsAsmParser::parseDirectiveOption() {
|
|||
return false;
|
||||
}
|
||||
|
||||
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");
|
||||
return false;
|
||||
}
|
||||
AsmToken Tok = Parser.getTok();
|
||||
if (Tok.isNot(AsmToken::Identifier) && Tok.getString() != "fp") {
|
||||
reportParseError("unexpected token in .module directive, 'fp' expected");
|
||||
return false;
|
||||
}
|
||||
Parser.Lex(); // Eat fp token
|
||||
Tok = Parser.getTok();
|
||||
if (Tok.isNot(AsmToken::Equal)) {
|
||||
reportParseError("unexpected token in statement");
|
||||
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.
|
||||
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::ParseDirective(AsmToken DirectiveID) {
|
||||
StringRef IDVal = DirectiveID.getString();
|
||||
|
||||
|
@ -2804,6 +2946,9 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) {
|
|||
if (IDVal == ".cpsetup")
|
||||
return parseDirectiveCPSetup();
|
||||
|
||||
if (IDVal == ".module")
|
||||
return parseDirectiveModule();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {}
|
||||
|
@ -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) {
|
||||
|
@ -137,18 +148,22 @@ 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) {
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -318,8 +386,8 @@ void MipsTargetELFStreamer::emitAssignment(MCSymbol *Symbol,
|
|||
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);
|
||||
|
@ -344,6 +412,7 @@ void MipsTargetELFStreamer::emitDirectiveSetMicroMips() {
|
|||
|
||||
void MipsTargetELFStreamer::emitDirectiveSetNoMicroMips() {
|
||||
MicroMipsEnabled = false;
|
||||
setCanHaveModuleDir(false);
|
||||
}
|
||||
|
||||
void MipsTargetELFStreamer::emitDirectiveSetMips16() {
|
||||
|
@ -351,14 +420,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() {
|
||||
|
@ -366,22 +438,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) {
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
|
|
@ -162,6 +162,7 @@ public:
|
|||
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
|
||||
|
@ -174,8 +175,11 @@ public:
|
|||
/// 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 {
|
||||
|
|
|
@ -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);
|
||||
|
@ -50,6 +132,109 @@ public:
|
|||
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
|
||||
|
@ -91,6 +276,11 @@ public:
|
|||
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
|
||||
|
@ -142,6 +332,9 @@ public:
|
|||
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; }
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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 : ^
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
# 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
|
||||
|
@ -20,7 +20,7 @@
|
|||
# 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
|
||||
|
|
|
@ -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.
|
|
@ -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.
|
|
@ -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.
|
|
@ -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 : ^
|
|
@ -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.
|
|
@ -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.
|
|
@ -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.
|
Loading…
Reference in New Issue