diff options
Diffstat (limited to 'llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp')
-rw-r--r-- | llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp | 443 |
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()); |