summaryrefslogtreecommitdiff
path: root/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp')
-rw-r--r--llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp443
1 files changed, 269 insertions, 174 deletions
diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
index 21d0df74d458..e467ed36938b 100644
--- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
+++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
@@ -126,13 +126,16 @@ const FeatureBitset MipsAssemblerOptions::AllArchRelatedMask = {
Mips::FeatureMips32r3, Mips::FeatureMips32r5, Mips::FeatureMips32r6,
Mips::FeatureMips64, Mips::FeatureMips64r2, Mips::FeatureMips64r3,
Mips::FeatureMips64r5, Mips::FeatureMips64r6, Mips::FeatureCnMips,
- Mips::FeatureFP64Bit, Mips::FeatureGP64Bit, Mips::FeatureNaN2008
+ Mips::FeatureCnMipsP, Mips::FeatureFP64Bit, Mips::FeatureGP64Bit,
+ Mips::FeatureNaN2008
};
namespace {
class MipsAsmParser : public MCTargetAsmParser {
MipsTargetStreamer &getTargetStreamer() {
+ assert(getParser().getStreamer().getTargetStreamer() &&
+ "do not have a target streamer");
MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer();
return static_cast<MipsTargetStreamer &>(TS);
}
@@ -251,8 +254,10 @@ class MipsAsmParser : public MCTargetAsmParser {
bool expandUncondBranchMMPseudo(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
const MCSubtargetInfo *STI);
- void expandMemInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
- const MCSubtargetInfo *STI, bool IsLoad);
+ void expandMem16Inst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+ const MCSubtargetInfo *STI, bool IsLoad);
+ void expandMem9Inst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+ const MCSubtargetInfo *STI, bool IsLoad);
bool expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
const MCSubtargetInfo *STI);
@@ -330,12 +335,14 @@ class MipsAsmParser : public MCTargetAsmParser {
bool expandMXTRAlias(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
const MCSubtargetInfo *STI);
+ bool expandSaaAddr(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+ const MCSubtargetInfo *STI);
+
bool reportParseError(Twine ErrorMsg);
bool reportParseError(SMLoc Loc, Twine ErrorMsg);
bool parseMemOffset(const MCExpr *&Res, bool isParenExpr);
- bool isEvaluated(const MCExpr *Expr);
bool parseSetMips0Directive();
bool parseSetArchDirective();
bool parseSetFeature(uint64_t Feature);
@@ -558,6 +565,19 @@ public:
return getSTI().getFeatureBits()[Mips::FeatureFP64Bit];
}
+ bool isJalrRelocAvailable(const MCExpr *JalExpr) {
+ if (!EmitJalrReloc)
+ return false;
+ MCValue Res;
+ if (!JalExpr->evaluateAsRelocatable(Res, nullptr, nullptr))
+ return false;
+ if (Res.getSymB() != nullptr)
+ return false;
+ if (Res.getConstant() != 0)
+ return ABI.IsN32() || ABI.IsN64();
+ return true;
+ }
+
const MipsABIInfo &getABI() const { return ABI; }
bool isABI_N32() const { return ABI.IsN32(); }
bool isABI_N64() const { return ABI.IsN64(); }
@@ -654,6 +674,10 @@ public:
return (getSTI().getFeatureBits()[Mips::FeatureCnMips]);
}
+ bool hasCnMipsP() const {
+ return (getSTI().getFeatureBits()[Mips::FeatureCnMipsP]);
+ }
+
bool inPicMode() {
return IsPicEnabled;
}
@@ -1295,8 +1319,6 @@ public:
}
// Allow relocation operators.
- // FIXME: This predicate and others need to look through binary expressions
- // and determine whether a Value is a constant or not.
template <unsigned Bits, unsigned ShiftAmount = 0>
bool isMemWithSimmOffset() const {
if (!isMem())
@@ -1777,17 +1799,71 @@ static unsigned countMCSymbolRefExpr(const MCExpr *Expr) {
return 0;
}
+static bool isEvaluated(const MCExpr *Expr) {
+ switch (Expr->getKind()) {
+ case MCExpr::Constant:
+ return true;
+ case MCExpr::SymbolRef:
+ return (cast<MCSymbolRefExpr>(Expr)->getKind() != MCSymbolRefExpr::VK_None);
+ case MCExpr::Binary: {
+ const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr);
+ if (!isEvaluated(BE->getLHS()))
+ return false;
+ return isEvaluated(BE->getRHS());
+ }
+ case MCExpr::Unary:
+ return isEvaluated(cast<MCUnaryExpr>(Expr)->getSubExpr());
+ case MCExpr::Target:
+ return true;
+ }
+ return false;
+}
+
+static bool needsExpandMemInst(MCInst &Inst) {
+ const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode());
+
+ unsigned NumOp = MCID.getNumOperands();
+ if (NumOp != 3 && NumOp != 4)
+ return false;
+
+ const MCOperandInfo &OpInfo = MCID.OpInfo[NumOp - 1];
+ if (OpInfo.OperandType != MCOI::OPERAND_MEMORY &&
+ OpInfo.OperandType != MCOI::OPERAND_UNKNOWN &&
+ OpInfo.OperandType != MipsII::OPERAND_MEM_SIMM9)
+ return false;
+
+ MCOperand &Op = Inst.getOperand(NumOp - 1);
+ if (Op.isImm()) {
+ if (OpInfo.OperandType == MipsII::OPERAND_MEM_SIMM9)
+ return !isInt<9>(Op.getImm());
+ // Offset can't exceed 16bit value.
+ return !isInt<16>(Op.getImm());
+ }
+
+ if (Op.isExpr()) {
+ const MCExpr *Expr = Op.getExpr();
+ if (Expr->getKind() != MCExpr::SymbolRef)
+ return !isEvaluated(Expr);
+
+ // Expand symbol.
+ const MCSymbolRefExpr *SR = static_cast<const MCSymbolRefExpr *>(Expr);
+ return SR->getKind() == MCSymbolRefExpr::VK_None;
+ }
+
+ return false;
+}
+
bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
MCStreamer &Out,
const MCSubtargetInfo *STI) {
MipsTargetStreamer &TOut = getTargetStreamer();
- const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode());
+ const unsigned Opcode = Inst.getOpcode();
+ const MCInstrDesc &MCID = getInstDesc(Opcode);
bool ExpandedJalSym = false;
Inst.setLoc(IDLoc);
if (MCID.isBranch() || MCID.isCall()) {
- const unsigned Opcode = Inst.getOpcode();
MCOperand Offset;
switch (Opcode) {
@@ -1901,14 +1977,13 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
// SSNOP is deprecated on MIPS32r6/MIPS64r6
// We still accept it but it is a normal nop.
- if (hasMips32r6() && Inst.getOpcode() == Mips::SSNOP) {
+ if (hasMips32r6() && Opcode == Mips::SSNOP) {
std::string ISA = hasMips64r6() ? "MIPS64r6" : "MIPS32r6";
Warning(IDLoc, "ssnop is deprecated for " + ISA + " and is equivalent to a "
"nop instruction");
}
if (hasCnMips()) {
- const unsigned Opcode = Inst.getOpcode();
MCOperand Opnd;
int Imm;
@@ -1958,7 +2033,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
// not in the operands.
unsigned FirstOp = 1;
unsigned SecondOp = 2;
- switch (Inst.getOpcode()) {
+ switch (Opcode) {
default:
break;
case Mips::SDivIMacro:
@@ -2004,8 +2079,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
}
// For PIC code convert unconditional jump to unconditional branch.
- if ((Inst.getOpcode() == Mips::J || Inst.getOpcode() == Mips::J_MM) &&
- inPicMode()) {
+ if ((Opcode == Mips::J || Opcode == Mips::J_MM) && inPicMode()) {
MCInst BInst;
BInst.setOpcode(inMicroMipsMode() ? Mips::BEQ_MM : Mips::BEQ);
BInst.addOperand(MCOperand::createReg(Mips::ZERO));
@@ -2016,8 +2090,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
// This expansion is not in a function called by tryExpandInstruction()
// because the pseudo-instruction doesn't have a distinct opcode.
- if ((Inst.getOpcode() == Mips::JAL || Inst.getOpcode() == Mips::JAL_MM) &&
- inPicMode()) {
+ if ((Opcode == Mips::JAL || Opcode == Mips::JAL_MM) && inPicMode()) {
warnIfNoMacro(IDLoc);
const MCExpr *JalExpr = Inst.getOperand(0).getExpr();
@@ -2031,62 +2104,19 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
// of the assembler. We ought to leave it to those later stages.
const MCSymbol *JalSym = getSingleMCSymbol(JalExpr);
- // FIXME: Add support for label+offset operands (currently causes an error).
- // FIXME: Add support for forward-declared local symbols.
- // FIXME: Add expansion for when the LargeGOT option is enabled.
- if (JalSym->isInSection() || JalSym->isTemporary() ||
- (JalSym->isELF() &&
- cast<MCSymbolELF>(JalSym)->getBinding() == ELF::STB_LOCAL)) {
- if (isABI_O32()) {
- // If it's a local symbol and the O32 ABI is being used, we expand to:
- // lw $25, 0($gp)
- // R_(MICRO)MIPS_GOT16 label
- // addiu $25, $25, 0
- // R_(MICRO)MIPS_LO16 label
- // jalr $25
- const MCExpr *Got16RelocExpr =
- MipsMCExpr::create(MipsMCExpr::MEK_GOT, JalExpr, getContext());
- const MCExpr *Lo16RelocExpr =
- MipsMCExpr::create(MipsMCExpr::MEK_LO, JalExpr, getContext());
-
- TOut.emitRRX(Mips::LW, Mips::T9, GPReg,
- MCOperand::createExpr(Got16RelocExpr), IDLoc, STI);
- TOut.emitRRX(Mips::ADDiu, Mips::T9, Mips::T9,
- MCOperand::createExpr(Lo16RelocExpr), IDLoc, STI);
- } else if (isABI_N32() || isABI_N64()) {
- // If it's a local symbol and the N32/N64 ABIs are being used,
- // we expand to:
- // lw/ld $25, 0($gp)
- // R_(MICRO)MIPS_GOT_DISP label
- // jalr $25
- const MCExpr *GotDispRelocExpr =
- MipsMCExpr::create(MipsMCExpr::MEK_GOT_DISP, JalExpr, getContext());
-
- TOut.emitRRX(ABI.ArePtrs64bit() ? Mips::LD : Mips::LW, Mips::T9,
- GPReg, MCOperand::createExpr(GotDispRelocExpr), IDLoc,
- STI);
- }
- } else {
- // If it's an external/weak symbol, we expand to:
- // lw/ld $25, 0($gp)
- // R_(MICRO)MIPS_CALL16 label
- // jalr $25
- const MCExpr *Call16RelocExpr =
- MipsMCExpr::create(MipsMCExpr::MEK_GOT_CALL, JalExpr, getContext());
-
- TOut.emitRRX(ABI.ArePtrs64bit() ? Mips::LD : Mips::LW, Mips::T9, GPReg,
- MCOperand::createExpr(Call16RelocExpr), IDLoc, STI);
- }
+ if (expandLoadAddress(Mips::T9, Mips::NoRegister, Inst.getOperand(0),
+ !isGP64bit(), IDLoc, Out, STI))
+ return true;
MCInst JalrInst;
- if (IsCpRestoreSet && inMicroMipsMode())
- JalrInst.setOpcode(Mips::JALRS_MM);
+ if (inMicroMipsMode())
+ JalrInst.setOpcode(IsCpRestoreSet ? Mips::JALRS_MM : Mips::JALR_MM);
else
- JalrInst.setOpcode(inMicroMipsMode() ? Mips::JALR_MM : Mips::JALR);
+ JalrInst.setOpcode(Mips::JALR);
JalrInst.addOperand(MCOperand::createReg(Mips::RA));
JalrInst.addOperand(MCOperand::createReg(Mips::T9));
- if (EmitJalrReloc) {
+ if (isJalrRelocAvailable(JalExpr)) {
// As an optimization hint for the linker, before the JALR we add:
// .reloc tmplabel, R_{MICRO}MIPS_JALR, symbol
// tmplabel:
@@ -2106,43 +2136,25 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
ExpandedJalSym = true;
}
- bool IsPCRelativeLoad = (MCID.TSFlags & MipsII::IsPCRelativeLoad) != 0;
- if ((MCID.mayLoad() || MCID.mayStore()) && !IsPCRelativeLoad) {
+ if (MCID.mayLoad() || MCID.mayStore()) {
// Check the offset of memory operand, if it is a symbol
// reference or immediate we may have to expand instructions.
- for (unsigned i = 0; i < MCID.getNumOperands(); i++) {
- const MCOperandInfo &OpInfo = MCID.OpInfo[i];
- if ((OpInfo.OperandType == MCOI::OPERAND_MEMORY) ||
- (OpInfo.OperandType == MCOI::OPERAND_UNKNOWN)) {
- MCOperand &Op = Inst.getOperand(i);
- if (Op.isImm()) {
- int64_t MemOffset = Op.getImm();
- if (MemOffset < -32768 || MemOffset > 32767) {
- // Offset can't exceed 16bit value.
- expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad());
- return getParser().hasPendingError();
- }
- } else if (Op.isExpr()) {
- const MCExpr *Expr = Op.getExpr();
- if (Expr->getKind() == MCExpr::SymbolRef) {
- const MCSymbolRefExpr *SR =
- static_cast<const MCSymbolRefExpr *>(Expr);
- if (SR->getKind() == MCSymbolRefExpr::VK_None) {
- // Expand symbol.
- expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad());
- return getParser().hasPendingError();
- }
- } else if (!isEvaluated(Expr)) {
- expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad());
- return getParser().hasPendingError();
- }
- }
+ if (needsExpandMemInst(Inst)) {
+ const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode());
+ switch (MCID.OpInfo[MCID.getNumOperands() - 1].OperandType) {
+ case MipsII::OPERAND_MEM_SIMM9:
+ expandMem9Inst(Inst, IDLoc, Out, STI, MCID.mayLoad());
+ break;
+ default:
+ expandMem16Inst(Inst, IDLoc, Out, STI, MCID.mayLoad());
+ break;
}
- } // for
- } // if load/store
+ return getParser().hasPendingError();
+ }
+ }
if (inMicroMipsMode()) {
- if (MCID.mayLoad() && Inst.getOpcode() != Mips::LWP_MM) {
+ if (MCID.mayLoad() && Opcode != Mips::LWP_MM) {
// Try to create 16-bit GP relative load instruction.
for (unsigned i = 0; i < MCID.getNumOperands(); i++) {
const MCOperandInfo &OpInfo = MCID.OpInfo[i];
@@ -2173,7 +2185,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
MCOperand Opnd;
int Imm;
- switch (Inst.getOpcode()) {
+ switch (Opcode) {
default:
break;
case Mips::ADDIUSP_MM:
@@ -2321,8 +2333,8 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
TOut.emitDirectiveSetReorder();
}
- if ((Inst.getOpcode() == Mips::JalOneReg ||
- Inst.getOpcode() == Mips::JalTwoReg || ExpandedJalSym) &&
+ if ((Opcode == Mips::JalOneReg || Opcode == Mips::JalTwoReg ||
+ ExpandedJalSym) &&
isPicAndNotNxxAbi()) {
if (IsCpRestoreSet) {
// We need a NOP between the JALR and the LW:
@@ -2586,6 +2598,9 @@ MipsAsmParser::tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
case Mips::MFTHC1: case Mips::MTTHC1:
case Mips::CFTC1: case Mips::CTTC1:
return expandMXTRAlias(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success;
+ case Mips::SaaAddr:
+ case Mips::SaadAddr:
+ return expandSaaAddr(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success;
}
}
@@ -2837,13 +2852,9 @@ bool MipsAsmParser::expandLoadAddress(unsigned DstReg, unsigned BaseReg,
const MCSubtargetInfo *STI) {
// la can't produce a usable address when addresses are 64-bit.
if (Is32BitAddress && ABI.ArePtrs64bit()) {
- // FIXME: Demote this to a warning and continue as if we had 'dla' instead.
- // We currently can't do this because we depend on the equality
- // operator and N64 can end up with a GPR32/GPR64 mismatch.
- Error(IDLoc, "la used to load 64-bit address");
+ Warning(IDLoc, "la used to load 64-bit address");
// Continue as if we had 'dla' instead.
Is32BitAddress = false;
- return true;
}
// dla requires 64-bit addresses.
@@ -2933,6 +2944,9 @@ bool MipsAsmParser::loadAndAddSymbolAddress(const MCExpr *SymExpr,
TmpReg = ATReg;
}
+ // FIXME: In case of N32 / N64 ABI and emabled XGOT, local addresses
+ // loaded using R_MIPS_GOT_PAGE / R_MIPS_GOT_OFST pair of relocations.
+ // FIXME: Implement XGOT for microMIPS.
if (UseXGOT) {
// Loading address from XGOT
// External GOT: lui $tmp, %got_hi(symbol)($gp)
@@ -2969,7 +2983,7 @@ bool MipsAsmParser::loadAndAddSymbolAddress(const MCExpr *SymExpr,
const MipsMCExpr *GotExpr = nullptr;
const MCExpr *LoExpr = nullptr;
- if (IsPtr64) {
+ if (ABI.IsN32() || ABI.IsN64()) {
// The remaining cases are:
// Small offset: ld $tmp, %got_disp(symbol)($gp)
// >daddiu $tmp, $tmp, offset
@@ -3079,7 +3093,7 @@ bool MipsAsmParser::loadAndAddSymbolAddress(const MCExpr *SymExpr,
TOut.emitRRR(Mips::DADDu, DstReg, ATReg, SrcReg, IDLoc, STI);
return false;
- } else if (canUseATReg() && !RdRegIsRsReg) {
+ } else if (canUseATReg() && !RdRegIsRsReg && DstReg != getATReg(IDLoc)) {
unsigned ATReg = getATReg(IDLoc);
// If the $rs is different from $rd or if $rs isn't specified and we
@@ -3106,7 +3120,8 @@ bool MipsAsmParser::loadAndAddSymbolAddress(const MCExpr *SymExpr,
TOut.emitRRR(Mips::DADDu, DstReg, DstReg, SrcReg, IDLoc, STI);
return false;
- } else if (!canUseATReg() && !RdRegIsRsReg) {
+ } else if ((!canUseATReg() && !RdRegIsRsReg) ||
+ (canUseATReg() && DstReg == getATReg(IDLoc))) {
// Otherwise, synthesize the address in the destination register
// serially:
// (d)la $rd, sym/sym($rs) => lui $rd, %highest(sym)
@@ -3631,20 +3646,26 @@ bool MipsAsmParser::expandBranchImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
return false;
}
-void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
- const MCSubtargetInfo *STI, bool IsLoad) {
- const MCOperand &DstRegOp = Inst.getOperand(0);
+void MipsAsmParser::expandMem16Inst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+ const MCSubtargetInfo *STI, bool IsLoad) {
+ unsigned NumOp = Inst.getNumOperands();
+ assert((NumOp == 3 || NumOp == 4) && "unexpected operands number");
+ unsigned StartOp = NumOp == 3 ? 0 : 1;
+
+ const MCOperand &DstRegOp = Inst.getOperand(StartOp);
assert(DstRegOp.isReg() && "expected register operand kind");
- const MCOperand &BaseRegOp = Inst.getOperand(1);
+ const MCOperand &BaseRegOp = Inst.getOperand(StartOp + 1);
assert(BaseRegOp.isReg() && "expected register operand kind");
+ const MCOperand &OffsetOp = Inst.getOperand(StartOp + 2);
MipsTargetStreamer &TOut = getTargetStreamer();
+ unsigned OpCode = Inst.getOpcode();
unsigned DstReg = DstRegOp.getReg();
unsigned BaseReg = BaseRegOp.getReg();
unsigned TmpReg = DstReg;
- const MCInstrDesc &Desc = getInstDesc(Inst.getOpcode());
- int16_t DstRegClass = Desc.OpInfo[0].RegClass;
+ const MCInstrDesc &Desc = getInstDesc(OpCode);
+ int16_t DstRegClass = Desc.OpInfo[StartOp].RegClass;
unsigned DstRegClassID =
getContext().getRegisterInfo()->getRegClass(DstRegClass).getID();
bool IsGPR = (DstRegClassID == Mips::GPR32RegClassID) ||
@@ -3658,25 +3679,12 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
return;
}
- if (Inst.getNumOperands() > 3) {
- const MCOperand &BaseRegOp = Inst.getOperand(2);
- assert(BaseRegOp.isReg() && "expected register operand kind");
- const MCOperand &ExprOp = Inst.getOperand(3);
- assert(ExprOp.isExpr() && "expected expression oprand kind");
-
- unsigned BaseReg = BaseRegOp.getReg();
- const MCExpr *ExprOffset = ExprOp.getExpr();
-
- MCOperand LoOperand = MCOperand::createExpr(
- MipsMCExpr::create(MipsMCExpr::MEK_LO, ExprOffset, getContext()));
- MCOperand HiOperand = MCOperand::createExpr(
- MipsMCExpr::create(MipsMCExpr::MEK_HI, ExprOffset, getContext()));
- TOut.emitSCWithSymOffset(Inst.getOpcode(), DstReg, BaseReg, HiOperand,
- LoOperand, TmpReg, IDLoc, STI);
- return;
- }
-
- const MCOperand &OffsetOp = Inst.getOperand(2);
+ auto emitInstWithOffset = [&](const MCOperand &Off) {
+ if (NumOp == 3)
+ TOut.emitRRX(OpCode, DstReg, TmpReg, Off, IDLoc, STI);
+ else
+ TOut.emitRRRX(OpCode, DstReg, DstReg, TmpReg, Off, IDLoc, STI);
+ };
if (OffsetOp.isImm()) {
int64_t LoOffset = OffsetOp.getImm() & 0xffff;
@@ -3690,16 +3698,16 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
bool IsLargeOffset = HiOffset != 0;
if (IsLargeOffset) {
- bool Is32BitImm = (HiOffset >> 32) == 0;
+ bool Is32BitImm = isInt<32>(OffsetOp.getImm());
if (loadImmediate(HiOffset, TmpReg, Mips::NoRegister, Is32BitImm, true,
IDLoc, Out, STI))
return;
}
if (BaseReg != Mips::ZERO && BaseReg != Mips::ZERO_64)
- TOut.emitRRR(isGP64bit() ? Mips::DADDu : Mips::ADDu, TmpReg, TmpReg,
- BaseReg, IDLoc, STI);
- TOut.emitRRI(Inst.getOpcode(), DstReg, TmpReg, LoOffset, IDLoc, STI);
+ TOut.emitRRR(ABI.ArePtrs64bit() ? Mips::DADDu : Mips::ADDu, TmpReg,
+ TmpReg, BaseReg, IDLoc, STI);
+ emitInstWithOffset(MCOperand::createImm(int16_t(LoOffset)));
return;
}
@@ -3723,26 +3731,41 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
loadAndAddSymbolAddress(Res.getSymA(), TmpReg, BaseReg,
!ABI.ArePtrs64bit(), IDLoc, Out, STI);
- TOut.emitRRI(Inst.getOpcode(), DstReg, TmpReg, Res.getConstant(), IDLoc,
- STI);
+ emitInstWithOffset(MCOperand::createImm(int16_t(Res.getConstant())));
} else {
// FIXME: Implement 64-bit case.
// 1) lw $8, sym => lui $8, %hi(sym)
// lw $8, %lo(sym)($8)
// 2) sw $8, sym => lui $at, %hi(sym)
// sw $8, %lo(sym)($at)
- const MCExpr *ExprOffset = OffsetOp.getExpr();
+ const MCExpr *OffExpr = OffsetOp.getExpr();
MCOperand LoOperand = MCOperand::createExpr(
- MipsMCExpr::create(MipsMCExpr::MEK_LO, ExprOffset, getContext()));
+ MipsMCExpr::create(MipsMCExpr::MEK_LO, OffExpr, getContext()));
MCOperand HiOperand = MCOperand::createExpr(
- MipsMCExpr::create(MipsMCExpr::MEK_HI, ExprOffset, getContext()));
-
- // Generate the base address in TmpReg.
- TOut.emitRX(Mips::LUi, TmpReg, HiOperand, IDLoc, STI);
- if (BaseReg != Mips::ZERO)
- TOut.emitRRR(Mips::ADDu, TmpReg, TmpReg, BaseReg, IDLoc, STI);
- // Emit the load or store with the adjusted base and offset.
- TOut.emitRRX(Inst.getOpcode(), DstReg, TmpReg, LoOperand, IDLoc, STI);
+ MipsMCExpr::create(MipsMCExpr::MEK_HI, OffExpr, getContext()));
+
+ if (ABI.IsN64()) {
+ MCOperand HighestOperand = MCOperand::createExpr(
+ MipsMCExpr::create(MipsMCExpr::MEK_HIGHEST, OffExpr, getContext()));
+ MCOperand HigherOperand = MCOperand::createExpr(
+ MipsMCExpr::create(MipsMCExpr::MEK_HIGHER, OffExpr, getContext()));
+
+ TOut.emitRX(Mips::LUi, TmpReg, HighestOperand, IDLoc, STI);
+ TOut.emitRRX(Mips::DADDiu, TmpReg, TmpReg, HigherOperand, IDLoc, STI);
+ TOut.emitRRI(Mips::DSLL, TmpReg, TmpReg, 16, IDLoc, STI);
+ TOut.emitRRX(Mips::DADDiu, TmpReg, TmpReg, HiOperand, IDLoc, STI);
+ TOut.emitRRI(Mips::DSLL, TmpReg, TmpReg, 16, IDLoc, STI);
+ if (BaseReg != Mips::ZERO && BaseReg != Mips::ZERO_64)
+ TOut.emitRRR(Mips::DADDu, TmpReg, TmpReg, BaseReg, IDLoc, STI);
+ emitInstWithOffset(LoOperand);
+ } else {
+ // Generate the base address in TmpReg.
+ TOut.emitRX(Mips::LUi, TmpReg, HiOperand, IDLoc, STI);
+ if (BaseReg != Mips::ZERO)
+ TOut.emitRRR(Mips::ADDu, TmpReg, TmpReg, BaseReg, IDLoc, STI);
+ // Emit the load or store with the adjusted base and offset.
+ emitInstWithOffset(LoOperand);
+ }
}
return;
}
@@ -3750,6 +3773,64 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
llvm_unreachable("unexpected operand type");
}
+void MipsAsmParser::expandMem9Inst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+ const MCSubtargetInfo *STI, bool IsLoad) {
+ unsigned NumOp = Inst.getNumOperands();
+ assert((NumOp == 3 || NumOp == 4) && "unexpected operands number");
+ unsigned StartOp = NumOp == 3 ? 0 : 1;
+
+ const MCOperand &DstRegOp = Inst.getOperand(StartOp);
+ assert(DstRegOp.isReg() && "expected register operand kind");
+ const MCOperand &BaseRegOp = Inst.getOperand(StartOp + 1);
+ assert(BaseRegOp.isReg() && "expected register operand kind");
+ const MCOperand &OffsetOp = Inst.getOperand(StartOp + 2);
+
+ MipsTargetStreamer &TOut = getTargetStreamer();
+ unsigned OpCode = Inst.getOpcode();
+ unsigned DstReg = DstRegOp.getReg();
+ unsigned BaseReg = BaseRegOp.getReg();
+ unsigned TmpReg = DstReg;
+
+ const MCInstrDesc &Desc = getInstDesc(OpCode);
+ int16_t DstRegClass = Desc.OpInfo[StartOp].RegClass;
+ unsigned DstRegClassID =
+ getContext().getRegisterInfo()->getRegClass(DstRegClass).getID();
+ bool IsGPR = (DstRegClassID == Mips::GPR32RegClassID) ||
+ (DstRegClassID == Mips::GPR64RegClassID);
+
+ if (!IsLoad || !IsGPR || (BaseReg == DstReg)) {
+ // At this point we need AT to perform the expansions
+ // and we exit if it is not available.
+ TmpReg = getATReg(IDLoc);
+ if (!TmpReg)
+ return;
+ }
+
+ auto emitInst = [&]() {
+ if (NumOp == 3)
+ TOut.emitRRX(OpCode, DstReg, TmpReg, MCOperand::createImm(0), IDLoc, STI);
+ else
+ TOut.emitRRRX(OpCode, DstReg, DstReg, TmpReg, MCOperand::createImm(0),
+ IDLoc, STI);
+ };
+
+ if (OffsetOp.isImm()) {
+ loadImmediate(OffsetOp.getImm(), TmpReg, BaseReg, !ABI.ArePtrs64bit(), true,
+ IDLoc, Out, STI);
+ emitInst();
+ return;
+ }
+
+ if (OffsetOp.isExpr()) {
+ loadAndAddSymbolAddress(OffsetOp.getExpr(), TmpReg, BaseReg,
+ !ABI.ArePtrs64bit(), IDLoc, Out, STI);
+ emitInst();
+ return;
+ }
+
+ llvm_unreachable("unexpected operand type");
+}
+
bool MipsAsmParser::expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc,
MCStreamer &Out,
const MCSubtargetInfo *STI) {
@@ -4051,8 +4132,8 @@ bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc,
// D(S)DivMacro.
bool MipsAsmParser::expandDivRem(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
- const MCSubtargetInfo *STI, const bool IsMips64,
- const bool Signed) {
+ const MCSubtargetInfo *STI,
+ const bool IsMips64, const bool Signed) {
MipsTargetStreamer &TOut = getTargetStreamer();
warnIfNoMacro(IDLoc);
@@ -5450,6 +5531,39 @@ bool MipsAsmParser::expandMXTRAlias(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
return false;
}
+bool MipsAsmParser::expandSaaAddr(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+ const MCSubtargetInfo *STI) {
+ assert(Inst.getNumOperands() == 3 && "expected three operands");
+ assert(Inst.getOperand(0).isReg() && "expected register operand kind");
+ assert(Inst.getOperand(1).isReg() && "expected register operand kind");
+
+ warnIfNoMacro(IDLoc);
+
+ MipsTargetStreamer &TOut = getTargetStreamer();
+ unsigned Opcode = Inst.getOpcode() == Mips::SaaAddr ? Mips::SAA : Mips::SAAD;
+ unsigned RtReg = Inst.getOperand(0).getReg();
+ unsigned BaseReg = Inst.getOperand(1).getReg();
+ const MCOperand &BaseOp = Inst.getOperand(2);
+
+ if (BaseOp.isImm()) {
+ int64_t ImmValue = BaseOp.getImm();
+ if (ImmValue == 0) {
+ TOut.emitRR(Opcode, RtReg, BaseReg, IDLoc, STI);
+ return false;
+ }
+ }
+
+ unsigned ATReg = getATReg(IDLoc);
+ if (!ATReg)
+ return true;
+
+ if (expandLoadAddress(ATReg, BaseReg, BaseOp, !isGP64bit(), IDLoc, Out, STI))
+ return true;
+
+ TOut.emitRR(Opcode, RtReg, ATReg, IDLoc, STI);
+ return false;
+}
+
unsigned
MipsAsmParser::checkEarlyTargetMatchPredicate(MCInst &Inst,
const OperandVector &Operands) {
@@ -6086,26 +6200,6 @@ bool MipsAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
return true;
}
-bool MipsAsmParser::isEvaluated(const MCExpr *Expr) {
- switch (Expr->getKind()) {
- case MCExpr::Constant:
- return true;
- case MCExpr::SymbolRef:
- return (cast<MCSymbolRefExpr>(Expr)->getKind() != MCSymbolRefExpr::VK_None);
- case MCExpr::Binary: {
- const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr);
- if (!isEvaluated(BE->getLHS()))
- return false;
- return isEvaluated(BE->getRHS());
- }
- case MCExpr::Unary:
- return isEvaluated(cast<MCUnaryExpr>(Expr)->getSubExpr());
- case MCExpr::Target:
- return true;
- }
- return false;
-}
-
bool MipsAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
SMLoc &EndLoc) {
SmallVector<std::unique_ptr<MCParsedAsmOperand>, 1> Operands;
@@ -7168,8 +7262,8 @@ bool MipsAsmParser::parseSetArchDirective() {
return reportParseError("unexpected token, expected equals sign");
Parser.Lex();
- StringRef Arch;
- if (Parser.parseIdentifier(Arch))
+ StringRef Arch = getParser().parseStringToEndOfStatement().trim();
+ if (Arch.empty())
return reportParseError("expected arch identifier");
StringRef ArchFeatureName =
@@ -7190,6 +7284,7 @@ bool MipsAsmParser::parseSetArchDirective() {
.Case("mips64r5", "mips64r5")
.Case("mips64r6", "mips64r6")
.Case("octeon", "cnmips")
+ .Case("octeon+", "cnmipsp")
.Case("r4000", "mips3") // This is an implementation of Mips3.
.Default("");
@@ -8550,7 +8645,7 @@ bool MipsAsmParser::parseInternalDirectiveReallowModule() {
return false;
}
-extern "C" void LLVMInitializeMipsAsmParser() {
+extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeMipsAsmParser() {
RegisterMCAsmParser<MipsAsmParser> X(getTheMipsTarget());
RegisterMCAsmParser<MipsAsmParser> Y(getTheMipselTarget());
RegisterMCAsmParser<MipsAsmParser> A(getTheMips64Target());