diff options
author | Visa Hankala <visa@cvs.openbsd.org> | 2019-06-24 13:44:22 +0000 |
---|---|---|
committer | Visa Hankala <visa@cvs.openbsd.org> | 2019-06-24 13:44:22 +0000 |
commit | dfbbd98e37070e0b93199f19be82fe03b42f0cff (patch) | |
tree | 2521ad103f02c6c5712e2668ed2bfc10474162fd /gnu/llvm | |
parent | 3b4164c21b061e88ece17f61147b895f61a41f85 (diff) |
Fix a bug in memory operand handling. If a load or store uses a symbol
as a memory operand, the assembler generates incorrect relocations in
PIC mode. As a simple fix, expand the instruction into an address load
sequence, which works, that is followed by the actual memory
instruction.
Note that the generated sequence is not always optimal. If the symbol
has a small offset, the offset could be fused with the memory
instruction. The fix does not achieve that, however. A symbol offset
adds an extra instruction.
Diffstat (limited to 'gnu/llvm')
-rw-r--r-- | gnu/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp | 4869 |
1 files changed, 3449 insertions, 1420 deletions
diff --git a/gnu/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/gnu/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index d4e061f00d3..9f93fb68871 100644 --- a/gnu/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/gnu/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -7,45 +7,71 @@ // //===----------------------------------------------------------------------===// +#include "MCTargetDesc/MipsABIFlagsSection.h" #include "MCTargetDesc/MipsABIInfo.h" +#include "MCTargetDesc/MipsBaseInfo.h" #include "MCTargetDesc/MipsMCExpr.h" #include "MCTargetDesc/MipsMCTargetDesc.h" -#include "MipsRegisterInfo.h" -#include "MipsTargetObjectFile.h" #include "MipsTargetStreamer.h" -#include "llvm/ADT/APInt.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" -#include "llvm/MC/MCInstBuilder.h" +#include "llvm/MC/MCInstrDesc.h" +#include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCParser/MCAsmParserExtension.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCParser/MCTargetAsmParser.h" +#include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" -#include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/MC/MCSymbolELF.h" +#include "llvm/MC/MCValue.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstdint> #include <memory> +#include <string> +#include <utility> using namespace llvm; #define DEBUG_TYPE "mips-asm-parser" namespace llvm { + class MCInstrInfo; -} + +} // end namespace llvm + +extern cl::opt<bool> EmitJalrReloc; namespace { + class MipsAssemblerOptions { public: - MipsAssemblerOptions(const FeatureBitset &Features_) : - ATReg(1), Reorder(true), Macro(true), Features(Features_) {} + MipsAssemblerOptions(const FeatureBitset &Features_) : Features(Features_) {} MipsAssemblerOptions(const MipsAssemblerOptions *Opts) { ATReg = Opts->getATRegIndex(); @@ -82,12 +108,13 @@ public: static const FeatureBitset AllArchRelatedMask; private: - unsigned ATReg; - bool Reorder; - bool Macro; + unsigned ATReg = 1; + bool Reorder = true; + bool Macro = true; FeatureBitset Features; }; -} + +} // end anonymous namespace const FeatureBitset MipsAssemblerOptions::AllArchRelatedMask = { Mips::FeatureMips1, Mips::FeatureMips2, Mips::FeatureMips3, @@ -101,6 +128,7 @@ const FeatureBitset MipsAssemblerOptions::AllArchRelatedMask = { }; namespace { + class MipsAsmParser : public MCTargetAsmParser { MipsTargetStreamer &getTargetStreamer() { MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer(); @@ -121,13 +149,21 @@ class MipsAsmParser : public MCTargetAsmParser { /// If true, then CpSaveLocation is a register, otherwise it's an offset. bool CpSaveLocationIsRegister; + // Map of register aliases created via the .set directive. + StringMap<AsmToken> RegisterSets; + // Print a warning along with its fix-it message at the given range. void printWarningWithFixIt(const Twine &Msg, const Twine &FixMsg, SMRange Range, bool ShowColors = true); + void ConvertXWPOperands(MCInst &Inst, const OperandVector &Operands); + #define GET_ASSEMBLER_HEADER #include "MipsGenAsmMatcher.inc" + unsigned + checkEarlyTargetMatchPredicate(MCInst &Inst, + const OperandVector &Operands) override; unsigned checkTargetMatchPredicate(MCInst &Inst) override; bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, @@ -142,6 +178,8 @@ class MipsAsmParser : public MCTargetAsmParser { bool parseBracketSuffix(StringRef Name, OperandVector &Operands); + bool mnemonicIsValid(StringRef Mnemonic, unsigned VariantID); + bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) override; @@ -152,14 +190,14 @@ class MipsAsmParser : public MCTargetAsmParser { matchAnyRegisterNameWithoutDollar(OperandVector &Operands, StringRef Identifier, SMLoc S); OperandMatchResultTy matchAnyRegisterWithoutDollar(OperandVector &Operands, + const AsmToken &Token, + SMLoc S); + OperandMatchResultTy matchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S); OperandMatchResultTy parseAnyRegister(OperandVector &Operands); OperandMatchResultTy parseImm(OperandVector &Operands); OperandMatchResultTy parseJumpTarget(OperandVector &Operands); OperandMatchResultTy parseInvNum(OperandVector &Operands); - OperandMatchResultTy parseLSAImm(OperandVector &Operands); - OperandMatchResultTy parseRegisterPair(OperandVector &Operands); - OperandMatchResultTy parseMovePRegPair(OperandVector &Operands); OperandMatchResultTy parseRegisterList(OperandVector &Operands); bool searchSymbolAlias(OperandVector &Operands); @@ -173,82 +211,109 @@ class MipsAsmParser : public MCTargetAsmParser { }; // Expands assembly pseudo instructions. - MacroExpanderResultTy - tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions); + MacroExpanderResultTy tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, + MCStreamer &Out, + const MCSubtargetInfo *STI); - bool expandJalWithRegs(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions); + bool expandJalWithRegs(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); bool loadImmediate(int64_t ImmValue, unsigned DstReg, unsigned SrcReg, bool Is32BitImm, bool IsAddress, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions); + MCStreamer &Out, const MCSubtargetInfo *STI); bool loadAndAddSymbolAddress(const MCExpr *SymExpr, unsigned DstReg, unsigned SrcReg, bool Is32BitSym, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions); + MCStreamer &Out, const MCSubtargetInfo *STI); + + bool emitPartialAddress(MipsTargetStreamer &TOut, SMLoc IDLoc, MCSymbol *Sym); bool expandLoadImm(MCInst &Inst, bool Is32BitImm, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions); + MCStreamer &Out, const MCSubtargetInfo *STI); + + bool expandLoadImmReal(MCInst &Inst, bool IsSingle, bool IsGPR, bool Is64FPU, + SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); bool expandLoadAddress(unsigned DstReg, unsigned BaseReg, const MCOperand &Offset, bool Is32BitAddress, - SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions); + SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); + + bool expandUncondBranchMMPseudo(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); + + void expandMemInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI, bool IsLoad); - bool expandUncondBranchMMPseudo(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions); + bool expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); - void expandMemInst(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions, bool isLoad, - bool isImmOpnd); + bool expandAliasImmediate(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); - bool expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions); + bool expandBranchImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); - bool expandAliasImmediate(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions); + bool expandCondBranches(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); - bool expandBranchImm(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions); + bool expandDivRem(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI, const bool IsMips64, + const bool Signed); - bool expandCondBranches(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions); + bool expandTrunc(MCInst &Inst, bool IsDouble, bool Is64FPU, SMLoc IDLoc, + MCStreamer &Out, const MCSubtargetInfo *STI); - bool expandDiv(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions, const bool IsMips64, - const bool Signed); + bool expandUlh(MCInst &Inst, bool Signed, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); - bool expandUlh(MCInst &Inst, bool Signed, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions); + bool expandUsh(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); - bool expandUlw(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions); + bool expandUxw(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); bool expandRotation(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions); - bool expandRotationImm(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions); - bool expandDRotation(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions); - bool expandDRotationImm(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions); + MCStreamer &Out, const MCSubtargetInfo *STI); + bool expandRotationImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); + bool expandDRotation(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); + bool expandDRotationImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); + + bool expandAbs(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); + + bool expandMulImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); + + bool expandMulO(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); + + bool expandMulOU(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); + + bool expandDMULMacro(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); - void createNop(bool hasShortDelaySlot, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions); + bool expandLoadStoreDMacro(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI, bool IsLoad); - void createAddu(unsigned DstReg, unsigned SrcReg, unsigned TrgReg, - bool Is64Bit, SmallVectorImpl<MCInst> &Instructions); + bool expandSeq(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); - void createCpRestoreMemOp(bool IsLoad, int StackOffset, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions); + bool expandSeqI(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); + + bool expandMXTRAlias(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 parseRelocOperand(const MCExpr *&Res); - - const MCExpr *evaluateRelocExpr(const MCExpr *Expr, StringRef RelocStr); bool isEvaluated(const MCExpr *Expr); bool parseSetMips0Directive(); @@ -263,6 +328,8 @@ class MipsAsmParser : public MCTargetAsmParser { bool parseDirectiveSet(); bool parseDirectiveOption(); bool parseInsnDirective(); + bool parseRSectionDirective(StringRef Section); + bool parseSSectionDirective(StringRef Section, unsigned Type); bool parseSetAtDirective(); bool parseSetNoAtDirective(); @@ -282,12 +349,20 @@ class MipsAsmParser : public MCTargetAsmParser { bool parseSetPushDirective(); bool parseSetSoftFloatDirective(); bool parseSetHardFloatDirective(); + bool parseSetMtDirective(); + bool parseSetNoMtDirective(); + bool parseSetNoCRCDirective(); + bool parseSetNoVirtDirective(); + bool parseSetNoGINVDirective(); bool parseSetAssignment(); - bool parseDataDirective(unsigned Size, SMLoc L); bool parseDirectiveGpWord(); bool parseDirectiveGpDWord(); + bool parseDirectiveDtpRelWord(); + bool parseDirectiveDtpRelDWord(); + bool parseDirectiveTpRelWord(); + bool parseDirectiveTpRelDWord(); bool parseDirectiveModule(); bool parseDirectiveModuleFP(); bool parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI, @@ -295,16 +370,12 @@ class MipsAsmParser : public MCTargetAsmParser { bool parseInternalDirectiveReallowModule(); - MCSymbolRefExpr::VariantKind getVariantKind(StringRef Symbol); - bool eatComma(StringRef ErrorStr); int matchCPURegisterName(StringRef Symbol); int matchHWRegsRegisterName(StringRef Symbol); - int matchRegisterByNumber(unsigned RegNum, unsigned RegClass); - int matchFPURegisterName(StringRef Name); int matchFCCRegisterName(StringRef Name); @@ -317,15 +388,15 @@ class MipsAsmParser : public MCTargetAsmParser { unsigned getReg(int RC, int RegNo); - unsigned getGPR(int RegNo); - /// Returns the internal register number for the current AT. Also checks if /// the current AT is unavailable (set to $0) and gives an error if it is. /// This should be used in pseudo-instruction expansions which need AT. unsigned getATReg(SMLoc Loc); - bool processInstruction(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions); + bool canUseATReg(); + + bool processInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); // Helper function that checks if the value of a vector index is within the // boundaries of accepted values for each RegisterKind @@ -395,6 +466,15 @@ class MipsAsmParser : public MCTargetAsmParser { public: enum MipsMatchResultTy { Match_RequiresDifferentSrcAndDst = FIRST_TARGET_MATCH_RESULT_TY, + Match_RequiresDifferentOperands, + Match_RequiresNoZeroRegister, + Match_RequiresSameSrcAndDst, + Match_NoFCCRegisterForCurrentISA, + Match_NonZeroOperandForSync, + Match_NonZeroOperandForMTCX, + Match_RequiresPosSizeRange0_32, + Match_RequiresPosSizeRange33_64, + Match_RequiresPosSizeUImm6, #define GET_OPERAND_DIAGNOSTIC_TYPES #include "MipsGenAsmMatcher.inc" #undef GET_OPERAND_DIAGNOSTIC_TYPES @@ -402,12 +482,15 @@ public: MipsAsmParser(const MCSubtargetInfo &sti, MCAsmParser &parser, const MCInstrInfo &MII, const MCTargetOptions &Options) - : MCTargetAsmParser(Options, sti), + : MCTargetAsmParser(Options, sti, MII), ABI(MipsABIInfo::computeTargetABI(Triple(sti.getTargetTriple()), sti.getCPU(), Options)) { MCAsmParserExtension::Initialize(parser); parser.addAliasForDirective(".asciiz", ".asciz"); + parser.addAliasForDirective(".hword", ".2byte"); + parser.addAliasForDirective(".word", ".4byte"); + parser.addAliasForDirective(".dword", ".8byte"); // Initialize the set of available features. setAvailableFeatures(ComputeAvailableFeatures(getSTI().getFeatureBits())); @@ -427,18 +510,19 @@ public: CurrentFn = nullptr; - IsPicEnabled = - (getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_); + IsPicEnabled = getContext().getObjectFileInfo()->isPositionIndependent(); IsCpRestoreSet = false; CpRestoreOffset = -1; - Triple TheTriple(sti.getTargetTriple()); - if ((TheTriple.getArch() == Triple::mips) || - (TheTriple.getArch() == Triple::mips64)) - IsLittleEndian = false; - else - IsLittleEndian = true; + const Triple &TheTriple = sti.getTargetTriple(); + IsLittleEndian = TheTriple.isLittleEndian(); + + if (getSTI().getCPU() == "mips64r6" && inMicroMipsMode()) + report_fatal_error("microMIPS64R6 is not supported", false); + + if (!isABI_O32() && inMicroMipsMode()) + report_fatal_error("microMIPS64 is not supported", false); } /// True if all of $fcc0 - $fcc7 exist for the current ISA. @@ -447,9 +531,11 @@ public: bool isGP64bit() const { return getSTI().getFeatureBits()[Mips::FeatureGP64Bit]; } + bool isFP64bit() const { return getSTI().getFeatureBits()[Mips::FeatureFP64Bit]; } + const MipsABIInfo &getABI() const { return ABI; } bool isABI_N32() const { return ABI.IsN32(); } bool isABI_N64() const { return ABI.IsN64(); } @@ -465,48 +551,63 @@ public: bool inMicroMipsMode() const { return getSTI().getFeatureBits()[Mips::FeatureMicroMips]; } + bool hasMips1() const { return getSTI().getFeatureBits()[Mips::FeatureMips1]; } + bool hasMips2() const { return getSTI().getFeatureBits()[Mips::FeatureMips2]; } + bool hasMips3() const { return getSTI().getFeatureBits()[Mips::FeatureMips3]; } + bool hasMips4() const { return getSTI().getFeatureBits()[Mips::FeatureMips4]; } + bool hasMips5() const { return getSTI().getFeatureBits()[Mips::FeatureMips5]; } + bool hasMips32() const { return getSTI().getFeatureBits()[Mips::FeatureMips32]; } + bool hasMips64() const { return getSTI().getFeatureBits()[Mips::FeatureMips64]; } + bool hasMips32r2() const { return getSTI().getFeatureBits()[Mips::FeatureMips32r2]; } + bool hasMips64r2() const { return getSTI().getFeatureBits()[Mips::FeatureMips64r2]; } + bool hasMips32r3() const { return (getSTI().getFeatureBits()[Mips::FeatureMips32r3]); } + bool hasMips64r3() const { return (getSTI().getFeatureBits()[Mips::FeatureMips64r3]); } + bool hasMips32r5() const { return (getSTI().getFeatureBits()[Mips::FeatureMips32r5]); } + bool hasMips64r5() const { return (getSTI().getFeatureBits()[Mips::FeatureMips64r5]); } + bool hasMips32r6() const { return getSTI().getFeatureBits()[Mips::FeatureMips32r6]; } + bool hasMips64r6() const { return getSTI().getFeatureBits()[Mips::FeatureMips64r6]; } @@ -514,15 +615,19 @@ public: bool hasDSP() const { return getSTI().getFeatureBits()[Mips::FeatureDSP]; } + bool hasDSPR2() const { return getSTI().getFeatureBits()[Mips::FeatureDSPR2]; } + bool hasDSPR3() const { return getSTI().getFeatureBits()[Mips::FeatureDSPR3]; } + bool hasMSA() const { return getSTI().getFeatureBits()[Mips::FeatureMSA]; } + bool hasCnMips() const { return (getSTI().getFeatureBits()[Mips::FeatureCnMips]); } @@ -542,6 +647,21 @@ public: bool useSoftFloat() const { return getSTI().getFeatureBits()[Mips::FeatureSoftFloat]; } + bool hasMT() const { + return getSTI().getFeatureBits()[Mips::FeatureMT]; + } + + bool hasCRC() const { + return getSTI().getFeatureBits()[Mips::FeatureCRC]; + } + + bool hasVirt() const { + return getSTI().getFeatureBits()[Mips::FeatureVirt]; + } + + bool hasGINV() const { + return getSTI().getFeatureBits()[Mips::FeatureGINV]; + } /// Warn if RegIndex is the same as the current AT. void warnIfRegIndexIsAT(unsigned RegIndex, SMLoc Loc); @@ -549,10 +669,65 @@ public: void warnIfNoMacro(SMLoc Loc); bool isLittle() const { return IsLittleEndian; } -}; -} -namespace { + const MCExpr *createTargetUnaryExpr(const MCExpr *E, + AsmToken::TokenKind OperatorToken, + MCContext &Ctx) override { + switch(OperatorToken) { + default: + llvm_unreachable("Unknown token"); + return nullptr; + case AsmToken::PercentCall16: + return MipsMCExpr::create(MipsMCExpr::MEK_GOT_CALL, E, Ctx); + case AsmToken::PercentCall_Hi: + return MipsMCExpr::create(MipsMCExpr::MEK_CALL_HI16, E, Ctx); + case AsmToken::PercentCall_Lo: + return MipsMCExpr::create(MipsMCExpr::MEK_CALL_LO16, E, Ctx); + case AsmToken::PercentDtprel_Hi: + return MipsMCExpr::create(MipsMCExpr::MEK_DTPREL_HI, E, Ctx); + case AsmToken::PercentDtprel_Lo: + return MipsMCExpr::create(MipsMCExpr::MEK_DTPREL_LO, E, Ctx); + case AsmToken::PercentGot: + return MipsMCExpr::create(MipsMCExpr::MEK_GOT, E, Ctx); + case AsmToken::PercentGot_Disp: + return MipsMCExpr::create(MipsMCExpr::MEK_GOT_DISP, E, Ctx); + case AsmToken::PercentGot_Hi: + return MipsMCExpr::create(MipsMCExpr::MEK_GOT_HI16, E, Ctx); + case AsmToken::PercentGot_Lo: + return MipsMCExpr::create(MipsMCExpr::MEK_GOT_LO16, E, Ctx); + case AsmToken::PercentGot_Ofst: + return MipsMCExpr::create(MipsMCExpr::MEK_GOT_OFST, E, Ctx); + case AsmToken::PercentGot_Page: + return MipsMCExpr::create(MipsMCExpr::MEK_GOT_PAGE, E, Ctx); + case AsmToken::PercentGottprel: + return MipsMCExpr::create(MipsMCExpr::MEK_GOTTPREL, E, Ctx); + case AsmToken::PercentGp_Rel: + return MipsMCExpr::create(MipsMCExpr::MEK_GPREL, E, Ctx); + case AsmToken::PercentHi: + return MipsMCExpr::create(MipsMCExpr::MEK_HI, E, Ctx); + case AsmToken::PercentHigher: + return MipsMCExpr::create(MipsMCExpr::MEK_HIGHER, E, Ctx); + case AsmToken::PercentHighest: + return MipsMCExpr::create(MipsMCExpr::MEK_HIGHEST, E, Ctx); + case AsmToken::PercentLo: + return MipsMCExpr::create(MipsMCExpr::MEK_LO, E, Ctx); + case AsmToken::PercentNeg: + return MipsMCExpr::create(MipsMCExpr::MEK_NEG, E, Ctx); + case AsmToken::PercentPcrel_Hi: + return MipsMCExpr::create(MipsMCExpr::MEK_PCREL_HI16, E, Ctx); + case AsmToken::PercentPcrel_Lo: + return MipsMCExpr::create(MipsMCExpr::MEK_PCREL_LO16, E, Ctx); + case AsmToken::PercentTlsgd: + return MipsMCExpr::create(MipsMCExpr::MEK_TLSGD, E, Ctx); + case AsmToken::PercentTlsldm: + return MipsMCExpr::create(MipsMCExpr::MEK_TLSLDM, E, Ctx); + case AsmToken::PercentTprel_Hi: + return MipsMCExpr::create(MipsMCExpr::MEK_TPREL_HI, E, Ctx); + case AsmToken::PercentTprel_Lo: + return MipsMCExpr::create(MipsMCExpr::MEK_TPREL_LO, E, Ctx); + } + } +}; /// MipsOperand - Instances of this class represent a parsed Mips machine /// instruction. @@ -584,17 +759,30 @@ private: enum KindTy { k_Immediate, /// An immediate (possibly involving symbol references) k_Memory, /// Base + Offset Memory Address - k_PhysRegister, /// A physical register from the Mips namespace k_RegisterIndex, /// A register index in one or more RegKind. k_Token, /// A simple token k_RegList, /// A physical register list - k_RegPair /// A pair of physical register } Kind; public: MipsOperand(KindTy K, MipsAsmParser &Parser) : MCParsedAsmOperand(), Kind(K), AsmParser(Parser) {} + ~MipsOperand() override { + switch (Kind) { + case k_Memory: + delete Mem.Base; + break; + case k_RegList: + delete RegList.List; + break; + case k_Immediate: + case k_RegisterIndex: + case k_Token: + break; + } + } + private: /// For diagnostics, and checking the assembler temporary MipsAsmParser &AsmParser; @@ -604,13 +792,10 @@ private: unsigned Length; }; - struct PhysRegOp { - unsigned Num; /// Register Number - }; - struct RegIdxOp { unsigned Index; /// Index into the register class RegKind Kind; /// Bitfield of the kinds it could possibly be + struct Token Tok; /// The input token this operand originated from. const MCRegisterInfo *RegInfo; }; @@ -629,7 +814,6 @@ private: union { struct Token Tok; - struct PhysRegOp PhysReg; struct RegIdxOp RegIdx; struct ImmOp Imm; struct MemOp Mem; @@ -639,14 +823,17 @@ private: SMLoc StartLoc, EndLoc; /// Internal constructor for register kinds - static std::unique_ptr<MipsOperand> CreateReg(unsigned Index, RegKind RegKind, + static std::unique_ptr<MipsOperand> CreateReg(unsigned Index, StringRef Str, + RegKind RegKind, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, MipsAsmParser &Parser) { - auto Op = make_unique<MipsOperand>(k_RegisterIndex, Parser); + auto Op = llvm::make_unique<MipsOperand>(k_RegisterIndex, Parser); Op->RegIdx.Index = Index; Op->RegIdx.RegInfo = RegInfo; Op->RegIdx.Kind = RegKind; + Op->RegIdx.Tok.Data = Str.data(); + Op->RegIdx.Tok.Length = Str.size(); Op->StartLoc = S; Op->EndLoc = E; return Op; @@ -821,6 +1008,16 @@ public: /// Render the operand to an MCInst as a GPR32 /// Asserts if the wrong number of operands are requested, or the operand /// is not a k_RegisterIndex compatible with RegKind_GPR + void addGPR32ZeroAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getGPR32Reg())); + } + + void addGPR32NonZeroAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getGPR32Reg())); + } + void addGPR32AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getGPR32Reg())); @@ -841,6 +1038,17 @@ public: Inst.addOperand(MCOperand::createReg(getGPRMM16Reg())); } + void addGPRMM16AsmRegMovePPairFirstOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getGPRMM16Reg())); + } + + void addGPRMM16AsmRegMovePPairSecondOperands(MCInst &Inst, + unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getGPRMM16Reg())); + } + /// Render the operand to an MCInst as a GPR64 /// Asserts if the wrong number of operands are requested, or the operand /// is not a k_RegisterIndex compatible with RegKind_GPR @@ -854,6 +1062,16 @@ public: Inst.addOperand(MCOperand::createReg(getAFGR64Reg())); } + void addStrictlyAFGR64AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getAFGR64Reg())); + } + + void addStrictlyFGR64AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getFGR64Reg())); + } + void addFGR64AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getFGR64Reg())); @@ -863,6 +1081,17 @@ public: assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getFGR32Reg())); // FIXME: We ought to do this for -integrated-as without -via-file-asm too. + // FIXME: This should propagate failure up to parseStatement. + if (!AsmParser.useOddSPReg() && RegIdx.Index & 1) + AsmParser.getParser().printError( + StartLoc, "-mno-odd-spreg prohibits the use of odd FPU " + "registers"); + } + + void addStrictlyFGR32AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getFGR32Reg())); + // FIXME: We ought to do this for -integrated-as without -via-file-asm too. if (!AsmParser.useOddSPReg() && RegIdx.Index & 1) AsmParser.Error(StartLoc, "-mno-odd-spreg prohibits the use of odd FPU " "registers"); @@ -932,7 +1161,35 @@ public: void addConstantUImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); uint64_t Imm = getConstantImm() - Offset; - Imm &= (1 << Bits) - 1; + Imm &= (1ULL << Bits) - 1; + Imm += Offset; + Imm += AdjustOffset; + Inst.addOperand(MCOperand::createImm(Imm)); + } + + template <unsigned Bits> + void addSImmOperands(MCInst &Inst, unsigned N) const { + if (isImm() && !isConstantImm()) { + addExpr(Inst, getImm()); + return; + } + addConstantSImmOperands<Bits, 0, 0>(Inst, N); + } + + template <unsigned Bits> + void addUImmOperands(MCInst &Inst, unsigned N) const { + if (isImm() && !isConstantImm()) { + addExpr(Inst, getImm()); + return; + } + addConstantUImmOperands<Bits, 0, 0>(Inst, N); + } + + template <unsigned Bits, int Offset = 0, int AdjustOffset = 0> + void addConstantSImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + int64_t Imm = getConstantImm() - Offset; + Imm = SignExtend64<Bits>(Imm); Imm += Offset; Imm += AdjustOffset; Inst.addOperand(MCOperand::createImm(Imm)); @@ -971,75 +1228,136 @@ public: Inst.addOperand(MCOperand::createReg(RegNo)); } - void addRegPairOperands(MCInst &Inst, unsigned N) const { - assert(N == 2 && "Invalid number of operands!"); - unsigned RegNo = getRegPair(); - Inst.addOperand(MCOperand::createReg(RegNo++)); - Inst.addOperand(MCOperand::createReg(RegNo)); - } - - void addMovePRegPairOperands(MCInst &Inst, unsigned N) const { - assert(N == 2 && "Invalid number of operands!"); - for (auto RegNo : getRegList()) - Inst.addOperand(MCOperand::createReg(RegNo)); - } - bool isReg() const override { - // As a special case until we sort out the definition of div/divu, pretend - // that $0/$zero are k_PhysRegister so that MCK_ZERO works correctly. - if (isGPRAsmReg() && RegIdx.Index == 0) - return true; - - return Kind == k_PhysRegister; + // As a special case until we sort out the definition of div/divu, accept + // $0/$zero here so that MCK_ZERO works correctly. + return isGPRAsmReg() && RegIdx.Index == 0; } + bool isRegIdx() const { return Kind == k_RegisterIndex; } bool isImm() const override { return Kind == k_Immediate; } + bool isConstantImm() const { - return isImm() && isa<MCConstantExpr>(getImm()); + int64_t Res; + return isImm() && getImm()->evaluateAsAbsolute(Res); } + bool isConstantImmz() const { return isConstantImm() && getConstantImm() == 0; } + template <unsigned Bits, int Offset = 0> bool isConstantUImm() const { return isConstantImm() && isUInt<Bits>(getConstantImm() - Offset); } - template <unsigned Bits> bool isConstantSImm() const { - return isConstantImm() && isInt<Bits>(getConstantImm()); + + template <unsigned Bits> bool isSImm() const { + return isConstantImm() ? isInt<Bits>(getConstantImm()) : isImm(); + } + + template <unsigned Bits> bool isUImm() const { + return isConstantImm() ? isUInt<Bits>(getConstantImm()) : isImm(); + } + + template <unsigned Bits> bool isAnyImm() const { + return isConstantImm() ? (isInt<Bits>(getConstantImm()) || + isUInt<Bits>(getConstantImm())) + : isImm(); + } + + template <unsigned Bits, int Offset = 0> bool isConstantSImm() const { + return isConstantImm() && isInt<Bits>(getConstantImm() - Offset); } + + template <unsigned Bottom, unsigned Top> bool isConstantUImmRange() const { + return isConstantImm() && getConstantImm() >= Bottom && + getConstantImm() <= Top; + } + bool isToken() const override { // Note: It's not possible to pretend that other operand kinds are tokens. // The matcher emitter checks tokens first. return Kind == k_Token; } + bool isMem() const override { return Kind == k_Memory; } + bool isConstantMemOff() const { return isMem() && isa<MCConstantExpr>(getMemOff()); } - template <unsigned Bits> bool isMemWithSimmOffset() const { - return isMem() && isConstantMemOff() && isInt<Bits>(getConstantMemOff()) - && getMemBase()->isGPRAsmReg(); + + // 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()) + return false; + if (!getMemBase()->isGPRAsmReg()) + return false; + if (isa<MCTargetExpr>(getMemOff()) || + (isConstantMemOff() && + isShiftedInt<Bits, ShiftAmount>(getConstantMemOff()))) + return true; + MCValue Res; + bool IsReloc = getMemOff()->evaluateAsRelocatable(Res, nullptr, nullptr); + return IsReloc && isShiftedInt<Bits, ShiftAmount>(Res.getConstant()); } - template <unsigned Bits> bool isMemWithSimmOffsetGPR() const { - return isMem() && isConstantMemOff() && isInt<Bits>(getConstantMemOff()) && - getMemBase()->isGPRAsmReg(); + + bool isMemWithPtrSizeOffset() const { + if (!isMem()) + return false; + if (!getMemBase()->isGPRAsmReg()) + return false; + const unsigned PtrBits = AsmParser.getABI().ArePtrs64bit() ? 64 : 32; + if (isa<MCTargetExpr>(getMemOff()) || + (isConstantMemOff() && isIntN(PtrBits, getConstantMemOff()))) + return true; + MCValue Res; + bool IsReloc = getMemOff()->evaluateAsRelocatable(Res, nullptr, nullptr); + return IsReloc && isIntN(PtrBits, Res.getConstant()); } + bool isMemWithGRPMM16Base() const { return isMem() && getMemBase()->isMM16AsmReg(); } + template <unsigned Bits> bool isMemWithUimmOffsetSP() const { return isMem() && isConstantMemOff() && isUInt<Bits>(getConstantMemOff()) && getMemBase()->isRegIdx() && (getMemBase()->getGPR32Reg() == Mips::SP); } + template <unsigned Bits> bool isMemWithUimmWordAlignedOffsetSP() const { return isMem() && isConstantMemOff() && isUInt<Bits>(getConstantMemOff()) && (getConstantMemOff() % 4 == 0) && getMemBase()->isRegIdx() && (getMemBase()->getGPR32Reg() == Mips::SP); } + + template <unsigned Bits> bool isMemWithSimmWordAlignedOffsetGP() const { + return isMem() && isConstantMemOff() && isInt<Bits>(getConstantMemOff()) + && (getConstantMemOff() % 4 == 0) && getMemBase()->isRegIdx() + && (getMemBase()->getGPR32Reg() == Mips::GP); + } + template <unsigned Bits, unsigned ShiftLeftAmount> bool isScaledUImm() const { return isConstantImm() && isShiftedUInt<Bits, ShiftLeftAmount>(getConstantImm()); } + + template <unsigned Bits, unsigned ShiftLeftAmount> + bool isScaledSImm() const { + if (isConstantImm() && + isShiftedInt<Bits, ShiftLeftAmount>(getConstantImm())) + return true; + // Operand can also be a symbol or symbol plus + // offset in case of relocations. + if (Kind != k_Immediate) + return false; + MCValue Res; + bool Success = getImm()->evaluateAsRelocatable(Res, nullptr, nullptr); + return Success && isShiftedInt<Bits, ShiftLeftAmount>(Res.getConstant()); + } + bool isRegList16() const { if (!isRegList()) return false; @@ -1064,49 +1382,32 @@ public: return true; } + bool isInvNum() const { return Kind == k_Immediate; } + bool isLSAImm() const { if (!isConstantImm()) return false; int64_t Val = getConstantImm(); return 1 <= Val && Val <= 4; } - bool isRegList() const { return Kind == k_RegList; } - bool isMovePRegPair() const { - if (Kind != k_RegList || RegList.List->size() != 2) - return false; - - unsigned R0 = RegList.List->front(); - unsigned R1 = RegList.List->back(); - - if ((R0 == Mips::A1 && R1 == Mips::A2) || - (R0 == Mips::A1 && R1 == Mips::A3) || - (R0 == Mips::A2 && R1 == Mips::A3) || - (R0 == Mips::A0 && R1 == Mips::S5) || - (R0 == Mips::A0 && R1 == Mips::S6) || - (R0 == Mips::A0 && R1 == Mips::A1) || - (R0 == Mips::A0 && R1 == Mips::A2) || - (R0 == Mips::A0 && R1 == Mips::A3)) - return true; - return false; - } + bool isRegList() const { return Kind == k_RegList; } StringRef getToken() const { assert(Kind == k_Token && "Invalid access!"); return StringRef(Tok.Data, Tok.Length); } - bool isRegPair() const { return Kind == k_RegPair; } unsigned getReg() const override { - // As a special case until we sort out the definition of div/divu, pretend - // that $0/$zero are k_PhysRegister so that MCK_ZERO works correctly. + // As a special case until we sort out the definition of div/divu, accept + // $0/$zero here so that MCK_ZERO works correctly. if (Kind == k_RegisterIndex && RegIdx.Index == 0 && RegIdx.Kind & RegKind_GPR) return getGPR32Reg(); // FIXME: GPR64 too - assert(Kind == k_PhysRegister && "Invalid access!"); - return PhysReg.Num; + llvm_unreachable("Invalid access!"); + return 0; } const MCExpr *getImm() const { @@ -1116,7 +1417,9 @@ public: int64_t getConstantImm() const { const MCExpr *Val = getImm(); - return static_cast<const MCConstantExpr *>(Val)->getValue(); + int64_t Value = 0; + (void)Val->evaluateAsAbsolute(Value); + return Value; } MipsOperand *getMemBase() const { @@ -1138,14 +1441,9 @@ public: return *(RegList.List); } - unsigned getRegPair() const { - assert((Kind == k_RegPair) && "Invalid access!"); - return RegIdx.Index; - } - static std::unique_ptr<MipsOperand> CreateToken(StringRef Str, SMLoc S, MipsAsmParser &Parser) { - auto Op = make_unique<MipsOperand>(k_Token, Parser); + auto Op = llvm::make_unique<MipsOperand>(k_Token, Parser); Op->Tok.Data = Str.data(); Op->Tok.Length = Str.size(); Op->StartLoc = S; @@ -1156,71 +1454,71 @@ public: /// Create a numeric register (e.g. $1). The exact register remains /// unresolved until an instruction successfully matches static std::unique_ptr<MipsOperand> - createNumericReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, - SMLoc E, MipsAsmParser &Parser) { - DEBUG(dbgs() << "createNumericReg(" << Index << ", ...)\n"); - return CreateReg(Index, RegKind_Numeric, RegInfo, S, E, Parser); + createNumericReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, + SMLoc S, SMLoc E, MipsAsmParser &Parser) { + LLVM_DEBUG(dbgs() << "createNumericReg(" << Index << ", ...)\n"); + return CreateReg(Index, Str, RegKind_Numeric, RegInfo, S, E, Parser); } /// Create a register that is definitely a GPR. /// This is typically only used for named registers such as $gp. static std::unique_ptr<MipsOperand> - createGPRReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, - MipsAsmParser &Parser) { - return CreateReg(Index, RegKind_GPR, RegInfo, S, E, Parser); + createGPRReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, + SMLoc S, SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, Str, RegKind_GPR, RegInfo, S, E, Parser); } /// Create a register that is definitely a FGR. /// This is typically only used for named registers such as $f0. static std::unique_ptr<MipsOperand> - createFGRReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, - MipsAsmParser &Parser) { - return CreateReg(Index, RegKind_FGR, RegInfo, S, E, Parser); + createFGRReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, + SMLoc S, SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, Str, RegKind_FGR, RegInfo, S, E, Parser); } /// Create a register that is definitely a HWReg. /// This is typically only used for named registers such as $hwr_cpunum. static std::unique_ptr<MipsOperand> - createHWRegsReg(unsigned Index, const MCRegisterInfo *RegInfo, + createHWRegsReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, MipsAsmParser &Parser) { - return CreateReg(Index, RegKind_HWRegs, RegInfo, S, E, Parser); + return CreateReg(Index, Str, RegKind_HWRegs, RegInfo, S, E, Parser); } /// Create a register that is definitely an FCC. /// This is typically only used for named registers such as $fcc0. static std::unique_ptr<MipsOperand> - createFCCReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, - MipsAsmParser &Parser) { - return CreateReg(Index, RegKind_FCC, RegInfo, S, E, Parser); + createFCCReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, + SMLoc S, SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, Str, RegKind_FCC, RegInfo, S, E, Parser); } /// Create a register that is definitely an ACC. /// This is typically only used for named registers such as $ac0. static std::unique_ptr<MipsOperand> - createACCReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, - MipsAsmParser &Parser) { - return CreateReg(Index, RegKind_ACC, RegInfo, S, E, Parser); + createACCReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, + SMLoc S, SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, Str, RegKind_ACC, RegInfo, S, E, Parser); } /// Create a register that is definitely an MSA128. /// This is typically only used for named registers such as $w0. static std::unique_ptr<MipsOperand> - createMSA128Reg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, - SMLoc E, MipsAsmParser &Parser) { - return CreateReg(Index, RegKind_MSA128, RegInfo, S, E, Parser); + createMSA128Reg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, + SMLoc S, SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, Str, RegKind_MSA128, RegInfo, S, E, Parser); } /// Create a register that is definitely an MSACtrl. /// This is typically only used for named registers such as $msaaccess. static std::unique_ptr<MipsOperand> - createMSACtrlReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, - SMLoc E, MipsAsmParser &Parser) { - return CreateReg(Index, RegKind_MSACtrl, RegInfo, S, E, Parser); + createMSACtrlReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, + SMLoc S, SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, Str, RegKind_MSACtrl, RegInfo, S, E, Parser); } static std::unique_ptr<MipsOperand> CreateImm(const MCExpr *Val, SMLoc S, SMLoc E, MipsAsmParser &Parser) { - auto Op = make_unique<MipsOperand>(k_Immediate, Parser); + auto Op = llvm::make_unique<MipsOperand>(k_Immediate, Parser); Op->Imm.Val = Val; Op->StartLoc = S; Op->EndLoc = E; @@ -1230,7 +1528,7 @@ public: static std::unique_ptr<MipsOperand> CreateMem(std::unique_ptr<MipsOperand> Base, const MCExpr *Off, SMLoc S, SMLoc E, MipsAsmParser &Parser) { - auto Op = make_unique<MipsOperand>(k_Memory, Parser); + auto Op = llvm::make_unique<MipsOperand>(k_Memory, Parser); Op->Mem.Base = Base.release(); Op->Mem.Off = Off; Op->StartLoc = S; @@ -1241,32 +1539,34 @@ public: static std::unique_ptr<MipsOperand> CreateRegList(SmallVectorImpl<unsigned> &Regs, SMLoc StartLoc, SMLoc EndLoc, MipsAsmParser &Parser) { - assert (Regs.size() > 0 && "Empty list not allowed"); + assert(Regs.size() > 0 && "Empty list not allowed"); - auto Op = make_unique<MipsOperand>(k_RegList, Parser); + auto Op = llvm::make_unique<MipsOperand>(k_RegList, Parser); Op->RegList.List = new SmallVector<unsigned, 10>(Regs.begin(), Regs.end()); Op->StartLoc = StartLoc; Op->EndLoc = EndLoc; return Op; } - static std::unique_ptr<MipsOperand> - CreateRegPair(unsigned RegNo, SMLoc S, SMLoc E, MipsAsmParser &Parser) { - auto Op = make_unique<MipsOperand>(k_RegPair, Parser); - Op->RegIdx.Index = RegNo; - Op->StartLoc = S; - Op->EndLoc = E; - return Op; + bool isGPRZeroAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_GPR && RegIdx.Index == 0; + } + + bool isGPRNonZeroAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_GPR && RegIdx.Index > 0 && + RegIdx.Index <= 31; } bool isGPRAsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_GPR && RegIdx.Index <= 31; } + bool isMM16AsmReg() const { if (!(isRegIdx() && RegIdx.Kind)) return false; return ((RegIdx.Index >= 2 && RegIdx.Index <= 7) || RegIdx.Index == 16 || RegIdx.Index == 17); + } bool isMM16AsmRegZero() const { if (!(isRegIdx() && RegIdx.Kind)) @@ -1275,44 +1575,71 @@ public: (RegIdx.Index >= 2 && RegIdx.Index <= 7) || RegIdx.Index == 17); } + bool isMM16AsmRegMoveP() const { if (!(isRegIdx() && RegIdx.Kind)) return false; return (RegIdx.Index == 0 || (RegIdx.Index >= 2 && RegIdx.Index <= 3) || (RegIdx.Index >= 16 && RegIdx.Index <= 20)); } + + bool isMM16AsmRegMovePPairFirst() const { + if (!(isRegIdx() && RegIdx.Kind)) + return false; + return RegIdx.Index >= 4 && RegIdx.Index <= 6; + } + + bool isMM16AsmRegMovePPairSecond() const { + if (!(isRegIdx() && RegIdx.Kind)) + return false; + return (RegIdx.Index == 21 || RegIdx.Index == 22 || + (RegIdx.Index >= 5 && RegIdx.Index <= 7)); + } + bool isFGRAsmReg() const { // AFGR64 is $0-$15 but we handle this in getAFGR64() return isRegIdx() && RegIdx.Kind & RegKind_FGR && RegIdx.Index <= 31; } + + bool isStrictlyFGRAsmReg() const { + // AFGR64 is $0-$15 but we handle this in getAFGR64() + return isRegIdx() && RegIdx.Kind == RegKind_FGR && RegIdx.Index <= 31; + } + bool isHWRegsAsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_HWRegs && RegIdx.Index <= 31; } + bool isCCRAsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_CCR && RegIdx.Index <= 31; } + bool isFCCAsmReg() const { if (!(isRegIdx() && RegIdx.Kind & RegKind_FCC)) return false; - if (!AsmParser.hasEightFccRegisters()) - return RegIdx.Index == 0; return RegIdx.Index <= 7; } + bool isACCAsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_ACC && RegIdx.Index <= 3; } + bool isCOP0AsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_COP0 && RegIdx.Index <= 31; } + bool isCOP2AsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_COP2 && RegIdx.Index <= 31; } + bool isCOP3AsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_COP3 && RegIdx.Index <= 31; } + bool isMSA128AsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_MSA128 && RegIdx.Index <= 31; } + bool isMSACtrlAsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_MSACtrl && RegIdx.Index <= 7; } @@ -1322,23 +1649,6 @@ public: /// getEndLoc - Get the location of the last token of this operand. SMLoc getEndLoc() const override { return EndLoc; } - virtual ~MipsOperand() { - switch (Kind) { - case k_Immediate: - break; - case k_Memory: - delete Mem.Base; - break; - case k_RegList: - delete RegList.List; - case k_PhysRegister: - case k_RegisterIndex: - case k_Token: - case k_RegPair: - break; - } - } - void print(raw_ostream &OS) const override { switch (Kind) { case k_Immediate: @@ -1353,14 +1663,12 @@ public: OS << *Mem.Off; OS << ">"; break; - case k_PhysRegister: - OS << "PhysReg<" << PhysReg.Num << ">"; - break; case k_RegisterIndex: - OS << "RegIdx<" << RegIdx.Index << ":" << RegIdx.Kind << ">"; + OS << "RegIdx<" << RegIdx.Index << ":" << RegIdx.Kind << ", " + << StringRef(RegIdx.Tok.Data, RegIdx.Tok.Length) << ">"; break; case k_Token: - OS << Tok.Data; + OS << getToken(); break; case k_RegList: OS << "RegList< "; @@ -1368,29 +1676,55 @@ public: OS << Reg << " "; OS << ">"; break; - case k_RegPair: - OS << "RegPair<" << RegIdx.Index << "," << RegIdx.Index + 1 << ">"; - break; + } + } + + bool isValidForTie(const MipsOperand &Other) const { + if (Kind != Other.Kind) + return false; + + switch (Kind) { + default: + llvm_unreachable("Unexpected kind"); + return false; + case k_RegisterIndex: { + StringRef Token(RegIdx.Tok.Data, RegIdx.Tok.Length); + StringRef OtherToken(Other.RegIdx.Tok.Data, Other.RegIdx.Tok.Length); + return Token == OtherToken; + } } } }; // class MipsOperand -} // namespace + +} // end anonymous namespace namespace llvm { + extern const MCInstrDesc MipsInsts[]; -} + +} // end namespace llvm + static const MCInstrDesc &getInstDesc(unsigned Opcode) { return MipsInsts[Opcode]; } -static bool hasShortDelaySlot(unsigned Opcode) { - switch (Opcode) { +static bool hasShortDelaySlot(MCInst &Inst) { + switch (Inst.getOpcode()) { + case Mips::BEQ_MM: + case Mips::BNE_MM: + case Mips::BLTZ_MM: + case Mips::BGEZ_MM: + case Mips::BLEZ_MM: + case Mips::BGTZ_MM: + case Mips::JRC16_MM: case Mips::JALS_MM: case Mips::JALRS_MM: case Mips::JALRS16_MM: case Mips::BGEZALS_MM: case Mips::BLTZALS_MM: return true; + case Mips::J_MM: + return !Inst.getOperand(0).isReg(); default: return false; } @@ -1434,83 +1768,10 @@ static unsigned countMCSymbolRefExpr(const MCExpr *Expr) { return 0; } -namespace { -void emitRX(unsigned Opcode, unsigned Reg0, MCOperand Op1, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { - MCInst tmpInst; - tmpInst.setOpcode(Opcode); - tmpInst.addOperand(MCOperand::createReg(Reg0)); - tmpInst.addOperand(Op1); - tmpInst.setLoc(IDLoc); - Instructions.push_back(tmpInst); -} - -void emitRI(unsigned Opcode, unsigned Reg0, int32_t Imm, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { - emitRX(Opcode, Reg0, MCOperand::createImm(Imm), IDLoc, Instructions); -} - -void emitRR(unsigned Opcode, unsigned Reg0, unsigned Reg1, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { - emitRX(Opcode, Reg0, MCOperand::createReg(Reg1), IDLoc, Instructions); -} - -void emitII(unsigned Opcode, int16_t Imm1, int16_t Imm2, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { - MCInst tmpInst; - tmpInst.setOpcode(Opcode); - tmpInst.addOperand(MCOperand::createImm(Imm1)); - tmpInst.addOperand(MCOperand::createImm(Imm2)); - tmpInst.setLoc(IDLoc); - Instructions.push_back(tmpInst); -} - -void emitR(unsigned Opcode, unsigned Reg0, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { - MCInst tmpInst; - tmpInst.setOpcode(Opcode); - tmpInst.addOperand(MCOperand::createReg(Reg0)); - tmpInst.setLoc(IDLoc); - Instructions.push_back(tmpInst); -} - -void emitRRX(unsigned Opcode, unsigned Reg0, unsigned Reg1, MCOperand Op2, - SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { - MCInst tmpInst; - tmpInst.setOpcode(Opcode); - tmpInst.addOperand(MCOperand::createReg(Reg0)); - tmpInst.addOperand(MCOperand::createReg(Reg1)); - tmpInst.addOperand(Op2); - tmpInst.setLoc(IDLoc); - Instructions.push_back(tmpInst); -} - -void emitRRR(unsigned Opcode, unsigned Reg0, unsigned Reg1, unsigned Reg2, - SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { - emitRRX(Opcode, Reg0, Reg1, MCOperand::createReg(Reg2), IDLoc, - Instructions); -} - -void emitRRI(unsigned Opcode, unsigned Reg0, unsigned Reg1, int16_t Imm, - SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { - emitRRX(Opcode, Reg0, Reg1, MCOperand::createImm(Imm), IDLoc, - Instructions); -} - -void emitAppropriateDSLL(unsigned DstReg, unsigned SrcReg, int16_t ShiftAmount, - SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { - if (ShiftAmount >= 32) { - emitRRI(Mips::DSLL32, DstReg, SrcReg, ShiftAmount - 32, IDLoc, - Instructions); - return; - } - - emitRRI(Mips::DSLL, DstReg, SrcReg, ShiftAmount, IDLoc, Instructions); -} -} // end anonymous namespace. - bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { + MCStreamer &Out, + const MCSubtargetInfo *STI) { + MipsTargetStreamer &TOut = getTargetStreamer(); const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode()); bool ExpandedJalSym = false; @@ -1528,7 +1789,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, case Mips::BBIT1: case Mips::BBIT132: assert(hasCnMips() && "instruction only valid for octeon cpus"); - // Fall through + LLVM_FALLTHROUGH; case Mips::BEQ: case Mips::BNE: @@ -1560,6 +1821,10 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, case Mips::BLTZAL_MM: case Mips::BC1F_MM: case Mips::BC1T_MM: + case Mips::BC1EQZC_MMR6: + case Mips::BC1NEZC_MMR6: + case Mips::BC2EQZC_MMR6: + case Mips::BC2NEZC_MMR6: assert(MCID.getNumOperands() == 2 && "unexpected number of operands"); Offset = Inst.getOperand(1); if (!Offset.isImm()) @@ -1570,6 +1835,45 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, 1LL << (inMicroMipsMode() ? 1 : 2))) return Error(IDLoc, "branch to misaligned address"); break; + case Mips::BGEC: case Mips::BGEC_MMR6: + case Mips::BLTC: case Mips::BLTC_MMR6: + case Mips::BGEUC: case Mips::BGEUC_MMR6: + case Mips::BLTUC: case Mips::BLTUC_MMR6: + case Mips::BEQC: case Mips::BEQC_MMR6: + case Mips::BNEC: case Mips::BNEC_MMR6: + assert(MCID.getNumOperands() == 3 && "unexpected number of operands"); + Offset = Inst.getOperand(2); + if (!Offset.isImm()) + break; // We'll deal with this situation later on when applying fixups. + if (!isIntN(18, Offset.getImm())) + return Error(IDLoc, "branch target out of range"); + if (OffsetToAlignment(Offset.getImm(), 1LL << 2)) + return Error(IDLoc, "branch to misaligned address"); + break; + case Mips::BLEZC: case Mips::BLEZC_MMR6: + case Mips::BGEZC: case Mips::BGEZC_MMR6: + case Mips::BGTZC: case Mips::BGTZC_MMR6: + case Mips::BLTZC: case Mips::BLTZC_MMR6: + assert(MCID.getNumOperands() == 2 && "unexpected number of operands"); + Offset = Inst.getOperand(1); + if (!Offset.isImm()) + break; // We'll deal with this situation later on when applying fixups. + if (!isIntN(18, Offset.getImm())) + return Error(IDLoc, "branch target out of range"); + if (OffsetToAlignment(Offset.getImm(), 1LL << 2)) + return Error(IDLoc, "branch to misaligned address"); + break; + case Mips::BEQZC: case Mips::BEQZC_MMR6: + case Mips::BNEZC: case Mips::BNEZC_MMR6: + assert(MCID.getNumOperands() == 2 && "unexpected number of operands"); + Offset = Inst.getOperand(1); + if (!Offset.isImm()) + break; // We'll deal with this situation later on when applying fixups. + if (!isIntN(23, Offset.getImm())) + return Error(IDLoc, "branch target out of range"); + if (OffsetToAlignment(Offset.getImm(), 1LL << 2)) + return Error(IDLoc, "branch to misaligned address"); + break; case Mips::BEQZ16_MM: case Mips::BEQZC16_MMR6: case Mips::BNEZ16_MM: @@ -1636,6 +1940,71 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, } } + // Warn on division by zero. We're checking here as all instructions get + // processed here, not just the macros that need expansion. + // + // The MIPS backend models most of the divison instructions and macros as + // three operand instructions. The pre-R6 divide instructions however have + // two operands and explicitly define HI/LO as part of the instruction, + // not in the operands. + unsigned FirstOp = 1; + unsigned SecondOp = 2; + switch (Inst.getOpcode()) { + default: + break; + case Mips::SDivIMacro: + case Mips::UDivIMacro: + case Mips::DSDivIMacro: + case Mips::DUDivIMacro: + if (Inst.getOperand(2).getImm() == 0) { + if (Inst.getOperand(1).getReg() == Mips::ZERO || + Inst.getOperand(1).getReg() == Mips::ZERO_64) + Warning(IDLoc, "dividing zero by zero"); + else + Warning(IDLoc, "division by zero"); + } + break; + case Mips::DSDIV: + case Mips::SDIV: + case Mips::UDIV: + case Mips::DUDIV: + case Mips::UDIV_MM: + case Mips::SDIV_MM: + FirstOp = 0; + SecondOp = 1; + LLVM_FALLTHROUGH; + case Mips::SDivMacro: + case Mips::DSDivMacro: + case Mips::UDivMacro: + case Mips::DUDivMacro: + case Mips::DIV: + case Mips::DIVU: + case Mips::DDIV: + case Mips::DDIVU: + case Mips::DIVU_MMR6: + case Mips::DIV_MMR6: + if (Inst.getOperand(SecondOp).getReg() == Mips::ZERO || + Inst.getOperand(SecondOp).getReg() == Mips::ZERO_64) { + if (Inst.getOperand(FirstOp).getReg() == Mips::ZERO || + Inst.getOperand(FirstOp).getReg() == Mips::ZERO_64) + Warning(IDLoc, "dividing zero by zero"); + else + Warning(IDLoc, "division by zero"); + } + break; + } + + // For PIC code convert unconditional jump to unconditional branch. + if ((Inst.getOpcode() == Mips::J || Inst.getOpcode() == Mips::J_MM) && + inPicMode()) { + MCInst BInst; + BInst.setOpcode(inMicroMipsMode() ? Mips::BEQ_MM : Mips::BEQ); + BInst.addOperand(MCOperand::createReg(Mips::ZERO)); + BInst.addOperand(MCOperand::createReg(Mips::ZERO)); + BInst.addOperand(Inst.getOperand(0)); + Inst = BInst; + } + // 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) && @@ -1650,15 +2019,15 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, return Error(IDLoc, "jal doesn't support multiple symbols in PIC mode"); // FIXME: This is checking the expression can be handled by the later stages - // of the assembler. We ought to leave it to those later stages but - // we can't do that until we stop evaluateRelocExpr() rewriting the - // expressions into non-equivalent forms. + // 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()) { + 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) @@ -1666,33 +2035,38 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, // addiu $25, $25, 0 // R_(MICRO)MIPS_LO16 label // jalr $25 - const MCExpr *Got16RelocExpr = evaluateRelocExpr(JalExpr, "got"); - const MCExpr *Lo16RelocExpr = evaluateRelocExpr(JalExpr, "lo"); - - emitRRX(Mips::LW, Mips::T9, Mips::GP, - MCOperand::createExpr(Got16RelocExpr), IDLoc, Instructions); - emitRRX(Mips::ADDiu, Mips::T9, Mips::T9, - MCOperand::createExpr(Lo16RelocExpr), IDLoc, Instructions); + 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, Mips::GP, + 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 = evaluateRelocExpr(JalExpr, "got_disp"); + const MCExpr *GotDispRelocExpr = + MipsMCExpr::create(MipsMCExpr::MEK_GOT_DISP, JalExpr, getContext()); - emitRRX(ABI.ArePtrs64bit() ? Mips::LD : Mips::LW, Mips::T9, Mips::GP, - MCOperand::createExpr(GotDispRelocExpr), IDLoc, Instructions); + TOut.emitRRX(ABI.ArePtrs64bit() ? Mips::LD : Mips::LW, Mips::T9, + Mips::GP, 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 = evaluateRelocExpr(JalExpr, "call16"); + const MCExpr *Call16RelocExpr = + MipsMCExpr::create(MipsMCExpr::MEK_GOT_CALL, JalExpr, getContext()); - emitRRX(ABI.ArePtrs64bit() ? Mips::LD : Mips::LW, Mips::T9, Mips::GP, - MCOperand::createExpr(Call16RelocExpr), IDLoc, Instructions); + TOut.emitRRX(ABI.ArePtrs64bit() ? Mips::LD : Mips::LW, Mips::T9, Mips::GP, + MCOperand::createExpr(Call16RelocExpr), IDLoc, STI); } MCInst JalrInst; @@ -1703,15 +2077,28 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, JalrInst.addOperand(MCOperand::createReg(Mips::RA)); JalrInst.addOperand(MCOperand::createReg(Mips::T9)); - // FIXME: Add an R_(MICRO)MIPS_JALR relocation after the JALR. - // This relocation is supposed to be an optimization hint for the linker - // and is not necessary for correctness. + if (EmitJalrReloc) { + // As an optimization hint for the linker, before the JALR we add: + // .reloc tmplabel, R_{MICRO}MIPS_JALR, symbol + // tmplabel: + MCSymbol *TmpLabel = getContext().createTempSymbol(); + const MCExpr *TmpExpr = MCSymbolRefExpr::create(TmpLabel, getContext()); + const MCExpr *RelocJalrExpr = + MCSymbolRefExpr::create(JalSym, MCSymbolRefExpr::VK_None, + getContext(), IDLoc); + + TOut.getStreamer().EmitRelocDirective(*TmpExpr, + inMicroMipsMode() ? "R_MICROMIPS_JALR" : "R_MIPS_JALR", + RelocJalrExpr, IDLoc, *STI); + TOut.getStreamer().EmitLabel(TmpLabel); + } Inst = JalrInst; ExpandedJalSym = true; } - if (MCID.mayLoad() || MCID.mayStore()) { + bool IsPCRelativeLoad = (MCID.TSFlags & MipsII::IsPCRelativeLoad) != 0; + if ((MCID.mayLoad() || MCID.mayStore()) && !IsPCRelativeLoad) { // 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++) { @@ -1720,11 +2107,11 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, (OpInfo.OperandType == MCOI::OPERAND_UNKNOWN)) { MCOperand &Op = Inst.getOperand(i); if (Op.isImm()) { - int MemOffset = Op.getImm(); + int64_t MemOffset = Op.getImm(); if (MemOffset < -32768 || MemOffset > 32767) { // Offset can't exceed 16bit value. - expandMemInst(Inst, IDLoc, Instructions, MCID.mayLoad(), true); - return false; + expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad()); + return getParser().hasPendingError(); } } else if (Op.isExpr()) { const MCExpr *Expr = Op.getExpr(); @@ -1733,12 +2120,12 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, static_cast<const MCSymbolRefExpr *>(Expr); if (SR->getKind() == MCSymbolRefExpr::VK_None) { // Expand symbol. - expandMemInst(Inst, IDLoc, Instructions, MCID.mayLoad(), false); - return false; + expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad()); + return getParser().hasPendingError(); } } else if (!isEvaluated(Expr)) { - expandMemInst(Inst, IDLoc, Instructions, MCID.mayLoad(), false); - return false; + expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad()); + return getParser().hasPendingError(); } } } @@ -1746,7 +2133,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, } // if load/store if (inMicroMipsMode()) { - if (MCID.mayLoad()) { + if (MCID.mayLoad() && Inst.getOpcode() != 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]; @@ -1763,8 +2150,8 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, (BaseReg.getReg() == Mips::GP || BaseReg.getReg() == Mips::GP_64)) { - emitRRI(Mips::LWGP_MM, DstReg.getReg(), Mips::GP, MemOffset, - IDLoc, Instructions); + TOut.emitRRI(Mips::LWGP_MM, DstReg.getReg(), Mips::GP, MemOffset, + IDLoc, STI); return false; } } @@ -1780,14 +2167,6 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, switch (Inst.getOpcode()) { default: break; - case Mips::ADDIUS5_MM: - Opnd = Inst.getOperand(2); - if (!Opnd.isImm()) - return Error(IDLoc, "expected immediate operand kind"); - Imm = Opnd.getImm(); - if (Imm < -8 || Imm > 7) - return Error(IDLoc, "immediate operand value out of range"); - break; case Mips::ADDIUSP_MM: Opnd = Inst.getOperand(0); if (!Opnd.isImm()) @@ -1823,16 +2202,6 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, ((Imm % 4 == 0) && Imm < 28 && Imm > 0))) return Error(IDLoc, "immediate operand value out of range"); break; - case Mips::ADDIUR1SP_MM: - Opnd = Inst.getOperand(1); - if (!Opnd.isImm()) - return Error(IDLoc, "expected immediate operand kind"); - Imm = Opnd.getImm(); - if (OffsetToAlignment(Imm, 4LL)) - return Error(IDLoc, "misaligned immediate operand value"); - if (Imm < 0 || Imm > 255) - return Error(IDLoc, "immediate operand value out of range"); - break; case Mips::ANDI16_MM: Opnd = Inst.getOperand(2); if (!Opnd.isImm()) @@ -1851,12 +2220,6 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, if (Imm < -1 || Imm > 14) return Error(IDLoc, "immediate operand value out of range"); break; - case Mips::TEQ_MM: - case Mips::TGE_MM: - case Mips::TGEU_MM: - case Mips::TLT_MM: - case Mips::TLTU_MM: - case Mips::TNE_MM: case Mips::SB16_MM: case Mips::SB16_MMR6: Opnd = Inst.getOperand(2); @@ -1887,21 +2250,47 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, return Error(IDLoc, "immediate operand value out of range"); break; case Mips::ADDIUPC_MM: - MCOperand Opnd = Inst.getOperand(1); + Opnd = Inst.getOperand(1); if (!Opnd.isImm()) return Error(IDLoc, "expected immediate operand kind"); - int Imm = Opnd.getImm(); + Imm = Opnd.getImm(); if ((Imm % 4 != 0) || !isInt<25>(Imm)) return Error(IDLoc, "immediate operand value out of range"); break; + case Mips::LWP_MM: + case Mips::SWP_MM: + if (Inst.getOperand(0).getReg() == Mips::RA) + return Error(IDLoc, "invalid operand for instruction"); + break; + case Mips::MOVEP_MM: + case Mips::MOVEP_MMR6: { + unsigned R0 = Inst.getOperand(0).getReg(); + unsigned R1 = Inst.getOperand(1).getReg(); + bool RegPair = ((R0 == Mips::A1 && R1 == Mips::A2) || + (R0 == Mips::A1 && R1 == Mips::A3) || + (R0 == Mips::A2 && R1 == Mips::A3) || + (R0 == Mips::A0 && R1 == Mips::S5) || + (R0 == Mips::A0 && R1 == Mips::S6) || + (R0 == Mips::A0 && R1 == Mips::A1) || + (R0 == Mips::A0 && R1 == Mips::A2) || + (R0 == Mips::A0 && R1 == Mips::A3)); + if (!RegPair) + return Error(IDLoc, "invalid operand for instruction"); + break; + } } } + bool FillDelaySlot = + MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder(); + if (FillDelaySlot) + TOut.emitDirectiveSetNoReorder(); + MacroExpanderResultTy ExpandResult = - tryExpandInstruction(Inst, IDLoc, Instructions); + tryExpandInstruction(Inst, IDLoc, Out, STI); switch (ExpandResult) { case MER_NotAMacro: - Instructions.push_back(Inst); + Out.EmitInstruction(Inst, *STI); break; case MER_Success: break; @@ -1909,10 +2298,19 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, return true; } + // We know we emitted an instruction on the MER_NotAMacro or MER_Success path. + // If we're in microMIPS mode then we must also set EF_MIPS_MICROMIPS. + if (inMicroMipsMode()) { + TOut.setUsesMicroMips(); + TOut.updateABIInfo(*this); + } + // If this instruction has a delay slot and .set reorder is active, // emit a NOP after it. - if (MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder()) - createNop(hasShortDelaySlot(Inst.getOpcode()), IDLoc, Instructions); + if (FillDelaySlot) { + TOut.emitEmptyDelaySlot(hasShortDelaySlot(Inst), IDLoc, STI); + TOut.emitDirectiveSetReorder(); + } if ((Inst.getOpcode() == Mips::JalOneReg || Inst.getOpcode() == Mips::JalTwoReg || ExpandedJalSym) && @@ -1922,16 +2320,11 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, // If .set reorder has been used, we've already emitted a NOP. // If .set noreorder has been used, we need to emit a NOP at this point. if (!AssemblerOptions.back()->isReorder()) - createNop(hasShortDelaySlot(Inst.getOpcode()), IDLoc, Instructions); + TOut.emitEmptyDelaySlot(hasShortDelaySlot(Inst), IDLoc, + STI); // Load the $gp from the stack. - SmallVector<MCInst, 3> LoadInsts; - createCpRestoreMemOp(true /*IsLoad*/, CpRestoreOffset /*StackOffset*/, - IDLoc, LoadInsts); - - for (const MCInst &Inst : LoadInsts) - Instructions.push_back(Inst); - + TOut.emitGPRestore(CpRestoreOffset, IDLoc, STI); } else Warning(IDLoc, "no .cprestore used in PIC mode"); } @@ -1940,17 +2333,15 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, } MipsAsmParser::MacroExpanderResultTy -MipsAsmParser::tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { +MipsAsmParser::tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI) { switch (Inst.getOpcode()) { default: return MER_NotAMacro; case Mips::LoadImm32: - return expandLoadImm(Inst, true, IDLoc, Instructions) ? MER_Fail - : MER_Success; + return expandLoadImm(Inst, true, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::LoadImm64: - return expandLoadImm(Inst, false, IDLoc, Instructions) ? MER_Fail - : MER_Success; + return expandLoadImm(Inst, false, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::LoadAddrImm32: case Mips::LoadAddrImm64: assert(Inst.getOperand(0).isReg() && "expected register operand kind"); @@ -1960,7 +2351,7 @@ MipsAsmParser::tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, return expandLoadAddress(Inst.getOperand(0).getReg(), Mips::NoRegister, Inst.getOperand(1), Inst.getOpcode() == Mips::LoadAddrImm32, IDLoc, - Instructions) + Out, STI) ? MER_Fail : MER_Success; case Mips::LoadAddrReg32: @@ -1973,24 +2364,25 @@ MipsAsmParser::tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, return expandLoadAddress(Inst.getOperand(0).getReg(), Inst.getOperand(1).getReg(), Inst.getOperand(2), Inst.getOpcode() == Mips::LoadAddrReg32, IDLoc, - Instructions) + Out, STI) ? MER_Fail : MER_Success; case Mips::B_MM_Pseudo: case Mips::B_MMR6_Pseudo: - return expandUncondBranchMMPseudo(Inst, IDLoc, Instructions) ? MER_Fail - : MER_Success; + return expandUncondBranchMMPseudo(Inst, IDLoc, Out, STI) ? MER_Fail + : MER_Success; case Mips::SWM_MM: case Mips::LWM_MM: - return expandLoadStoreMultiple(Inst, IDLoc, Instructions) ? MER_Fail - : MER_Success; + return expandLoadStoreMultiple(Inst, IDLoc, Out, STI) ? MER_Fail + : MER_Success; case Mips::JalOneReg: case Mips::JalTwoReg: - return expandJalWithRegs(Inst, IDLoc, Instructions) ? MER_Fail - : MER_Success; + return expandJalWithRegs(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::BneImm: case Mips::BeqImm: - return expandBranchImm(Inst, IDLoc, Instructions) ? MER_Fail : MER_Success; + case Mips::BEQLImmMacro: + case Mips::BNELImmMacro: + return expandBranchImm(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::BLT: case Mips::BLE: case Mips::BGE: @@ -2023,75 +2415,163 @@ MipsAsmParser::tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, case Mips::BLEULImmMacro: case Mips::BGEULImmMacro: case Mips::BGTULImmMacro: - return expandCondBranches(Inst, IDLoc, Instructions) ? MER_Fail - : MER_Success; + return expandCondBranches(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::SDivMacro: - return expandDiv(Inst, IDLoc, Instructions, false, true) ? MER_Fail - : MER_Success; - case Mips::DSDivMacro: - return expandDiv(Inst, IDLoc, Instructions, true, true) ? MER_Fail + case Mips::SDivIMacro: + case Mips::SRemMacro: + case Mips::SRemIMacro: + return expandDivRem(Inst, IDLoc, Out, STI, false, true) ? MER_Fail : MER_Success; + case Mips::DSDivMacro: + case Mips::DSDivIMacro: + case Mips::DSRemMacro: + case Mips::DSRemIMacro: + return expandDivRem(Inst, IDLoc, Out, STI, true, true) ? MER_Fail + : MER_Success; case Mips::UDivMacro: - return expandDiv(Inst, IDLoc, Instructions, false, false) ? MER_Fail - : MER_Success; - case Mips::DUDivMacro: - return expandDiv(Inst, IDLoc, Instructions, true, false) ? MER_Fail + case Mips::UDivIMacro: + case Mips::URemMacro: + case Mips::URemIMacro: + return expandDivRem(Inst, IDLoc, Out, STI, false, false) ? MER_Fail : MER_Success; + case Mips::DUDivMacro: + case Mips::DUDivIMacro: + case Mips::DURemMacro: + case Mips::DURemIMacro: + return expandDivRem(Inst, IDLoc, Out, STI, true, false) ? MER_Fail + : MER_Success; + case Mips::PseudoTRUNC_W_S: + return expandTrunc(Inst, false, false, IDLoc, Out, STI) ? MER_Fail + : MER_Success; + case Mips::PseudoTRUNC_W_D32: + return expandTrunc(Inst, true, false, IDLoc, Out, STI) ? MER_Fail + : MER_Success; + case Mips::PseudoTRUNC_W_D: + return expandTrunc(Inst, true, true, IDLoc, Out, STI) ? MER_Fail + : MER_Success; + + case Mips::LoadImmSingleGPR: + return expandLoadImmReal(Inst, true, true, false, IDLoc, Out, STI) + ? MER_Fail + : MER_Success; + case Mips::LoadImmSingleFGR: + return expandLoadImmReal(Inst, true, false, false, IDLoc, Out, STI) + ? MER_Fail + : MER_Success; + case Mips::LoadImmDoubleGPR: + return expandLoadImmReal(Inst, false, true, false, IDLoc, Out, STI) + ? MER_Fail + : MER_Success; + case Mips::LoadImmDoubleFGR: + return expandLoadImmReal(Inst, false, false, true, IDLoc, Out, STI) + ? MER_Fail + : MER_Success; + case Mips::LoadImmDoubleFGR_32: + return expandLoadImmReal(Inst, false, false, false, IDLoc, Out, STI) + ? MER_Fail + : MER_Success; case Mips::Ulh: - return expandUlh(Inst, true, IDLoc, Instructions) ? MER_Fail : MER_Success; + return expandUlh(Inst, true, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::Ulhu: - return expandUlh(Inst, false, IDLoc, Instructions) ? MER_Fail : MER_Success; + return expandUlh(Inst, false, IDLoc, Out, STI) ? MER_Fail : MER_Success; + case Mips::Ush: + return expandUsh(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::Ulw: - return expandUlw(Inst, IDLoc, Instructions) ? MER_Fail : MER_Success; + case Mips::Usw: + return expandUxw(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::NORImm: - return expandAliasImmediate(Inst, IDLoc, Instructions) ? MER_Fail - : MER_Success; - case Mips::ADDi: - case Mips::ADDiu: - case Mips::SLTi: - case Mips::SLTiu: + case Mips::NORImm64: + return expandAliasImmediate(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; + case Mips::SLTImm64: + if (isInt<16>(Inst.getOperand(2).getImm())) { + Inst.setOpcode(Mips::SLTi64); + return MER_NotAMacro; + } + return expandAliasImmediate(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; + case Mips::SLTUImm64: + if (isInt<16>(Inst.getOperand(2).getImm())) { + Inst.setOpcode(Mips::SLTiu64); + return MER_NotAMacro; + } + return expandAliasImmediate(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; + case Mips::ADDi: case Mips::ADDi_MM: + case Mips::ADDiu: case Mips::ADDiu_MM: + case Mips::SLTi: case Mips::SLTi_MM: + case Mips::SLTiu: case Mips::SLTiu_MM: if ((Inst.getNumOperands() == 3) && Inst.getOperand(0).isReg() && Inst.getOperand(1).isReg() && Inst.getOperand(2).isImm()) { int64_t ImmValue = Inst.getOperand(2).getImm(); if (isInt<16>(ImmValue)) return MER_NotAMacro; - return expandAliasImmediate(Inst, IDLoc, Instructions) ? MER_Fail - : MER_Success; + return expandAliasImmediate(Inst, IDLoc, Out, STI) ? MER_Fail + : MER_Success; } return MER_NotAMacro; - case Mips::ANDi: - case Mips::ORi: - case Mips::XORi: + case Mips::ANDi: case Mips::ANDi_MM: case Mips::ANDi64: + case Mips::ORi: case Mips::ORi_MM: case Mips::ORi64: + case Mips::XORi: case Mips::XORi_MM: case Mips::XORi64: if ((Inst.getNumOperands() == 3) && Inst.getOperand(0).isReg() && Inst.getOperand(1).isReg() && Inst.getOperand(2).isImm()) { int64_t ImmValue = Inst.getOperand(2).getImm(); if (isUInt<16>(ImmValue)) return MER_NotAMacro; - return expandAliasImmediate(Inst, IDLoc, Instructions) ? MER_Fail - : MER_Success; + return expandAliasImmediate(Inst, IDLoc, Out, STI) ? MER_Fail + : MER_Success; } return MER_NotAMacro; case Mips::ROL: case Mips::ROR: - return expandRotation(Inst, IDLoc, Instructions) ? MER_Fail - : MER_Success; + return expandRotation(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::ROLImm: case Mips::RORImm: - return expandRotationImm(Inst, IDLoc, Instructions) ? MER_Fail - : MER_Success; + return expandRotationImm(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::DROL: case Mips::DROR: - return expandDRotation(Inst, IDLoc, Instructions) ? MER_Fail - : MER_Success; + return expandDRotation(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::DROLImm: case Mips::DRORImm: - return expandDRotationImm(Inst, IDLoc, Instructions) ? MER_Fail - : MER_Success; + return expandDRotationImm(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; + case Mips::ABSMacro: + return expandAbs(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; + case Mips::MULImmMacro: + case Mips::DMULImmMacro: + return expandMulImm(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; + case Mips::MULOMacro: + case Mips::DMULOMacro: + return expandMulO(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; + case Mips::MULOUMacro: + case Mips::DMULOUMacro: + return expandMulOU(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; + case Mips::DMULMacro: + return expandDMULMacro(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; + case Mips::LDMacro: + case Mips::SDMacro: + return expandLoadStoreDMacro(Inst, IDLoc, Out, STI, + Inst.getOpcode() == Mips::LDMacro) + ? MER_Fail + : MER_Success; + case Mips::SEQMacro: + return expandSeq(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; + case Mips::SEQIMacro: + return expandSeqI(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; + case Mips::MFTC0: case Mips::MTTC0: + case Mips::MFTGPR: case Mips::MTTGPR: + case Mips::MFTLO: case Mips::MTTLO: + case Mips::MFTHI: case Mips::MTTHI: + case Mips::MFTACX: case Mips::MTTACX: + case Mips::MFTDSP: case Mips::MTTDSP: + case Mips::MFTC1: case Mips::MTTC1: + case Mips::MFTHC1: case Mips::MTTHC1: + case Mips::CFTC1: case Mips::CTTC1: + return expandMXTRAlias(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; } } bool MipsAsmParser::expandJalWithRegs(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { + MCStreamer &Out, + const MCSubtargetInfo *STI) { + MipsTargetStreamer &TOut = getTargetStreamer(); + // Create a JALR instruction which is going to replace the pseudo-JAL. MCInst JalrInst; JalrInst.setLoc(IDLoc); @@ -2121,14 +2601,14 @@ bool MipsAsmParser::expandJalWithRegs(MCInst &Inst, SMLoc IDLoc, const MCOperand SecondRegOp = Inst.getOperand(1); JalrInst.addOperand(SecondRegOp); } - Instructions.push_back(JalrInst); + Out.EmitInstruction(JalrInst, *STI); // If .set reorder is active and branch instruction has a delay slot, // emit a NOP after it. const MCInstrDesc &MCID = getInstDesc(JalrInst.getOpcode()); - if (MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder()) { - createNop(hasShortDelaySlot(JalrInst.getOpcode()), IDLoc, Instructions); - } + if (MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder()) + TOut.emitEmptyDelaySlot(hasShortDelaySlot(JalrInst), IDLoc, + STI); return false; } @@ -2150,11 +2630,12 @@ template <unsigned N> static bool isShiftedUIntAtAnyPosition(uint64_t x) { /// @param IsAddress True if the immediate represents an address. False if it /// is an integer. /// @param IDLoc Location of the immediate in the source file. -/// @param Instructions The instructions emitted by this expansion. bool MipsAsmParser::loadImmediate(int64_t ImmValue, unsigned DstReg, unsigned SrcReg, bool Is32BitImm, - bool IsAddress, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { + bool IsAddress, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI) { + MipsTargetStreamer &TOut = getTargetStreamer(); + if (!Is32BitImm && !isGP64bit()) { Error(IDLoc, "instruction requires a 64-bit architecture"); return true; @@ -2180,7 +2661,8 @@ bool MipsAsmParser::loadImmediate(int64_t ImmValue, unsigned DstReg, UseSrcReg = true; unsigned TmpReg = DstReg; - if (UseSrcReg && (DstReg == SrcReg)) { + if (UseSrcReg && + getContext().getRegisterInfo()->isSuperOrSubRegisterEq(DstReg, SrcReg)) { // At this point we need AT to perform the expansions and we exit if it is // not available. unsigned ATReg = getATReg(IDLoc); @@ -2197,11 +2679,11 @@ bool MipsAsmParser::loadImmediate(int64_t ImmValue, unsigned DstReg, // traditional assembler behaviour. N32 would normally use addiu for both // integers and addresses. if (IsAddress && !Is32BitImm) { - emitRRI(Mips::DADDiu, DstReg, SrcReg, ImmValue, IDLoc, Instructions); + TOut.emitRRI(Mips::DADDiu, DstReg, SrcReg, ImmValue, IDLoc, STI); return false; } - emitRRI(Mips::ADDiu, DstReg, SrcReg, ImmValue, IDLoc, Instructions); + TOut.emitRRI(Mips::ADDiu, DstReg, SrcReg, ImmValue, IDLoc, STI); return false; } @@ -2213,9 +2695,9 @@ bool MipsAsmParser::loadImmediate(int64_t ImmValue, unsigned DstReg, return true; } - emitRRI(Mips::ORi, TmpReg, ZeroReg, ImmValue, IDLoc, Instructions); + TOut.emitRRI(Mips::ORi, TmpReg, ZeroReg, ImmValue, IDLoc, STI); if (UseSrcReg) - emitRRR(ABI.GetPtrAdduOp(), DstReg, TmpReg, SrcReg, IDLoc, Instructions); + TOut.emitRRR(ABI.GetPtrAdduOp(), DstReg, TmpReg, SrcReg, IDLoc, STI); return false; } @@ -2224,34 +2706,33 @@ bool MipsAsmParser::loadImmediate(int64_t ImmValue, unsigned DstReg, uint16_t Bits31To16 = (ImmValue >> 16) & 0xffff; uint16_t Bits15To0 = ImmValue & 0xffff; - if (!Is32BitImm && !isInt<32>(ImmValue)) { // Traditional behaviour seems to special case this particular value. It's // not clear why other masks are handled differently. if (ImmValue == 0xffffffff) { - emitRI(Mips::LUi, TmpReg, 0xffff, IDLoc, Instructions); - emitRRI(Mips::DSRL32, TmpReg, TmpReg, 0, IDLoc, Instructions); + TOut.emitRI(Mips::LUi, TmpReg, 0xffff, IDLoc, STI); + TOut.emitRRI(Mips::DSRL32, TmpReg, TmpReg, 0, IDLoc, STI); if (UseSrcReg) - emitRRR(AdduOp, DstReg, TmpReg, SrcReg, IDLoc, Instructions); + TOut.emitRRR(AdduOp, DstReg, TmpReg, SrcReg, IDLoc, STI); return false; } // Expand to an ORi instead of a LUi to avoid sign-extending into the // upper 32 bits. - emitRRI(Mips::ORi, TmpReg, ZeroReg, Bits31To16, IDLoc, Instructions); - emitRRI(Mips::DSLL, TmpReg, TmpReg, 16, IDLoc, Instructions); + TOut.emitRRI(Mips::ORi, TmpReg, ZeroReg, Bits31To16, IDLoc, STI); + TOut.emitRRI(Mips::DSLL, TmpReg, TmpReg, 16, IDLoc, STI); if (Bits15To0) - emitRRI(Mips::ORi, TmpReg, TmpReg, Bits15To0, IDLoc, Instructions); + TOut.emitRRI(Mips::ORi, TmpReg, TmpReg, Bits15To0, IDLoc, STI); if (UseSrcReg) - emitRRR(AdduOp, DstReg, TmpReg, SrcReg, IDLoc, Instructions); + TOut.emitRRR(AdduOp, DstReg, TmpReg, SrcReg, IDLoc, STI); return false; } - emitRI(Mips::LUi, TmpReg, Bits31To16, IDLoc, Instructions); + TOut.emitRI(Mips::LUi, TmpReg, Bits31To16, IDLoc, STI); if (Bits15To0) - emitRRI(Mips::ORi, TmpReg, TmpReg, Bits15To0, IDLoc, Instructions); + TOut.emitRRI(Mips::ORi, TmpReg, TmpReg, Bits15To0, IDLoc, STI); if (UseSrcReg) - emitRRR(AdduOp, DstReg, TmpReg, SrcReg, IDLoc, Instructions); + TOut.emitRRR(AdduOp, DstReg, TmpReg, SrcReg, IDLoc, STI); return false; } @@ -2267,11 +2748,11 @@ bool MipsAsmParser::loadImmediate(int64_t ImmValue, unsigned DstReg, unsigned LastSet = findLastSet((uint64_t)ImmValue); unsigned ShiftAmount = FirstSet - (15 - (LastSet - FirstSet)); uint16_t Bits = (ImmValue >> ShiftAmount) & 0xffff; - emitRRI(Mips::ORi, TmpReg, ZeroReg, Bits, IDLoc, Instructions); - emitRRI(Mips::DSLL, TmpReg, TmpReg, ShiftAmount, IDLoc, Instructions); + TOut.emitRRI(Mips::ORi, TmpReg, ZeroReg, Bits, IDLoc, STI); + TOut.emitRRI(Mips::DSLL, TmpReg, TmpReg, ShiftAmount, IDLoc, STI); if (UseSrcReg) - emitRRR(AdduOp, DstReg, TmpReg, SrcReg, IDLoc, Instructions); + TOut.emitRRR(AdduOp, DstReg, TmpReg, SrcReg, IDLoc, STI); return false; } @@ -2284,7 +2765,7 @@ bool MipsAsmParser::loadImmediate(int64_t ImmValue, unsigned DstReg, // Load bits 32-63 of ImmValue into bits 0-31 of the temporary register. if (loadImmediate(ImmValue >> 32, TmpReg, Mips::NoRegister, true, false, - IDLoc, Instructions)) + IDLoc, Out, STI)) return false; // Shift and accumulate into the register. If a 16-bit chunk is zero, then @@ -2294,9 +2775,8 @@ bool MipsAsmParser::loadImmediate(int64_t ImmValue, unsigned DstReg, uint16_t ImmChunk = (ImmValue >> BitNum) & 0xffff; if (ImmChunk != 0) { - emitAppropriateDSLL(TmpReg, TmpReg, ShiftCarriedForwards, IDLoc, - Instructions); - emitRRI(Mips::ORi, TmpReg, TmpReg, ImmChunk, IDLoc, Instructions); + TOut.emitDSLL(TmpReg, TmpReg, ShiftCarriedForwards, IDLoc, STI); + TOut.emitRRI(Mips::ORi, TmpReg, TmpReg, ImmChunk, IDLoc, STI); ShiftCarriedForwards = 0; } @@ -2306,24 +2786,23 @@ bool MipsAsmParser::loadImmediate(int64_t ImmValue, unsigned DstReg, // Finish any remaining shifts left by trailing zeros. if (ShiftCarriedForwards) - emitAppropriateDSLL(TmpReg, TmpReg, ShiftCarriedForwards, IDLoc, - Instructions); + TOut.emitDSLL(TmpReg, TmpReg, ShiftCarriedForwards, IDLoc, STI); if (UseSrcReg) - emitRRR(AdduOp, DstReg, TmpReg, SrcReg, IDLoc, Instructions); + TOut.emitRRR(AdduOp, DstReg, TmpReg, SrcReg, IDLoc, STI); return false; } bool MipsAsmParser::expandLoadImm(MCInst &Inst, bool Is32BitImm, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { + MCStreamer &Out, const MCSubtargetInfo *STI) { const MCOperand &ImmOp = Inst.getOperand(1); assert(ImmOp.isImm() && "expected immediate operand kind"); const MCOperand &DstRegOp = Inst.getOperand(0); assert(DstRegOp.isReg() && "expected register operand kind"); if (loadImmediate(ImmOp.getImm(), DstRegOp.getReg(), Mips::NoRegister, - Is32BitImm, false, IDLoc, Instructions)) + Is32BitImm, false, IDLoc, Out, STI)) return true; return false; @@ -2332,7 +2811,8 @@ bool MipsAsmParser::expandLoadImm(MCInst &Inst, bool Is32BitImm, SMLoc IDLoc, bool MipsAsmParser::expandLoadAddress(unsigned DstReg, unsigned BaseReg, const MCOperand &Offset, bool Is32BitAddress, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { + MCStreamer &Out, + 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. @@ -2341,49 +2821,218 @@ bool MipsAsmParser::expandLoadAddress(unsigned DstReg, unsigned BaseReg, Error(IDLoc, "la used to load 64-bit address"); // Continue as if we had 'dla' instead. Is32BitAddress = false; + return true; } // dla requires 64-bit addresses. - if (!Is32BitAddress && !ABI.ArePtrs64bit()) { + if (!Is32BitAddress && !hasMips3()) { Error(IDLoc, "instruction requires a 64-bit architecture"); return true; } if (!Offset.isImm()) return loadAndAddSymbolAddress(Offset.getExpr(), DstReg, BaseReg, - Is32BitAddress, IDLoc, Instructions); + Is32BitAddress, IDLoc, Out, STI); + + if (!ABI.ArePtrs64bit()) { + // Continue as if we had 'la' whether we had 'la' or 'dla'. + Is32BitAddress = true; + } return loadImmediate(Offset.getImm(), DstReg, BaseReg, Is32BitAddress, true, - IDLoc, Instructions); + IDLoc, Out, STI); } -bool MipsAsmParser::loadAndAddSymbolAddress( - const MCExpr *SymExpr, unsigned DstReg, unsigned SrcReg, bool Is32BitSym, - SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { +bool MipsAsmParser::loadAndAddSymbolAddress(const MCExpr *SymExpr, + unsigned DstReg, unsigned SrcReg, + bool Is32BitSym, SMLoc IDLoc, + MCStreamer &Out, + const MCSubtargetInfo *STI) { + // FIXME: These expansions do not respect -mxgot. + MipsTargetStreamer &TOut = getTargetStreamer(); + bool UseSrcReg = SrcReg != Mips::NoRegister; warnIfNoMacro(IDLoc); - const MCExpr *Symbol = cast<MCExpr>(SymExpr); - const MipsMCExpr *HiExpr = MipsMCExpr::create( - MCSymbolRefExpr::VK_Mips_ABS_HI, Symbol, getContext()); - const MipsMCExpr *LoExpr = MipsMCExpr::create( - MCSymbolRefExpr::VK_Mips_ABS_LO, Symbol, getContext()); + if (inPicMode() && ABI.IsO32()) { + MCValue Res; + if (!SymExpr->evaluateAsRelocatable(Res, nullptr, nullptr)) { + Error(IDLoc, "expected relocatable expression"); + return true; + } + if (Res.getSymB() != nullptr) { + Error(IDLoc, "expected relocatable expression with only one symbol"); + return true; + } - bool UseSrcReg = SrcReg != Mips::NoRegister; + // The case where the result register is $25 is somewhat special. If the + // symbol in the final relocation is external and not modified with a + // constant then we must use R_MIPS_CALL16 instead of R_MIPS_GOT16. + if ((DstReg == Mips::T9 || DstReg == Mips::T9_64) && !UseSrcReg && + Res.getConstant() == 0 && + !(Res.getSymA()->getSymbol().isInSection() || + Res.getSymA()->getSymbol().isTemporary() || + (Res.getSymA()->getSymbol().isELF() && + cast<MCSymbolELF>(Res.getSymA()->getSymbol()).getBinding() == + ELF::STB_LOCAL))) { + const MCExpr *CallExpr = + MipsMCExpr::create(MipsMCExpr::MEK_GOT_CALL, SymExpr, getContext()); + TOut.emitRRX(Mips::LW, DstReg, ABI.GetGlobalPtr(), + MCOperand::createExpr(CallExpr), IDLoc, STI); + return false; + } + + // The remaining cases are: + // External GOT: lw $tmp, %got(symbol+offset)($gp) + // >addiu $tmp, $tmp, %lo(offset) + // >addiu $rd, $tmp, $rs + // Local GOT: lw $tmp, %got(symbol+offset)($gp) + // addiu $tmp, $tmp, %lo(symbol+offset)($gp) + // >addiu $rd, $tmp, $rs + // The addiu's marked with a '>' may be omitted if they are redundant. If + // this happens then the last instruction must use $rd as the result + // register. + const MipsMCExpr *GotExpr = + MipsMCExpr::create(MipsMCExpr::MEK_GOT, SymExpr, getContext()); + const MCExpr *LoExpr = nullptr; + if (Res.getSymA()->getSymbol().isInSection() || + Res.getSymA()->getSymbol().isTemporary()) + LoExpr = MipsMCExpr::create(MipsMCExpr::MEK_LO, SymExpr, getContext()); + else if (Res.getConstant() != 0) { + // External symbols fully resolve the symbol with just the %got(symbol) + // but we must still account for any offset to the symbol for expressions + // like symbol+8. + LoExpr = MCConstantExpr::create(Res.getConstant(), getContext()); + } + + unsigned TmpReg = DstReg; + if (UseSrcReg && + getContext().getRegisterInfo()->isSuperOrSubRegisterEq(DstReg, + SrcReg)) { + // If $rs is the same as $rd, we need to use AT. + // If it is not available we exit. + unsigned ATReg = getATReg(IDLoc); + if (!ATReg) + return true; + TmpReg = ATReg; + } + + TOut.emitRRX(Mips::LW, TmpReg, ABI.GetGlobalPtr(), + MCOperand::createExpr(GotExpr), IDLoc, STI); + + if (LoExpr) + TOut.emitRRX(Mips::ADDiu, TmpReg, TmpReg, MCOperand::createExpr(LoExpr), + IDLoc, STI); + + if (UseSrcReg) + TOut.emitRRR(Mips::ADDu, DstReg, TmpReg, SrcReg, IDLoc, STI); + + return false; + } + + if (inPicMode() && ABI.ArePtrs64bit()) { + MCValue Res; + if (!SymExpr->evaluateAsRelocatable(Res, nullptr, nullptr)) { + Error(IDLoc, "expected relocatable expression"); + return true; + } + if (Res.getSymB() != nullptr) { + Error(IDLoc, "expected relocatable expression with only one symbol"); + return true; + } + + // The case where the result register is $25 is somewhat special. If the + // symbol in the final relocation is external and not modified with a + // constant then we must use R_MIPS_CALL16 instead of R_MIPS_GOT_DISP. + if ((DstReg == Mips::T9 || DstReg == Mips::T9_64) && !UseSrcReg && + Res.getConstant() == 0 && + !(Res.getSymA()->getSymbol().isInSection() || + Res.getSymA()->getSymbol().isTemporary() || + (Res.getSymA()->getSymbol().isELF() && + cast<MCSymbolELF>(Res.getSymA()->getSymbol()).getBinding() == + ELF::STB_LOCAL))) { + const MCExpr *CallExpr = + MipsMCExpr::create(MipsMCExpr::MEK_GOT_CALL, SymExpr, getContext()); + TOut.emitRRX(Mips::LD, DstReg, ABI.GetGlobalPtr(), + MCOperand::createExpr(CallExpr), IDLoc, STI); + return false; + } + + // The remaining cases are: + // Small offset: ld $tmp, %got_disp(symbol)($gp) + // >daddiu $tmp, $tmp, offset + // >daddu $rd, $tmp, $rs + // The daddiu's marked with a '>' may be omitted if they are redundant. If + // this happens then the last instruction must use $rd as the result + // register. + const MipsMCExpr *GotExpr = MipsMCExpr::create(MipsMCExpr::MEK_GOT_DISP, + Res.getSymA(), + getContext()); + const MCExpr *LoExpr = nullptr; + if (Res.getConstant() != 0) { + // Symbols fully resolve with just the %got_disp(symbol) but we + // must still account for any offset to the symbol for + // expressions like symbol+8. + LoExpr = MCConstantExpr::create(Res.getConstant(), getContext()); + + // FIXME: Offsets greater than 16 bits are not yet implemented. + // FIXME: The correct range is a 32-bit sign-extended number. + if (Res.getConstant() < -0x8000 || Res.getConstant() > 0x7fff) { + Error(IDLoc, "macro instruction uses large offset, which is not " + "currently supported"); + return true; + } + } + + unsigned TmpReg = DstReg; + if (UseSrcReg && + getContext().getRegisterInfo()->isSuperOrSubRegisterEq(DstReg, + SrcReg)) { + // If $rs is the same as $rd, we need to use AT. + // If it is not available we exit. + unsigned ATReg = getATReg(IDLoc); + if (!ATReg) + return true; + TmpReg = ATReg; + } + + TOut.emitRRX(Mips::LD, TmpReg, ABI.GetGlobalPtr(), + MCOperand::createExpr(GotExpr), IDLoc, STI); + + if (LoExpr) + TOut.emitRRX(Mips::DADDiu, TmpReg, TmpReg, MCOperand::createExpr(LoExpr), + IDLoc, STI); + + if (UseSrcReg) + TOut.emitRRR(Mips::DADDu, DstReg, TmpReg, SrcReg, IDLoc, STI); + + return false; + } + + const MipsMCExpr *HiExpr = + MipsMCExpr::create(MipsMCExpr::MEK_HI, SymExpr, getContext()); + const MipsMCExpr *LoExpr = + MipsMCExpr::create(MipsMCExpr::MEK_LO, SymExpr, getContext()); // This is the 64-bit symbol address expansion. if (ABI.ArePtrs64bit() && isGP64bit()) { - // We always need AT for the 64-bit expansion. - // If it is not available we exit. - unsigned ATReg = getATReg(IDLoc); - if (!ATReg) - return true; + // We need AT for the 64-bit expansion in the cases where the optional + // source register is the destination register and for the superscalar + // scheduled form. + // + // If it is not available we exit if the destination is the same as the + // source register. + + const MipsMCExpr *HighestExpr = + MipsMCExpr::create(MipsMCExpr::MEK_HIGHEST, SymExpr, getContext()); + const MipsMCExpr *HigherExpr = + MipsMCExpr::create(MipsMCExpr::MEK_HIGHER, SymExpr, getContext()); + + bool RdRegIsRsReg = + getContext().getRegisterInfo()->isSuperOrSubRegisterEq(DstReg, SrcReg); - const MipsMCExpr *HighestExpr = MipsMCExpr::create( - MCSymbolRefExpr::VK_Mips_HIGHEST, Symbol, getContext()); - const MipsMCExpr *HigherExpr = MipsMCExpr::create( - MCSymbolRefExpr::VK_Mips_HIGHER, Symbol, getContext()); + if (canUseATReg() && UseSrcReg && RdRegIsRsReg) { + unsigned ATReg = getATReg(IDLoc); - if (UseSrcReg && (DstReg == SrcReg)) { // If $rs is the same as $rd: // (d)la $rd, sym($rd) => lui $at, %highest(sym) // daddiu $at, $at, %higher(sym) @@ -2392,43 +3041,78 @@ bool MipsAsmParser::loadAndAddSymbolAddress( // dsll $at, $at, 16 // daddiu $at, $at, %lo(sym) // daddu $rd, $at, $rd - emitRX(Mips::LUi, ATReg, MCOperand::createExpr(HighestExpr), IDLoc, - Instructions); - emitRRX(Mips::DADDiu, ATReg, ATReg, MCOperand::createExpr(HigherExpr), - IDLoc, Instructions); - emitRRI(Mips::DSLL, ATReg, ATReg, 16, IDLoc, Instructions); - emitRRX(Mips::DADDiu, ATReg, ATReg, MCOperand::createExpr(HiExpr), IDLoc, - Instructions); - emitRRI(Mips::DSLL, ATReg, ATReg, 16, IDLoc, Instructions); - emitRRX(Mips::DADDiu, ATReg, ATReg, MCOperand::createExpr(LoExpr), IDLoc, - Instructions); - emitRRR(Mips::DADDu, DstReg, ATReg, SrcReg, IDLoc, Instructions); + TOut.emitRX(Mips::LUi, ATReg, MCOperand::createExpr(HighestExpr), IDLoc, + STI); + TOut.emitRRX(Mips::DADDiu, ATReg, ATReg, + MCOperand::createExpr(HigherExpr), IDLoc, STI); + TOut.emitRRI(Mips::DSLL, ATReg, ATReg, 16, IDLoc, STI); + TOut.emitRRX(Mips::DADDiu, ATReg, ATReg, MCOperand::createExpr(HiExpr), + IDLoc, STI); + TOut.emitRRI(Mips::DSLL, ATReg, ATReg, 16, IDLoc, STI); + TOut.emitRRX(Mips::DADDiu, ATReg, ATReg, MCOperand::createExpr(LoExpr), + IDLoc, STI); + TOut.emitRRR(Mips::DADDu, DstReg, ATReg, SrcReg, IDLoc, STI); return false; - } + } else if (canUseATReg() && !RdRegIsRsReg) { + unsigned ATReg = getATReg(IDLoc); + + // If the $rs is different from $rd or if $rs isn't specified and we + // have $at available: + // (d)la $rd, sym/sym($rs) => lui $rd, %highest(sym) + // lui $at, %hi(sym) + // daddiu $rd, $rd, %higher(sym) + // daddiu $at, $at, %lo(sym) + // dsll32 $rd, $rd, 0 + // daddu $rd, $rd, $at + // (daddu $rd, $rd, $rs) + // + // Which is preferred for superscalar issue. + TOut.emitRX(Mips::LUi, DstReg, MCOperand::createExpr(HighestExpr), IDLoc, + STI); + TOut.emitRX(Mips::LUi, ATReg, MCOperand::createExpr(HiExpr), IDLoc, STI); + TOut.emitRRX(Mips::DADDiu, DstReg, DstReg, + MCOperand::createExpr(HigherExpr), IDLoc, STI); + TOut.emitRRX(Mips::DADDiu, ATReg, ATReg, MCOperand::createExpr(LoExpr), + IDLoc, STI); + TOut.emitRRI(Mips::DSLL32, DstReg, DstReg, 0, IDLoc, STI); + TOut.emitRRR(Mips::DADDu, DstReg, DstReg, ATReg, IDLoc, STI); + if (UseSrcReg) + TOut.emitRRR(Mips::DADDu, DstReg, DstReg, SrcReg, IDLoc, STI); - // Otherwise, if the $rs is different from $rd or if $rs isn't specified: - // (d)la $rd, sym/sym($rs) => lui $rd, %highest(sym) - // lui $at, %hi(sym) - // daddiu $rd, $rd, %higher(sym) - // daddiu $at, $at, %lo(sym) - // dsll32 $rd, $rd, 0 - // daddu $rd, $rd, $at - // (daddu $rd, $rd, $rs) - emitRX(Mips::LUi, DstReg, MCOperand::createExpr(HighestExpr), IDLoc, - Instructions); - emitRX(Mips::LUi, ATReg, MCOperand::createExpr(HiExpr), IDLoc, - Instructions); - emitRRX(Mips::DADDiu, DstReg, DstReg, MCOperand::createExpr(HigherExpr), - IDLoc, Instructions); - emitRRX(Mips::DADDiu, ATReg, ATReg, MCOperand::createExpr(LoExpr), IDLoc, - Instructions); - emitRRI(Mips::DSLL32, DstReg, DstReg, 0, IDLoc, Instructions); - emitRRR(Mips::DADDu, DstReg, DstReg, ATReg, IDLoc, Instructions); - if (UseSrcReg) - emitRRR(Mips::DADDu, DstReg, DstReg, SrcReg, IDLoc, Instructions); + return false; + } else if (!canUseATReg() && !RdRegIsRsReg) { + // Otherwise, synthesize the address in the destination register + // serially: + // (d)la $rd, sym/sym($rs) => lui $rd, %highest(sym) + // daddiu $rd, $rd, %higher(sym) + // dsll $rd, $rd, 16 + // daddiu $rd, $rd, %hi(sym) + // dsll $rd, $rd, 16 + // daddiu $rd, $rd, %lo(sym) + TOut.emitRX(Mips::LUi, DstReg, MCOperand::createExpr(HighestExpr), IDLoc, + STI); + TOut.emitRRX(Mips::DADDiu, DstReg, DstReg, + MCOperand::createExpr(HigherExpr), IDLoc, STI); + TOut.emitRRI(Mips::DSLL, DstReg, DstReg, 16, IDLoc, STI); + TOut.emitRRX(Mips::DADDiu, DstReg, DstReg, + MCOperand::createExpr(HiExpr), IDLoc, STI); + TOut.emitRRI(Mips::DSLL, DstReg, DstReg, 16, IDLoc, STI); + TOut.emitRRX(Mips::DADDiu, DstReg, DstReg, + MCOperand::createExpr(LoExpr), IDLoc, STI); + if (UseSrcReg) + TOut.emitRRR(Mips::DADDu, DstReg, DstReg, SrcReg, IDLoc, STI); - return false; + return false; + } else { + // We have a case where SrcReg == DstReg and we don't have $at + // available. We can't expand this case, so error out appropriately. + assert(SrcReg == DstReg && !canUseATReg() && + "Could have expanded dla but didn't?"); + reportParseError(IDLoc, + "pseudo-instruction requires $at, which is not available"); + return true; + } } // And now, the 32-bit symbol address expansion: @@ -2441,7 +3125,8 @@ bool MipsAsmParser::loadAndAddSymbolAddress( // ori $rd, $rd, %lo(sym) // (addu $rd, $rd, $rs) unsigned TmpReg = DstReg; - if (UseSrcReg && (DstReg == SrcReg)) { + if (UseSrcReg && + getContext().getRegisterInfo()->isSuperOrSubRegisterEq(DstReg, SrcReg)) { // If $rs is the same as $rd, we need to use AT. // If it is not available we exit. unsigned ATReg = getATReg(IDLoc); @@ -2450,20 +3135,320 @@ bool MipsAsmParser::loadAndAddSymbolAddress( TmpReg = ATReg; } - emitRX(Mips::LUi, TmpReg, MCOperand::createExpr(HiExpr), IDLoc, Instructions); - emitRRX(Mips::ADDiu, TmpReg, TmpReg, MCOperand::createExpr(LoExpr), IDLoc, - Instructions); + TOut.emitRX(Mips::LUi, TmpReg, MCOperand::createExpr(HiExpr), IDLoc, STI); + TOut.emitRRX(Mips::ADDiu, TmpReg, TmpReg, MCOperand::createExpr(LoExpr), + IDLoc, STI); if (UseSrcReg) - emitRRR(Mips::ADDu, DstReg, TmpReg, SrcReg, IDLoc, Instructions); + TOut.emitRRR(Mips::ADDu, DstReg, TmpReg, SrcReg, IDLoc, STI); else - assert(DstReg == TmpReg); + assert( + getContext().getRegisterInfo()->isSuperOrSubRegisterEq(DstReg, TmpReg)); + + return false; +} + +// Each double-precision register DO-D15 overlaps with two of the single +// precision registers F0-F31. As an example, all of the following hold true: +// D0 + 1 == F1, F1 + 1 == D1, F1 + 1 == F2, depending on the context. +static unsigned nextReg(unsigned Reg) { + if (MipsMCRegisterClasses[Mips::FGR32RegClassID].contains(Reg)) + return Reg == (unsigned)Mips::F31 ? (unsigned)Mips::F0 : Reg + 1; + switch (Reg) { + default: llvm_unreachable("Unknown register in assembly macro expansion!"); + case Mips::ZERO: return Mips::AT; + case Mips::AT: return Mips::V0; + case Mips::V0: return Mips::V1; + case Mips::V1: return Mips::A0; + case Mips::A0: return Mips::A1; + case Mips::A1: return Mips::A2; + case Mips::A2: return Mips::A3; + case Mips::A3: return Mips::T0; + case Mips::T0: return Mips::T1; + case Mips::T1: return Mips::T2; + case Mips::T2: return Mips::T3; + case Mips::T3: return Mips::T4; + case Mips::T4: return Mips::T5; + case Mips::T5: return Mips::T6; + case Mips::T6: return Mips::T7; + case Mips::T7: return Mips::S0; + case Mips::S0: return Mips::S1; + case Mips::S1: return Mips::S2; + case Mips::S2: return Mips::S3; + case Mips::S3: return Mips::S4; + case Mips::S4: return Mips::S5; + case Mips::S5: return Mips::S6; + case Mips::S6: return Mips::S7; + case Mips::S7: return Mips::T8; + case Mips::T8: return Mips::T9; + case Mips::T9: return Mips::K0; + case Mips::K0: return Mips::K1; + case Mips::K1: return Mips::GP; + case Mips::GP: return Mips::SP; + case Mips::SP: return Mips::FP; + case Mips::FP: return Mips::RA; + case Mips::RA: return Mips::ZERO; + case Mips::D0: return Mips::F1; + case Mips::D1: return Mips::F3; + case Mips::D2: return Mips::F5; + case Mips::D3: return Mips::F7; + case Mips::D4: return Mips::F9; + case Mips::D5: return Mips::F11; + case Mips::D6: return Mips::F13; + case Mips::D7: return Mips::F15; + case Mips::D8: return Mips::F17; + case Mips::D9: return Mips::F19; + case Mips::D10: return Mips::F21; + case Mips::D11: return Mips::F23; + case Mips::D12: return Mips::F25; + case Mips::D13: return Mips::F27; + case Mips::D14: return Mips::F29; + case Mips::D15: return Mips::F31; + } +} + +// FIXME: This method is too general. In principle we should compute the number +// of instructions required to synthesize the immediate inline compared to +// synthesizing the address inline and relying on non .text sections. +// For static O32 and N32 this may yield a small benefit, for static N64 this is +// likely to yield a much larger benefit as we have to synthesize a 64bit +// address to load a 64 bit value. +bool MipsAsmParser::emitPartialAddress(MipsTargetStreamer &TOut, SMLoc IDLoc, + MCSymbol *Sym) { + unsigned ATReg = getATReg(IDLoc); + if (!ATReg) + return true; + + if(IsPicEnabled) { + const MCExpr *GotSym = + MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + const MipsMCExpr *GotExpr = + MipsMCExpr::create(MipsMCExpr::MEK_GOT, GotSym, getContext()); + + if(isABI_O32() || isABI_N32()) { + TOut.emitRRX(Mips::LW, ATReg, Mips::GP, MCOperand::createExpr(GotExpr), + IDLoc, STI); + } else { //isABI_N64() + TOut.emitRRX(Mips::LD, ATReg, Mips::GP, MCOperand::createExpr(GotExpr), + IDLoc, STI); + } + } else { //!IsPicEnabled + const MCExpr *HiSym = + MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + const MipsMCExpr *HiExpr = + MipsMCExpr::create(MipsMCExpr::MEK_HI, HiSym, getContext()); + + // FIXME: This is technically correct but gives a different result to gas, + // but gas is incomplete there (it has a fixme noting it doesn't work with + // 64-bit addresses). + // FIXME: With -msym32 option, the address expansion for N64 should probably + // use the O32 / N32 case. It's safe to use the 64 address expansion as the + // symbol's value is considered sign extended. + if(isABI_O32() || isABI_N32()) { + TOut.emitRX(Mips::LUi, ATReg, MCOperand::createExpr(HiExpr), IDLoc, STI); + } else { //isABI_N64() + const MCExpr *HighestSym = + MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + const MipsMCExpr *HighestExpr = + MipsMCExpr::create(MipsMCExpr::MEK_HIGHEST, HighestSym, getContext()); + const MCExpr *HigherSym = + MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + const MipsMCExpr *HigherExpr = + MipsMCExpr::create(MipsMCExpr::MEK_HIGHER, HigherSym, getContext()); + + TOut.emitRX(Mips::LUi, ATReg, MCOperand::createExpr(HighestExpr), IDLoc, + STI); + TOut.emitRRX(Mips::DADDiu, ATReg, ATReg, + MCOperand::createExpr(HigherExpr), IDLoc, STI); + TOut.emitRRI(Mips::DSLL, ATReg, ATReg, 16, IDLoc, STI); + TOut.emitRRX(Mips::DADDiu, ATReg, ATReg, MCOperand::createExpr(HiExpr), + IDLoc, STI); + TOut.emitRRI(Mips::DSLL, ATReg, ATReg, 16, IDLoc, STI); + } + } + return false; +} + +bool MipsAsmParser::expandLoadImmReal(MCInst &Inst, bool IsSingle, bool IsGPR, + bool Is64FPU, SMLoc IDLoc, + MCStreamer &Out, + const MCSubtargetInfo *STI) { + MipsTargetStreamer &TOut = getTargetStreamer(); + assert(Inst.getNumOperands() == 2 && "Invalid operand count"); + assert(Inst.getOperand(0).isReg() && Inst.getOperand(1).isImm() && + "Invalid instruction operand."); + + unsigned FirstReg = Inst.getOperand(0).getReg(); + uint64_t ImmOp64 = Inst.getOperand(1).getImm(); + + uint32_t HiImmOp64 = (ImmOp64 & 0xffffffff00000000) >> 32; + // If ImmOp64 is AsmToken::Integer type (all bits set to zero in the + // exponent field), convert it to double (e.g. 1 to 1.0) + if ((HiImmOp64 & 0x7ff00000) == 0) { + APFloat RealVal(APFloat::IEEEdouble(), ImmOp64); + ImmOp64 = RealVal.bitcastToAPInt().getZExtValue(); + } + + uint32_t LoImmOp64 = ImmOp64 & 0xffffffff; + HiImmOp64 = (ImmOp64 & 0xffffffff00000000) >> 32; + + if (IsSingle) { + // Conversion of a double in an uint64_t to a float in a uint32_t, + // retaining the bit pattern of a float. + uint32_t ImmOp32; + double doubleImm = BitsToDouble(ImmOp64); + float tmp_float = static_cast<float>(doubleImm); + ImmOp32 = FloatToBits(tmp_float); + + if (IsGPR) { + if (loadImmediate(ImmOp32, FirstReg, Mips::NoRegister, true, true, IDLoc, + Out, STI)) + return true; + return false; + } else { + unsigned ATReg = getATReg(IDLoc); + if (!ATReg) + return true; + if (LoImmOp64 == 0) { + if (loadImmediate(ImmOp32, ATReg, Mips::NoRegister, true, true, IDLoc, + Out, STI)) + return true; + TOut.emitRR(Mips::MTC1, FirstReg, ATReg, IDLoc, STI); + return false; + } + + MCSection *CS = getStreamer().getCurrentSectionOnly(); + // FIXME: Enhance this expansion to use the .lit4 & .lit8 sections + // where appropriate. + MCSection *ReadOnlySection = getContext().getELFSection( + ".rodata", ELF::SHT_PROGBITS, ELF::SHF_ALLOC); + + MCSymbol *Sym = getContext().createTempSymbol(); + const MCExpr *LoSym = + MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + const MipsMCExpr *LoExpr = + MipsMCExpr::create(MipsMCExpr::MEK_LO, LoSym, getContext()); + + getStreamer().SwitchSection(ReadOnlySection); + getStreamer().EmitLabel(Sym, IDLoc); + getStreamer().EmitIntValue(ImmOp32, 4); + getStreamer().SwitchSection(CS); + + if(emitPartialAddress(TOut, IDLoc, Sym)) + return true; + TOut.emitRRX(Mips::LWC1, FirstReg, ATReg, + MCOperand::createExpr(LoExpr), IDLoc, STI); + } + return false; + } + + // if(!IsSingle) + unsigned ATReg = getATReg(IDLoc); + if (!ATReg) + return true; + + if (IsGPR) { + if (LoImmOp64 == 0) { + if(isABI_N32() || isABI_N64()) { + if (loadImmediate(HiImmOp64, FirstReg, Mips::NoRegister, false, true, + IDLoc, Out, STI)) + return true; + return false; + } else { + if (loadImmediate(HiImmOp64, FirstReg, Mips::NoRegister, true, true, + IDLoc, Out, STI)) + return true; + + if (loadImmediate(0, nextReg(FirstReg), Mips::NoRegister, true, true, + IDLoc, Out, STI)) + return true; + return false; + } + } + + MCSection *CS = getStreamer().getCurrentSectionOnly(); + MCSection *ReadOnlySection = getContext().getELFSection( + ".rodata", ELF::SHT_PROGBITS, ELF::SHF_ALLOC); + + MCSymbol *Sym = getContext().createTempSymbol(); + const MCExpr *LoSym = + MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + const MipsMCExpr *LoExpr = + MipsMCExpr::create(MipsMCExpr::MEK_LO, LoSym, getContext()); + + getStreamer().SwitchSection(ReadOnlySection); + getStreamer().EmitLabel(Sym, IDLoc); + getStreamer().EmitIntValue(HiImmOp64, 4); + getStreamer().EmitIntValue(LoImmOp64, 4); + getStreamer().SwitchSection(CS); + + if(emitPartialAddress(TOut, IDLoc, Sym)) + return true; + if(isABI_N64()) + TOut.emitRRX(Mips::DADDiu, ATReg, ATReg, + MCOperand::createExpr(LoExpr), IDLoc, STI); + else + TOut.emitRRX(Mips::ADDiu, ATReg, ATReg, + MCOperand::createExpr(LoExpr), IDLoc, STI); + + if(isABI_N32() || isABI_N64()) + TOut.emitRRI(Mips::LD, FirstReg, ATReg, 0, IDLoc, STI); + else { + TOut.emitRRI(Mips::LW, FirstReg, ATReg, 0, IDLoc, STI); + TOut.emitRRI(Mips::LW, nextReg(FirstReg), ATReg, 4, IDLoc, STI); + } + return false; + } else { // if(!IsGPR && !IsSingle) + if ((LoImmOp64 == 0) && + !((HiImmOp64 & 0xffff0000) && (HiImmOp64 & 0x0000ffff))) { + // FIXME: In the case where the constant is zero, we can load the + // register directly from the zero register. + if (loadImmediate(HiImmOp64, ATReg, Mips::NoRegister, true, true, IDLoc, + Out, STI)) + return true; + if (isABI_N32() || isABI_N64()) + TOut.emitRR(Mips::DMTC1, FirstReg, ATReg, IDLoc, STI); + else if (hasMips32r2()) { + TOut.emitRR(Mips::MTC1, FirstReg, Mips::ZERO, IDLoc, STI); + TOut.emitRRR(Mips::MTHC1_D32, FirstReg, FirstReg, ATReg, IDLoc, STI); + } else { + TOut.emitRR(Mips::MTC1, nextReg(FirstReg), ATReg, IDLoc, STI); + TOut.emitRR(Mips::MTC1, FirstReg, Mips::ZERO, IDLoc, STI); + } + return false; + } + + MCSection *CS = getStreamer().getCurrentSectionOnly(); + // FIXME: Enhance this expansion to use the .lit4 & .lit8 sections + // where appropriate. + MCSection *ReadOnlySection = getContext().getELFSection( + ".rodata", ELF::SHT_PROGBITS, ELF::SHF_ALLOC); + + MCSymbol *Sym = getContext().createTempSymbol(); + const MCExpr *LoSym = + MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + const MipsMCExpr *LoExpr = + MipsMCExpr::create(MipsMCExpr::MEK_LO, LoSym, getContext()); + + getStreamer().SwitchSection(ReadOnlySection); + getStreamer().EmitLabel(Sym, IDLoc); + getStreamer().EmitIntValue(HiImmOp64, 4); + getStreamer().EmitIntValue(LoImmOp64, 4); + getStreamer().SwitchSection(CS); + if(emitPartialAddress(TOut, IDLoc, Sym)) + return true; + TOut.emitRRX(Is64FPU ? Mips::LDC164 : Mips::LDC1, FirstReg, ATReg, + MCOperand::createExpr(LoExpr), IDLoc, STI); + } return false; } -bool MipsAsmParser::expandUncondBranchMMPseudo( - MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { +bool MipsAsmParser::expandUncondBranchMMPseudo(MCInst &Inst, SMLoc IDLoc, + MCStreamer &Out, + const MCSubtargetInfo *STI) { + MipsTargetStreamer &TOut = getTargetStreamer(); + assert(getInstDesc(Inst.getOpcode()).getNumOperands() == 1 && "unexpected number of operands"); @@ -2483,9 +3468,9 @@ bool MipsAsmParser::expandUncondBranchMMPseudo( Inst.setOpcode(hasMips32r6() ? Mips::BC16_MMR6 : Mips::B16_MM); } else { if (!isInt<17>(Offset.getImm())) - Error(IDLoc, "branch target out of range"); + return Error(IDLoc, "branch target out of range"); if (OffsetToAlignment(Offset.getImm(), 1LL << 1)) - Error(IDLoc, "branch to misaligned address"); + return Error(IDLoc, "branch to misaligned address"); Inst.clear(); Inst.setOpcode(Mips::BEQ_MM); Inst.addOperand(MCOperand::createReg(Mips::ZERO)); @@ -2493,19 +3478,20 @@ bool MipsAsmParser::expandUncondBranchMMPseudo( Inst.addOperand(MCOperand::createImm(Offset.getImm())); } } - Instructions.push_back(Inst); + Out.EmitInstruction(Inst, *STI); // If .set reorder is active and branch instruction has a delay slot, // emit a NOP after it. const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode()); if (MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder()) - createNop(true, IDLoc, Instructions); + TOut.emitEmptyDelaySlot(true, IDLoc, STI); return false; } -bool MipsAsmParser::expandBranchImm(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { +bool MipsAsmParser::expandBranchImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI) { + MipsTargetStreamer &TOut = getTargetStreamer(); const MCOperand &DstRegOp = Inst.getOperand(0); assert(DstRegOp.isReg() && "expected register operand kind"); @@ -2513,7 +3499,10 @@ bool MipsAsmParser::expandBranchImm(MCInst &Inst, SMLoc IDLoc, assert(ImmOp.isImm() && "expected immediate operand kind"); const MCOperand &MemOffsetOp = Inst.getOperand(2); - assert(MemOffsetOp.isImm() && "expected immediate operand kind"); + assert((MemOffsetOp.isImm() || MemOffsetOp.isExpr()) && + "expected immediate or expression operand"); + + bool IsLikely = false; unsigned OpCode = 0; switch(Inst.getOpcode()) { @@ -2523,16 +3512,29 @@ bool MipsAsmParser::expandBranchImm(MCInst &Inst, SMLoc IDLoc, case Mips::BeqImm: OpCode = Mips::BEQ; break; + case Mips::BEQLImmMacro: + OpCode = Mips::BEQL; + IsLikely = true; + break; + case Mips::BNELImmMacro: + OpCode = Mips::BNEL; + IsLikely = true; + break; default: llvm_unreachable("Unknown immediate branch pseudo-instruction."); break; } int64_t ImmValue = ImmOp.getImm(); - if (ImmValue == 0) - emitRRX(OpCode, DstRegOp.getReg(), Mips::ZERO, MemOffsetOp, IDLoc, - Instructions); - else { + if (ImmValue == 0) { + if (IsLikely) { + TOut.emitRRX(OpCode, DstRegOp.getReg(), Mips::ZERO, + MCOperand::createExpr(MemOffsetOp.getExpr()), IDLoc, STI); + TOut.emitRRI(Mips::SLL, Mips::ZERO, Mips::ZERO, 0, IDLoc, STI); + } else + TOut.emitRRX(OpCode, DstRegOp.getReg(), Mips::ZERO, MemOffsetOp, IDLoc, + STI); + } else { warnIfNoMacro(IDLoc); unsigned ATReg = getATReg(IDLoc); @@ -2540,101 +3542,100 @@ bool MipsAsmParser::expandBranchImm(MCInst &Inst, SMLoc IDLoc, return true; if (loadImmediate(ImmValue, ATReg, Mips::NoRegister, !isGP64bit(), true, - IDLoc, Instructions)) + IDLoc, Out, STI)) return true; - emitRRX(OpCode, DstRegOp.getReg(), ATReg, MemOffsetOp, IDLoc, Instructions); + if (IsLikely) { + TOut.emitRRX(OpCode, DstRegOp.getReg(), ATReg, + MCOperand::createExpr(MemOffsetOp.getExpr()), IDLoc, STI); + TOut.emitRRI(Mips::SLL, Mips::ZERO, Mips::ZERO, 0, IDLoc, STI); + } else + TOut.emitRRX(OpCode, DstRegOp.getReg(), ATReg, MemOffsetOp, IDLoc, STI); } return false; } -void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions, - bool isLoad, bool isImmOpnd) { - unsigned ImmOffset, HiOffset, LoOffset; - const MCExpr *ExprOffset; - unsigned TmpRegNum; - // 1st operand is either the source or destination register. - assert(Inst.getOperand(0).isReg() && "expected register operand kind"); - unsigned RegOpNum = Inst.getOperand(0).getReg(); - // 2nd operand is the base register. - assert(Inst.getOperand(1).isReg() && "expected register operand kind"); - unsigned BaseRegNum = Inst.getOperand(1).getReg(); - // 3rd operand is either an immediate or expression. - if (isImmOpnd) { - assert(Inst.getOperand(2).isImm() && "expected immediate operand kind"); - ImmOffset = Inst.getOperand(2).getImm(); - LoOffset = ImmOffset & 0x0000ffff; - HiOffset = (ImmOffset & 0xffff0000) >> 16; - // If msb of LoOffset is 1(negative number) we must increment HiOffset. - if (LoOffset & 0x8000) - HiOffset++; - } else - ExprOffset = Inst.getOperand(2).getExpr(); - // These are some of the types of expansions we perform here: - // 1) lw $8, sym => lui $8, %hi(sym) - // lw $8, %lo(sym)($8) - // 2) lw $8, offset($9) => lui $8, %hi(offset) - // add $8, $8, $9 - // lw $8, %lo(offset)($9) - // 3) lw $8, offset($8) => lui $at, %hi(offset) - // add $at, $at, $8 - // lw $8, %lo(offset)($at) - // 4) sw $8, sym => lui $at, %hi(sym) - // sw $8, %lo(sym)($at) - // 5) sw $8, offset($8) => lui $at, %hi(offset) - // add $at, $at, $8 - // sw $8, %lo(offset)($at) - // 6) ldc1 $f0, sym => lui $at, %hi(sym) - // ldc1 $f0, %lo(sym)($at) - // - // For load instructions we can use the destination register as a temporary - // if base and dst are different (examples 1 and 2) and if the base register - // is general purpose otherwise we must use $at (example 6) and error if it's - // not available. For stores we must use $at (examples 4 and 5) because we - // must not clobber the source register setting up the offset. +void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI, bool IsLoad) { + const MCOperand &DstRegOp = Inst.getOperand(0); + assert(DstRegOp.isReg() && "expected register operand kind"); + const MCOperand &BaseRegOp = Inst.getOperand(1); + assert(BaseRegOp.isReg() && "expected register operand kind"); + const MCOperand &OffsetOp = Inst.getOperand(2); + + MipsTargetStreamer &TOut = getTargetStreamer(); + unsigned DstReg = DstRegOp.getReg(); + unsigned BaseReg = BaseRegOp.getReg(); + unsigned TmpReg = DstReg; + const MCInstrDesc &Desc = getInstDesc(Inst.getOpcode()); - int16_t RegClassOp0 = Desc.OpInfo[0].RegClass; - unsigned RegClassIDOp0 = - getContext().getRegisterInfo()->getRegClass(RegClassOp0).getID(); - bool IsGPR = (RegClassIDOp0 == Mips::GPR32RegClassID) || - (RegClassIDOp0 == Mips::GPR64RegClassID); - if (isLoad && IsGPR && (BaseRegNum != RegOpNum)) - TmpRegNum = RegOpNum; - else { - // At this point we need AT to perform the expansions and we exit if it is - // not available. - TmpRegNum = getATReg(IDLoc); - if (!TmpRegNum) + int16_t DstRegClass = Desc.OpInfo[0].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; } - emitRX(Mips::LUi, TmpRegNum, - isImmOpnd ? MCOperand::createImm(HiOffset) - : MCOperand::createExpr(evaluateRelocExpr(ExprOffset, "hi")), - IDLoc, Instructions); - // Add temp register to base. - if (BaseRegNum != Mips::ZERO) - emitRRR(Mips::ADDu, TmpRegNum, TmpRegNum, BaseRegNum, IDLoc, Instructions); - // And finally, create original instruction with low part - // of offset and new base. - emitRRX(Inst.getOpcode(), RegOpNum, TmpRegNum, - isImmOpnd - ? MCOperand::createImm(LoOffset) - : MCOperand::createExpr(evaluateRelocExpr(ExprOffset, "lo")), - IDLoc, Instructions); -} - -bool -MipsAsmParser::expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { + if (OffsetOp.isImm()) { + int64_t LoOffset = OffsetOp.getImm() & 0xffff; + int64_t HiOffset = OffsetOp.getImm() & ~0xffff; + + // If msb of LoOffset is 1(negative number) we must increment + // HiOffset to account for the sign-extension of the low part. + if (LoOffset & 0x8000) + HiOffset += 0x10000; + + bool IsLargeOffset = HiOffset != 0; + + if (IsLargeOffset) { + bool Is32BitImm = (HiOffset >> 32) == 0; + 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); + } else if (inPicMode()) { + expandLoadAddress(TmpReg, Mips::NoRegister, OffsetOp, !ABI.ArePtrs64bit(), + IDLoc, Out, STI); + TOut.emitRRI(Inst.getOpcode(), DstReg, TmpReg, 0, IDLoc, STI); + } else { + assert(OffsetOp.isExpr() && "expected expression operand kind"); + const MCExpr *ExprOffset = OffsetOp.getExpr(); + MCOperand LoOperand = MCOperand::createExpr( + MipsMCExpr::create(MipsMCExpr::MEK_LO, ExprOffset, getContext())); + MCOperand HiOperand = MCOperand::createExpr( + MipsMCExpr::create(MipsMCExpr::MEK_HI, ExprOffset, getContext())); + + if (IsLoad) + TOut.emitLoadWithSymOffset(Inst.getOpcode(), DstReg, BaseReg, HiOperand, + LoOperand, TmpReg, IDLoc, STI); + else + TOut.emitStoreWithSymOffset(Inst.getOpcode(), DstReg, BaseReg, HiOperand, + LoOperand, TmpReg, IDLoc, STI); + } +} + +bool MipsAsmParser::expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc, + MCStreamer &Out, + const MCSubtargetInfo *STI) { unsigned OpNum = Inst.getNumOperands(); unsigned Opcode = Inst.getOpcode(); unsigned NewOpcode = Opcode == Mips::SWM_MM ? Mips::SWM32_MM : Mips::LWM32_MM; - assert (Inst.getOperand(OpNum - 1).isImm() && - Inst.getOperand(OpNum - 2).isReg() && - Inst.getOperand(OpNum - 3).isReg() && "Invalid instruction operand."); + assert(Inst.getOperand(OpNum - 1).isImm() && + Inst.getOperand(OpNum - 2).isReg() && + Inst.getOperand(OpNum - 3).isReg() && "Invalid instruction operand."); if (OpNum < 8 && Inst.getOperand(OpNum - 1).getImm() <= 60 && Inst.getOperand(OpNum - 1).getImm() >= 0 && @@ -2650,12 +3651,14 @@ MipsAsmParser::expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc, } Inst.setOpcode(NewOpcode); - Instructions.push_back(Inst); + Out.EmitInstruction(Inst, *STI); return false; } bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { + MCStreamer &Out, + const MCSubtargetInfo *STI) { + MipsTargetStreamer &TOut = getTargetStreamer(); bool EmittedNoMacroWarning = false; unsigned PseudoOpcode = Inst.getOpcode(); unsigned SrcReg = Inst.getOperand(0).getReg(); @@ -2730,7 +3733,7 @@ bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc, } if (loadImmediate(TrgOp.getImm(), TrgReg, Mips::NoRegister, !isGP64bit(), - false, IDLoc, Instructions)) + false, IDLoc, Out, STI)) return true; } @@ -2741,7 +3744,8 @@ bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc, case Mips::BLTUL: AcceptsEquality = false; ReverseOrderSLT = false; - IsUnsigned = ((PseudoOpcode == Mips::BLTU) || (PseudoOpcode == Mips::BLTUL)); + IsUnsigned = + ((PseudoOpcode == Mips::BLTU) || (PseudoOpcode == Mips::BLTUL)); IsLikely = ((PseudoOpcode == Mips::BLTL) || (PseudoOpcode == Mips::BLTUL)); ZeroSrcOpcode = Mips::BGTZ; ZeroTrgOpcode = Mips::BLTZ; @@ -2752,7 +3756,8 @@ bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc, case Mips::BLEUL: AcceptsEquality = true; ReverseOrderSLT = true; - IsUnsigned = ((PseudoOpcode == Mips::BLEU) || (PseudoOpcode == Mips::BLEUL)); + IsUnsigned = + ((PseudoOpcode == Mips::BLEU) || (PseudoOpcode == Mips::BLEUL)); IsLikely = ((PseudoOpcode == Mips::BLEL) || (PseudoOpcode == Mips::BLEUL)); ZeroSrcOpcode = Mips::BGEZ; ZeroTrgOpcode = Mips::BLEZ; @@ -2763,7 +3768,8 @@ bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc, case Mips::BGEUL: AcceptsEquality = true; ReverseOrderSLT = false; - IsUnsigned = ((PseudoOpcode == Mips::BGEU) || (PseudoOpcode == Mips::BGEUL)); + IsUnsigned = + ((PseudoOpcode == Mips::BGEU) || (PseudoOpcode == Mips::BGEUL)); IsLikely = ((PseudoOpcode == Mips::BGEL) || (PseudoOpcode == Mips::BGEUL)); ZeroSrcOpcode = Mips::BLEZ; ZeroTrgOpcode = Mips::BGEZ; @@ -2774,7 +3780,8 @@ bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc, case Mips::BGTUL: AcceptsEquality = false; ReverseOrderSLT = true; - IsUnsigned = ((PseudoOpcode == Mips::BGTU) || (PseudoOpcode == Mips::BGTUL)); + IsUnsigned = + ((PseudoOpcode == Mips::BGTU) || (PseudoOpcode == Mips::BGTUL)); IsLikely = ((PseudoOpcode == Mips::BGTL) || (PseudoOpcode == Mips::BGTUL)); ZeroSrcOpcode = Mips::BLTZ; ZeroTrgOpcode = Mips::BGTZ; @@ -2790,37 +3797,37 @@ bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc, // with GAS' behaviour. However, they may not generate the most efficient // code in some circumstances. if (PseudoOpcode == Mips::BLT) { - emitRX(Mips::BLTZ, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc, - Instructions); + TOut.emitRX(Mips::BLTZ, Mips::ZERO, MCOperand::createExpr(OffsetExpr), + IDLoc, STI); return false; } if (PseudoOpcode == Mips::BLE) { - emitRX(Mips::BLEZ, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc, - Instructions); + TOut.emitRX(Mips::BLEZ, Mips::ZERO, MCOperand::createExpr(OffsetExpr), + IDLoc, STI); Warning(IDLoc, "branch is always taken"); return false; } if (PseudoOpcode == Mips::BGE) { - emitRX(Mips::BGEZ, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc, - Instructions); + TOut.emitRX(Mips::BGEZ, Mips::ZERO, MCOperand::createExpr(OffsetExpr), + IDLoc, STI); Warning(IDLoc, "branch is always taken"); return false; } if (PseudoOpcode == Mips::BGT) { - emitRX(Mips::BGTZ, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc, - Instructions); + TOut.emitRX(Mips::BGTZ, Mips::ZERO, MCOperand::createExpr(OffsetExpr), + IDLoc, STI); return false; } if (PseudoOpcode == Mips::BGTU) { - emitRRX(Mips::BNE, Mips::ZERO, Mips::ZERO, - MCOperand::createExpr(OffsetExpr), IDLoc, Instructions); + TOut.emitRRX(Mips::BNE, Mips::ZERO, Mips::ZERO, + MCOperand::createExpr(OffsetExpr), IDLoc, STI); return false; } if (AcceptsEquality) { // If both registers are $0 and the pseudo-branch accepts equality, it // will always be taken, so we emit an unconditional branch. - emitRRX(Mips::BEQ, Mips::ZERO, Mips::ZERO, - MCOperand::createExpr(OffsetExpr), IDLoc, Instructions); + TOut.emitRRX(Mips::BEQ, Mips::ZERO, Mips::ZERO, + MCOperand::createExpr(OffsetExpr), IDLoc, STI); Warning(IDLoc, "branch is always taken"); return false; } @@ -2844,8 +3851,8 @@ bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc, // the pseudo-branch will always be taken, so we emit an unconditional // branch. // This only applies to unsigned pseudo-branches. - emitRRX(Mips::BEQ, Mips::ZERO, Mips::ZERO, - MCOperand::createExpr(OffsetExpr), IDLoc, Instructions); + TOut.emitRRX(Mips::BEQ, Mips::ZERO, Mips::ZERO, + MCOperand::createExpr(OffsetExpr), IDLoc, STI); Warning(IDLoc, "branch is always taken"); return false; } @@ -2862,17 +3869,17 @@ bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc, // // Because only BLEU and BGEU branch on equality, we can use the // AcceptsEquality variable to decide when to emit the BEQZ. - emitRRX(AcceptsEquality ? Mips::BEQ : Mips::BNE, - IsSrcRegZero ? TrgReg : SrcReg, Mips::ZERO, - MCOperand::createExpr(OffsetExpr), IDLoc, Instructions); + TOut.emitRRX(AcceptsEquality ? Mips::BEQ : Mips::BNE, + IsSrcRegZero ? TrgReg : SrcReg, Mips::ZERO, + MCOperand::createExpr(OffsetExpr), IDLoc, STI); return false; } // If we have a signed pseudo-branch and one of the registers is $0, // we can use an appropriate compare-to-zero branch. We select which one // to use in the switch statement above. - emitRX(IsSrcRegZero ? ZeroSrcOpcode : ZeroTrgOpcode, - IsSrcRegZero ? TrgReg : SrcReg, MCOperand::createExpr(OffsetExpr), - IDLoc, Instructions); + TOut.emitRX(IsSrcRegZero ? ZeroSrcOpcode : ZeroTrgOpcode, + IsSrcRegZero ? TrgReg : SrcReg, + MCOperand::createExpr(OffsetExpr), IDLoc, STI); return false; } @@ -2892,7 +3899,7 @@ bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc, // This is accomplished by using a BNEZ with the result of the SLT. // // The other 2 pseudo-branches are opposites of the above 2 (BGE with BLT - // and BLE with BGT), so we change the BNEZ into a a BEQZ. + // and BLE with BGT), so we change the BNEZ into a BEQZ. // Because only BGE and BLE branch on equality, we can use the // AcceptsEquality variable to decide when to emit the BEQZ. // Note that the order of the SLT arguments doesn't change between @@ -2900,102 +3907,155 @@ bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc, // // The same applies to the unsigned variants, except that SLTu is used // instead of SLT. - emitRRR(IsUnsigned ? Mips::SLTu : Mips::SLT, ATRegNum, - ReverseOrderSLT ? TrgReg : SrcReg, ReverseOrderSLT ? SrcReg : TrgReg, - IDLoc, Instructions); - - emitRRX(IsLikely ? (AcceptsEquality ? Mips::BEQL : Mips::BNEL) - : (AcceptsEquality ? Mips::BEQ : Mips::BNE), - ATRegNum, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc, - Instructions); + TOut.emitRRR(IsUnsigned ? Mips::SLTu : Mips::SLT, ATRegNum, + ReverseOrderSLT ? TrgReg : SrcReg, + ReverseOrderSLT ? SrcReg : TrgReg, IDLoc, STI); + + TOut.emitRRX(IsLikely ? (AcceptsEquality ? Mips::BEQL : Mips::BNEL) + : (AcceptsEquality ? Mips::BEQ : Mips::BNE), + ATRegNum, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc, + STI); return false; } -bool MipsAsmParser::expandDiv(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions, - const bool IsMips64, const bool Signed) { - if (hasMips32r6()) { - Error(IDLoc, "instruction not supported on mips32r6 or mips64r6"); - return false; - } +// Expand a integer division macro. +// +// Notably we don't have to emit a warning when encountering $rt as the $zero +// register, or 0 as an immediate. processInstruction() has already done that. +// +// The destination register can only be $zero when expanding (S)DivIMacro or +// D(S)DivMacro. + +bool MipsAsmParser::expandDivRem(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI, const bool IsMips64, + const bool Signed) { + MipsTargetStreamer &TOut = getTargetStreamer(); warnIfNoMacro(IDLoc); - const MCOperand &RsRegOp = Inst.getOperand(0); + const MCOperand &RdRegOp = Inst.getOperand(0); + assert(RdRegOp.isReg() && "expected register operand kind"); + unsigned RdReg = RdRegOp.getReg(); + + const MCOperand &RsRegOp = Inst.getOperand(1); assert(RsRegOp.isReg() && "expected register operand kind"); unsigned RsReg = RsRegOp.getReg(); - const MCOperand &RtRegOp = Inst.getOperand(1); - assert(RtRegOp.isReg() && "expected register operand kind"); - unsigned RtReg = RtRegOp.getReg(); + unsigned RtReg; + int64_t ImmValue; + + const MCOperand &RtOp = Inst.getOperand(2); + assert((RtOp.isReg() || RtOp.isImm()) && + "expected register or immediate operand kind"); + if (RtOp.isReg()) + RtReg = RtOp.getReg(); + else + ImmValue = RtOp.getImm(); + unsigned DivOp; unsigned ZeroReg; + unsigned SubOp; if (IsMips64) { DivOp = Signed ? Mips::DSDIV : Mips::DUDIV; ZeroReg = Mips::ZERO_64; + SubOp = Mips::DSUB; } else { DivOp = Signed ? Mips::SDIV : Mips::UDIV; ZeroReg = Mips::ZERO; + SubOp = Mips::SUB; } bool UseTraps = useTraps(); - if (RsReg == Mips::ZERO || RsReg == Mips::ZERO_64) { - if (RtReg == Mips::ZERO || RtReg == Mips::ZERO_64) - Warning(IDLoc, "dividing zero by zero"); - if (IsMips64) { - if (Signed && (RtReg == Mips::ZERO || RtReg == Mips::ZERO_64)) { - if (UseTraps) { - emitRRI(Mips::TEQ, RtReg, ZeroReg, 0x7, IDLoc, Instructions); - return false; - } + unsigned Opcode = Inst.getOpcode(); + bool isDiv = Opcode == Mips::SDivMacro || Opcode == Mips::SDivIMacro || + Opcode == Mips::UDivMacro || Opcode == Mips::UDivIMacro || + Opcode == Mips::DSDivMacro || Opcode == Mips::DSDivIMacro || + Opcode == Mips::DUDivMacro || Opcode == Mips::DUDivIMacro; - emitII(Mips::BREAK, 0x7, 0, IDLoc, Instructions); - return false; - } + bool isRem = Opcode == Mips::SRemMacro || Opcode == Mips::SRemIMacro || + Opcode == Mips::URemMacro || Opcode == Mips::URemIMacro || + Opcode == Mips::DSRemMacro || Opcode == Mips::DSRemIMacro || + Opcode == Mips::DURemMacro || Opcode == Mips::DURemIMacro; + + if (RtOp.isImm()) { + unsigned ATReg = getATReg(IDLoc); + if (!ATReg) + return true; + + if (ImmValue == 0) { + if (UseTraps) + TOut.emitRRI(Mips::TEQ, ZeroReg, ZeroReg, 0x7, IDLoc, STI); + else + TOut.emitII(Mips::BREAK, 0x7, 0, IDLoc, STI); + return false; + } + + if (isRem && (ImmValue == 1 || (Signed && (ImmValue == -1)))) { + TOut.emitRRR(Mips::OR, RdReg, ZeroReg, ZeroReg, IDLoc, STI); + return false; + } else if (isDiv && ImmValue == 1) { + TOut.emitRRR(Mips::OR, RdReg, RsReg, Mips::ZERO, IDLoc, STI); + return false; + } else if (isDiv && Signed && ImmValue == -1) { + TOut.emitRRR(SubOp, RdReg, ZeroReg, RsReg, IDLoc, STI); + return false; } else { - emitRR(DivOp, RsReg, RtReg, IDLoc, Instructions); + if (loadImmediate(ImmValue, ATReg, Mips::NoRegister, isInt<32>(ImmValue), + false, Inst.getLoc(), Out, STI)) + return true; + TOut.emitRR(DivOp, RsReg, ATReg, IDLoc, STI); + TOut.emitR(isDiv ? Mips::MFLO : Mips::MFHI, RdReg, IDLoc, STI); return false; } + return true; } + // If the macro expansion of (d)div(u) or (d)rem(u) would always trap or + // break, insert the trap/break and exit. This gives a different result to + // GAS. GAS has an inconsistency/missed optimization in that not all cases + // are handled equivalently. As the observed behaviour is the same, we're ok. if (RtReg == Mips::ZERO || RtReg == Mips::ZERO_64) { - Warning(IDLoc, "division by zero"); - if (Signed) { - if (UseTraps) { - emitRRI(Mips::TEQ, RtReg, ZeroReg, 0x7, IDLoc, Instructions); - return false; - } - - emitII(Mips::BREAK, 0x7, 0, IDLoc, Instructions); + if (UseTraps) { + TOut.emitRRI(Mips::TEQ, ZeroReg, ZeroReg, 0x7, IDLoc, STI); return false; } + TOut.emitII(Mips::BREAK, 0x7, 0, IDLoc, STI); + return false; } - // FIXME: The values for these two BranchTarget variables may be different in - // micromips. These magic numbers need to be removed. - unsigned BranchTargetNoTraps; - unsigned BranchTarget; + // (d)rem(u) $0, $X, $Y is a special case. Like div $zero, $X, $Y, it does + // not expand to macro sequence. + if (isRem && (RdReg == Mips::ZERO || RdReg == Mips::ZERO_64)) { + TOut.emitRR(DivOp, RsReg, RtReg, IDLoc, STI); + return false; + } + + // Temporary label for first branch traget + MCContext &Context = TOut.getStreamer().getContext(); + MCSymbol *BrTarget; + MCOperand LabelOp; if (UseTraps) { - BranchTarget = IsMips64 ? 12 : 8; - emitRRI(Mips::TEQ, RtReg, ZeroReg, 0x7, IDLoc, Instructions); + TOut.emitRRI(Mips::TEQ, RtReg, ZeroReg, 0x7, IDLoc, STI); } else { - BranchTarget = IsMips64 ? 20 : 16; - BranchTargetNoTraps = 8; // Branch to the li instruction. - emitRRI(Mips::BNE, RtReg, ZeroReg, BranchTargetNoTraps, IDLoc, - Instructions); + BrTarget = Context.createTempSymbol(); + LabelOp = MCOperand::createExpr(MCSymbolRefExpr::create(BrTarget, Context)); + TOut.emitRRX(Mips::BNE, RtReg, ZeroReg, LabelOp, IDLoc, STI); } - emitRR(DivOp, RsReg, RtReg, IDLoc, Instructions); + TOut.emitRR(DivOp, RsReg, RtReg, IDLoc, STI); if (!UseTraps) - emitII(Mips::BREAK, 0x7, 0, IDLoc, Instructions); + TOut.emitII(Mips::BREAK, 0x7, 0, IDLoc, STI); if (!Signed) { - emitR(Mips::MFLO, RsReg, IDLoc, Instructions); + if (!UseTraps) + TOut.getStreamer().EmitLabel(BrTarget); + + TOut.emitR(isDiv ? Mips::MFLO : Mips::MFHI, RdReg, IDLoc, STI); return false; } @@ -3003,179 +4063,246 @@ bool MipsAsmParser::expandDiv(MCInst &Inst, SMLoc IDLoc, if (!ATReg) return true; - emitRRI(Mips::ADDiu, ATReg, ZeroReg, -1, IDLoc, Instructions); + if (!UseTraps) + TOut.getStreamer().EmitLabel(BrTarget); + + TOut.emitRRI(Mips::ADDiu, ATReg, ZeroReg, -1, IDLoc, STI); + + // Temporary label for the second branch target. + MCSymbol *BrTargetEnd = Context.createTempSymbol(); + MCOperand LabelOpEnd = + MCOperand::createExpr(MCSymbolRefExpr::create(BrTargetEnd, Context)); + + // Branch to the mflo instruction. + TOut.emitRRX(Mips::BNE, RtReg, ATReg, LabelOpEnd, IDLoc, STI); + if (IsMips64) { - // Branch to the mflo instruction. - emitRRI(Mips::BNE, RtReg, ATReg, BranchTarget, IDLoc, Instructions); - emitRRI(Mips::ADDiu, ATReg, ZeroReg, 1, IDLoc, Instructions); - emitRRI(Mips::DSLL32, ATReg, ATReg, 0x1f, IDLoc, Instructions); + TOut.emitRRI(Mips::ADDiu, ATReg, ZeroReg, 1, IDLoc, STI); + TOut.emitDSLL(ATReg, ATReg, 63, IDLoc, STI); } else { - // Branch to the mflo instruction. - emitRRI(Mips::BNE, RtReg, ATReg, BranchTarget, IDLoc, Instructions); - emitRI(Mips::LUi, ATReg, (uint16_t)0x8000, IDLoc, Instructions); + TOut.emitRI(Mips::LUi, ATReg, (uint16_t)0x8000, IDLoc, STI); } if (UseTraps) - emitRRI(Mips::TEQ, RsReg, ATReg, 0x6, IDLoc, Instructions); + TOut.emitRRI(Mips::TEQ, RsReg, ATReg, 0x6, IDLoc, STI); else { // Branch to the mflo instruction. - emitRRI(Mips::BNE, RsReg, ATReg, BranchTargetNoTraps, IDLoc, Instructions); - emitRRI(Mips::SLL, ZeroReg, ZeroReg, 0, IDLoc, Instructions); - emitII(Mips::BREAK, 0x6, 0, IDLoc, Instructions); + TOut.emitRRX(Mips::BNE, RsReg, ATReg, LabelOpEnd, IDLoc, STI); + TOut.emitNop(IDLoc, STI); + TOut.emitII(Mips::BREAK, 0x6, 0, IDLoc, STI); } - emitR(Mips::MFLO, RsReg, IDLoc, Instructions); + + TOut.getStreamer().EmitLabel(BrTargetEnd); + TOut.emitR(isDiv ? Mips::MFLO : Mips::MFHI, RdReg, IDLoc, STI); return false; } -bool MipsAsmParser::expandUlh(MCInst &Inst, bool Signed, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { - if (hasMips32r6() || hasMips64r6()) { - Error(IDLoc, "instruction not supported on mips32r6 or mips64r6"); +bool MipsAsmParser::expandTrunc(MCInst &Inst, bool IsDouble, bool Is64FPU, + SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI) { + MipsTargetStreamer &TOut = getTargetStreamer(); + + assert(Inst.getNumOperands() == 3 && "Invalid operand count"); + assert(Inst.getOperand(0).isReg() && Inst.getOperand(1).isReg() && + Inst.getOperand(2).isReg() && "Invalid instruction operand."); + + unsigned FirstReg = Inst.getOperand(0).getReg(); + unsigned SecondReg = Inst.getOperand(1).getReg(); + unsigned ThirdReg = Inst.getOperand(2).getReg(); + + if (hasMips1() && !hasMips2()) { + unsigned ATReg = getATReg(IDLoc); + if (!ATReg) + return true; + TOut.emitRR(Mips::CFC1, ThirdReg, Mips::RA, IDLoc, STI); + TOut.emitRR(Mips::CFC1, ThirdReg, Mips::RA, IDLoc, STI); + TOut.emitNop(IDLoc, STI); + TOut.emitRRI(Mips::ORi, ATReg, ThirdReg, 0x3, IDLoc, STI); + TOut.emitRRI(Mips::XORi, ATReg, ATReg, 0x2, IDLoc, STI); + TOut.emitRR(Mips::CTC1, Mips::RA, ATReg, IDLoc, STI); + TOut.emitNop(IDLoc, STI); + TOut.emitRR(IsDouble ? (Is64FPU ? Mips::CVT_W_D64 : Mips::CVT_W_D32) + : Mips::CVT_W_S, + FirstReg, SecondReg, IDLoc, STI); + TOut.emitRR(Mips::CTC1, Mips::RA, ThirdReg, IDLoc, STI); + TOut.emitNop(IDLoc, STI); return false; } - warnIfNoMacro(IDLoc); + TOut.emitRR(IsDouble ? (Is64FPU ? Mips::TRUNC_W_D64 : Mips::TRUNC_W_D32) + : Mips::TRUNC_W_S, + FirstReg, SecondReg, IDLoc, STI); + + return false; +} + +bool MipsAsmParser::expandUlh(MCInst &Inst, bool Signed, SMLoc IDLoc, + MCStreamer &Out, const MCSubtargetInfo *STI) { + if (hasMips32r6() || hasMips64r6()) { + return Error(IDLoc, "instruction not supported on mips32r6 or mips64r6"); + } const MCOperand &DstRegOp = Inst.getOperand(0); assert(DstRegOp.isReg() && "expected register operand kind"); - const MCOperand &SrcRegOp = Inst.getOperand(1); assert(SrcRegOp.isReg() && "expected register operand kind"); - const MCOperand &OffsetImmOp = Inst.getOperand(2); assert(OffsetImmOp.isImm() && "expected immediate operand kind"); + MipsTargetStreamer &TOut = getTargetStreamer(); unsigned DstReg = DstRegOp.getReg(); unsigned SrcReg = SrcRegOp.getReg(); int64_t OffsetValue = OffsetImmOp.getImm(); // NOTE: We always need AT for ULHU, as it is always used as the source // register for one of the LBu's. + warnIfNoMacro(IDLoc); unsigned ATReg = getATReg(IDLoc); if (!ATReg) return true; - // When the value of offset+1 does not fit in 16 bits, we have to load the - // offset in AT, (D)ADDu the original source register (if there was one), and - // then use AT as the source register for the 2 generated LBu's. - bool LoadedOffsetInAT = false; - if (!isInt<16>(OffsetValue + 1) || !isInt<16>(OffsetValue)) { - LoadedOffsetInAT = true; - - if (loadImmediate(OffsetValue, ATReg, Mips::NoRegister, !ABI.ArePtrs64bit(), - true, IDLoc, Instructions)) + bool IsLargeOffset = !(isInt<16>(OffsetValue + 1) && isInt<16>(OffsetValue)); + if (IsLargeOffset) { + if (loadImmediate(OffsetValue, ATReg, SrcReg, !ABI.ArePtrs64bit(), true, + IDLoc, Out, STI)) return true; - - // NOTE: We do this (D)ADDu here instead of doing it in loadImmediate() - // because it will make our output more similar to GAS'. For example, - // generating an "ori $1, $zero, 32768" followed by an "addu $1, $1, $9", - // instead of just an "ori $1, $9, 32768". - // NOTE: If there is no source register specified in the ULHU, the parser - // will interpret it as $0. - if (SrcReg != Mips::ZERO && SrcReg != Mips::ZERO_64) - createAddu(ATReg, ATReg, SrcReg, ABI.ArePtrs64bit(), Instructions); } - unsigned FirstLbuDstReg = LoadedOffsetInAT ? DstReg : ATReg; - unsigned SecondLbuDstReg = LoadedOffsetInAT ? ATReg : DstReg; - unsigned LbuSrcReg = LoadedOffsetInAT ? ATReg : SrcReg; + int64_t FirstOffset = IsLargeOffset ? 0 : OffsetValue; + int64_t SecondOffset = IsLargeOffset ? 1 : (OffsetValue + 1); + if (isLittle()) + std::swap(FirstOffset, SecondOffset); - int64_t FirstLbuOffset = 0, SecondLbuOffset = 0; - if (isLittle()) { - FirstLbuOffset = LoadedOffsetInAT ? 1 : (OffsetValue + 1); - SecondLbuOffset = LoadedOffsetInAT ? 0 : OffsetValue; - } else { - FirstLbuOffset = LoadedOffsetInAT ? 0 : OffsetValue; - SecondLbuOffset = LoadedOffsetInAT ? 1 : (OffsetValue + 1); + unsigned FirstLbuDstReg = IsLargeOffset ? DstReg : ATReg; + unsigned SecondLbuDstReg = IsLargeOffset ? ATReg : DstReg; + + unsigned LbuSrcReg = IsLargeOffset ? ATReg : SrcReg; + unsigned SllReg = IsLargeOffset ? DstReg : ATReg; + + TOut.emitRRI(Signed ? Mips::LB : Mips::LBu, FirstLbuDstReg, LbuSrcReg, + FirstOffset, IDLoc, STI); + TOut.emitRRI(Mips::LBu, SecondLbuDstReg, LbuSrcReg, SecondOffset, IDLoc, STI); + TOut.emitRRI(Mips::SLL, SllReg, SllReg, 8, IDLoc, STI); + TOut.emitRRR(Mips::OR, DstReg, DstReg, ATReg, IDLoc, STI); + + return false; +} + +bool MipsAsmParser::expandUsh(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI) { + if (hasMips32r6() || hasMips64r6()) { + return Error(IDLoc, "instruction not supported on mips32r6 or mips64r6"); } - unsigned SllReg = LoadedOffsetInAT ? DstReg : ATReg; + const MCOperand &DstRegOp = Inst.getOperand(0); + assert(DstRegOp.isReg() && "expected register operand kind"); + const MCOperand &SrcRegOp = Inst.getOperand(1); + assert(SrcRegOp.isReg() && "expected register operand kind"); + const MCOperand &OffsetImmOp = Inst.getOperand(2); + assert(OffsetImmOp.isImm() && "expected immediate operand kind"); - emitRRI(Signed ? Mips::LB : Mips::LBu, FirstLbuDstReg, LbuSrcReg, - FirstLbuOffset, IDLoc, Instructions); + MipsTargetStreamer &TOut = getTargetStreamer(); + unsigned DstReg = DstRegOp.getReg(); + unsigned SrcReg = SrcRegOp.getReg(); + int64_t OffsetValue = OffsetImmOp.getImm(); + + warnIfNoMacro(IDLoc); + unsigned ATReg = getATReg(IDLoc); + if (!ATReg) + return true; - emitRRI(Mips::LBu, SecondLbuDstReg, LbuSrcReg, SecondLbuOffset, IDLoc, - Instructions); + bool IsLargeOffset = !(isInt<16>(OffsetValue + 1) && isInt<16>(OffsetValue)); + if (IsLargeOffset) { + if (loadImmediate(OffsetValue, ATReg, SrcReg, !ABI.ArePtrs64bit(), true, + IDLoc, Out, STI)) + return true; + } - emitRRI(Mips::SLL, SllReg, SllReg, 8, IDLoc, Instructions); + int64_t FirstOffset = IsLargeOffset ? 1 : (OffsetValue + 1); + int64_t SecondOffset = IsLargeOffset ? 0 : OffsetValue; + if (isLittle()) + std::swap(FirstOffset, SecondOffset); - emitRRR(Mips::OR, DstReg, DstReg, ATReg, IDLoc, Instructions); + if (IsLargeOffset) { + TOut.emitRRI(Mips::SB, DstReg, ATReg, FirstOffset, IDLoc, STI); + TOut.emitRRI(Mips::SRL, DstReg, DstReg, 8, IDLoc, STI); + TOut.emitRRI(Mips::SB, DstReg, ATReg, SecondOffset, IDLoc, STI); + TOut.emitRRI(Mips::LBu, ATReg, ATReg, 0, IDLoc, STI); + TOut.emitRRI(Mips::SLL, DstReg, DstReg, 8, IDLoc, STI); + TOut.emitRRR(Mips::OR, DstReg, DstReg, ATReg, IDLoc, STI); + } else { + TOut.emitRRI(Mips::SB, DstReg, SrcReg, FirstOffset, IDLoc, STI); + TOut.emitRRI(Mips::SRL, ATReg, DstReg, 8, IDLoc, STI); + TOut.emitRRI(Mips::SB, ATReg, SrcReg, SecondOffset, IDLoc, STI); + } return false; } -bool MipsAsmParser::expandUlw(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { +bool MipsAsmParser::expandUxw(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI) { if (hasMips32r6() || hasMips64r6()) { - Error(IDLoc, "instruction not supported on mips32r6 or mips64r6"); - return false; + return Error(IDLoc, "instruction not supported on mips32r6 or mips64r6"); } const MCOperand &DstRegOp = Inst.getOperand(0); assert(DstRegOp.isReg() && "expected register operand kind"); - const MCOperand &SrcRegOp = Inst.getOperand(1); assert(SrcRegOp.isReg() && "expected register operand kind"); - const MCOperand &OffsetImmOp = Inst.getOperand(2); assert(OffsetImmOp.isImm() && "expected immediate operand kind"); + MipsTargetStreamer &TOut = getTargetStreamer(); + unsigned DstReg = DstRegOp.getReg(); unsigned SrcReg = SrcRegOp.getReg(); int64_t OffsetValue = OffsetImmOp.getImm(); - unsigned ATReg = 0; - - // When the value of offset+3 does not fit in 16 bits, we have to load the - // offset in AT, (D)ADDu the original source register (if there was one), and - // then use AT as the source register for the generated LWL and LWR. - bool LoadedOffsetInAT = false; - if (!isInt<16>(OffsetValue + 3) || !isInt<16>(OffsetValue)) { - ATReg = getATReg(IDLoc); - if (!ATReg) - return true; - LoadedOffsetInAT = true; + // Compute left/right load/store offsets. + bool IsLargeOffset = !(isInt<16>(OffsetValue + 3) && isInt<16>(OffsetValue)); + int64_t LxlOffset = IsLargeOffset ? 0 : OffsetValue; + int64_t LxrOffset = IsLargeOffset ? 3 : (OffsetValue + 3); + if (isLittle()) + std::swap(LxlOffset, LxrOffset); + + bool IsLoadInst = (Inst.getOpcode() == Mips::Ulw); + bool DoMove = IsLoadInst && (SrcReg == DstReg) && !IsLargeOffset; + unsigned TmpReg = SrcReg; + if (IsLargeOffset || DoMove) { warnIfNoMacro(IDLoc); - - if (loadImmediate(OffsetValue, ATReg, Mips::NoRegister, !ABI.ArePtrs64bit(), - true, IDLoc, Instructions)) + TmpReg = getATReg(IDLoc); + if (!TmpReg) return true; + } - // NOTE: We do this (D)ADDu here instead of doing it in loadImmediate() - // because it will make our output more similar to GAS'. For example, - // generating an "ori $1, $zero, 32768" followed by an "addu $1, $1, $9", - // instead of just an "ori $1, $9, 32768". - // NOTE: If there is no source register specified in the ULW, the parser - // will interpret it as $0. - if (SrcReg != Mips::ZERO && SrcReg != Mips::ZERO_64) - createAddu(ATReg, ATReg, SrcReg, ABI.ArePtrs64bit(), Instructions); - } - - unsigned FinalSrcReg = LoadedOffsetInAT ? ATReg : SrcReg; - int64_t LeftLoadOffset = 0, RightLoadOffset = 0; - if (isLittle()) { - LeftLoadOffset = LoadedOffsetInAT ? 3 : (OffsetValue + 3); - RightLoadOffset = LoadedOffsetInAT ? 0 : OffsetValue; - } else { - LeftLoadOffset = LoadedOffsetInAT ? 0 : OffsetValue; - RightLoadOffset = LoadedOffsetInAT ? 3 : (OffsetValue + 3); + if (IsLargeOffset) { + if (loadImmediate(OffsetValue, TmpReg, SrcReg, !ABI.ArePtrs64bit(), true, + IDLoc, Out, STI)) + return true; } - emitRRI(Mips::LWL, DstRegOp.getReg(), FinalSrcReg, LeftLoadOffset, IDLoc, - Instructions); + if (DoMove) + std::swap(DstReg, TmpReg); - emitRRI(Mips::LWR, DstRegOp.getReg(), FinalSrcReg, RightLoadOffset, IDLoc, - Instructions); + unsigned XWL = IsLoadInst ? Mips::LWL : Mips::SWL; + unsigned XWR = IsLoadInst ? Mips::LWR : Mips::SWR; + TOut.emitRRI(XWL, DstReg, TmpReg, LxlOffset, IDLoc, STI); + TOut.emitRRI(XWR, DstReg, TmpReg, LxrOffset, IDLoc, STI); + + if (DoMove) + TOut.emitRRR(Mips::OR, TmpReg, DstReg, Mips::ZERO, IDLoc, STI); return false; } bool MipsAsmParser::expandAliasImmediate(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { + MCStreamer &Out, + const MCSubtargetInfo *STI) { + MipsTargetStreamer &TOut = getTargetStreamer(); - assert (Inst.getNumOperands() == 3 && "Invalid operand count"); - assert (Inst.getOperand(0).isReg() && - Inst.getOperand(1).isReg() && - Inst.getOperand(2).isImm() && "Invalid instruction operand."); + assert(Inst.getNumOperands() == 3 && "Invalid operand count"); + assert(Inst.getOperand(0).isReg() && + Inst.getOperand(1).isReg() && + Inst.getOperand(2).isImm() && "Invalid instruction operand."); unsigned ATReg = Mips::NoRegister; unsigned FinalDstReg = Mips::NoRegister; @@ -3183,7 +4310,7 @@ bool MipsAsmParser::expandAliasImmediate(MCInst &Inst, SMLoc IDLoc, unsigned SrcReg = Inst.getOperand(1).getReg(); int64_t ImmValue = Inst.getOperand(2).getImm(); - bool Is32Bit = isInt<32>(ImmValue) || isUInt<32>(ImmValue); + bool Is32Bit = isInt<32>(ImmValue) || (!isGP64bit() && isUInt<32>(ImmValue)); unsigned FinalOpcode = Inst.getOpcode(); @@ -3195,48 +4322,88 @@ bool MipsAsmParser::expandAliasImmediate(MCInst &Inst, SMLoc IDLoc, DstReg = ATReg; } - if (!loadImmediate(ImmValue, DstReg, Mips::NoRegister, Is32Bit, false, Inst.getLoc(), Instructions)) { + if (!loadImmediate(ImmValue, DstReg, Mips::NoRegister, Is32Bit, false, + Inst.getLoc(), Out, STI)) { switch (FinalOpcode) { default: llvm_unreachable("unimplemented expansion"); - case (Mips::ADDi): + case Mips::ADDi: FinalOpcode = Mips::ADD; break; - case (Mips::ADDiu): + case Mips::ADDiu: FinalOpcode = Mips::ADDu; break; - case (Mips::ANDi): + case Mips::ANDi: FinalOpcode = Mips::AND; break; - case (Mips::NORImm): + case Mips::NORImm: FinalOpcode = Mips::NOR; break; - case (Mips::ORi): + case Mips::ORi: FinalOpcode = Mips::OR; break; - case (Mips::SLTi): + case Mips::SLTi: FinalOpcode = Mips::SLT; break; - case (Mips::SLTiu): + case Mips::SLTiu: FinalOpcode = Mips::SLTu; break; - case (Mips::XORi): + case Mips::XORi: FinalOpcode = Mips::XOR; break; + case Mips::ADDi_MM: + FinalOpcode = Mips::ADD_MM; + break; + case Mips::ADDiu_MM: + FinalOpcode = Mips::ADDu_MM; + break; + case Mips::ANDi_MM: + FinalOpcode = Mips::AND_MM; + break; + case Mips::ORi_MM: + FinalOpcode = Mips::OR_MM; + break; + case Mips::SLTi_MM: + FinalOpcode = Mips::SLT_MM; + break; + case Mips::SLTiu_MM: + FinalOpcode = Mips::SLTu_MM; + break; + case Mips::XORi_MM: + FinalOpcode = Mips::XOR_MM; + break; + case Mips::ANDi64: + FinalOpcode = Mips::AND64; + break; + case Mips::NORImm64: + FinalOpcode = Mips::NOR64; + break; + case Mips::ORi64: + FinalOpcode = Mips::OR64; + break; + case Mips::SLTImm64: + FinalOpcode = Mips::SLT64; + break; + case Mips::SLTUImm64: + FinalOpcode = Mips::SLTu64; + break; + case Mips::XORi64: + FinalOpcode = Mips::XOR64; + break; } if (FinalDstReg == Mips::NoRegister) - emitRRR(FinalOpcode, DstReg, DstReg, SrcReg, IDLoc, Instructions); + TOut.emitRRR(FinalOpcode, DstReg, DstReg, SrcReg, IDLoc, STI); else - emitRRR(FinalOpcode, FinalDstReg, FinalDstReg, DstReg, IDLoc, - Instructions); + TOut.emitRRR(FinalOpcode, FinalDstReg, FinalDstReg, DstReg, IDLoc, STI); return false; } return true; } -bool MipsAsmParser::expandRotation(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { +bool MipsAsmParser::expandRotation(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI) { + MipsTargetStreamer &TOut = getTargetStreamer(); unsigned ATReg = Mips::NoRegister; unsigned DReg = Inst.getOperand(0).getReg(); unsigned SReg = Inst.getOperand(1).getReg(); @@ -3247,7 +4414,6 @@ bool MipsAsmParser::expandRotation(MCInst &Inst, SMLoc IDLoc, unsigned SecondShift = Mips::NOP; if (hasMips32r2()) { - if (DReg == SReg) { TmpReg = getATReg(Inst.getLoc()); if (!TmpReg) @@ -3255,13 +4421,13 @@ bool MipsAsmParser::expandRotation(MCInst &Inst, SMLoc IDLoc, } if (Inst.getOpcode() == Mips::ROL) { - emitRRR(Mips::SUBu, TmpReg, Mips::ZERO, TReg, Inst.getLoc(), Instructions); - emitRRR(Mips::ROTRV, DReg, SReg, TmpReg, Inst.getLoc(), Instructions); + TOut.emitRRR(Mips::SUBu, TmpReg, Mips::ZERO, TReg, Inst.getLoc(), STI); + TOut.emitRRR(Mips::ROTRV, DReg, SReg, TmpReg, Inst.getLoc(), STI); return false; } if (Inst.getOpcode() == Mips::ROR) { - emitRRR(Mips::ROTRV, DReg, SReg, TReg, Inst.getLoc(), Instructions); + TOut.emitRRR(Mips::ROTRV, DReg, SReg, TReg, Inst.getLoc(), STI); return false; } @@ -3269,7 +4435,6 @@ bool MipsAsmParser::expandRotation(MCInst &Inst, SMLoc IDLoc, } if (hasMips32()) { - switch (Inst.getOpcode()) { default: llvm_unreachable("unexpected instruction opcode"); @@ -3287,10 +4452,10 @@ bool MipsAsmParser::expandRotation(MCInst &Inst, SMLoc IDLoc, if (!ATReg) return true; - emitRRR(Mips::SUBu, ATReg, Mips::ZERO, TReg, Inst.getLoc(), Instructions); - emitRRR(FirstShift, ATReg, SReg, ATReg, Inst.getLoc(), Instructions); - emitRRR(SecondShift, DReg, SReg, TReg, Inst.getLoc(), Instructions); - emitRRR(Mips::OR, DReg, DReg, ATReg, Inst.getLoc(), Instructions); + TOut.emitRRR(Mips::SUBu, ATReg, Mips::ZERO, TReg, Inst.getLoc(), STI); + TOut.emitRRR(FirstShift, ATReg, SReg, ATReg, Inst.getLoc(), STI); + TOut.emitRRR(SecondShift, DReg, SReg, TReg, Inst.getLoc(), STI); + TOut.emitRRR(Mips::OR, DReg, DReg, ATReg, Inst.getLoc(), STI); return false; } @@ -3299,8 +4464,9 @@ bool MipsAsmParser::expandRotation(MCInst &Inst, SMLoc IDLoc, } bool MipsAsmParser::expandRotationImm(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { - + MCStreamer &Out, + const MCSubtargetInfo *STI) { + MipsTargetStreamer &TOut = getTargetStreamer(); unsigned ATReg = Mips::NoRegister; unsigned DReg = Inst.getOperand(0).getReg(); unsigned SReg = Inst.getOperand(1).getReg(); @@ -3310,18 +4476,17 @@ bool MipsAsmParser::expandRotationImm(MCInst &Inst, SMLoc IDLoc, unsigned SecondShift = Mips::NOP; if (hasMips32r2()) { - if (Inst.getOpcode() == Mips::ROLImm) { uint64_t MaxShift = 32; uint64_t ShiftValue = ImmValue; if (ImmValue != 0) ShiftValue = MaxShift - ImmValue; - emitRRI(Mips::ROTR, DReg, SReg, ShiftValue, Inst.getLoc(), Instructions); + TOut.emitRRI(Mips::ROTR, DReg, SReg, ShiftValue, Inst.getLoc(), STI); return false; } if (Inst.getOpcode() == Mips::RORImm) { - emitRRI(Mips::ROTR, DReg, SReg, ImmValue, Inst.getLoc(), Instructions); + TOut.emitRRI(Mips::ROTR, DReg, SReg, ImmValue, Inst.getLoc(), STI); return false; } @@ -3329,9 +4494,8 @@ bool MipsAsmParser::expandRotationImm(MCInst &Inst, SMLoc IDLoc, } if (hasMips32()) { - if (ImmValue == 0) { - emitRRI(Mips::SRL, DReg, SReg, 0, Inst.getLoc(), Instructions); + TOut.emitRRI(Mips::SRL, DReg, SReg, 0, Inst.getLoc(), STI); return false; } @@ -3352,9 +4516,9 @@ bool MipsAsmParser::expandRotationImm(MCInst &Inst, SMLoc IDLoc, if (!ATReg) return true; - emitRRI(FirstShift, ATReg, SReg, ImmValue, Inst.getLoc(), Instructions); - emitRRI(SecondShift, DReg, SReg, 32 - ImmValue, Inst.getLoc(), Instructions); - emitRRR(Mips::OR, DReg, DReg, ATReg, Inst.getLoc(), Instructions); + TOut.emitRRI(FirstShift, ATReg, SReg, ImmValue, Inst.getLoc(), STI); + TOut.emitRRI(SecondShift, DReg, SReg, 32 - ImmValue, Inst.getLoc(), STI); + TOut.emitRRR(Mips::OR, DReg, DReg, ATReg, Inst.getLoc(), STI); return false; } @@ -3362,9 +4526,9 @@ bool MipsAsmParser::expandRotationImm(MCInst &Inst, SMLoc IDLoc, return true; } -bool MipsAsmParser::expandDRotation(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { - +bool MipsAsmParser::expandDRotation(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI) { + MipsTargetStreamer &TOut = getTargetStreamer(); unsigned ATReg = Mips::NoRegister; unsigned DReg = Inst.getOperand(0).getReg(); unsigned SReg = Inst.getOperand(1).getReg(); @@ -3375,7 +4539,6 @@ bool MipsAsmParser::expandDRotation(MCInst &Inst, SMLoc IDLoc, unsigned SecondShift = Mips::NOP; if (hasMips64r2()) { - if (TmpReg == SReg) { TmpReg = getATReg(Inst.getLoc()); if (!TmpReg) @@ -3383,13 +4546,13 @@ bool MipsAsmParser::expandDRotation(MCInst &Inst, SMLoc IDLoc, } if (Inst.getOpcode() == Mips::DROL) { - emitRRR(Mips::DSUBu, TmpReg, Mips::ZERO, TReg, Inst.getLoc(), Instructions); - emitRRR(Mips::DROTRV, DReg, SReg, TmpReg, Inst.getLoc(), Instructions); + TOut.emitRRR(Mips::DSUBu, TmpReg, Mips::ZERO, TReg, Inst.getLoc(), STI); + TOut.emitRRR(Mips::DROTRV, DReg, SReg, TmpReg, Inst.getLoc(), STI); return false; } if (Inst.getOpcode() == Mips::DROR) { - emitRRR(Mips::DROTRV, DReg, SReg, TReg, Inst.getLoc(), Instructions); + TOut.emitRRR(Mips::DROTRV, DReg, SReg, TReg, Inst.getLoc(), STI); return false; } @@ -3397,7 +4560,6 @@ bool MipsAsmParser::expandDRotation(MCInst &Inst, SMLoc IDLoc, } if (hasMips64()) { - switch (Inst.getOpcode()) { default: llvm_unreachable("unexpected instruction opcode"); @@ -3415,10 +4577,10 @@ bool MipsAsmParser::expandDRotation(MCInst &Inst, SMLoc IDLoc, if (!ATReg) return true; - emitRRR(Mips::DSUBu, ATReg, Mips::ZERO, TReg, Inst.getLoc(), Instructions); - emitRRR(FirstShift, ATReg, SReg, ATReg, Inst.getLoc(), Instructions); - emitRRR(SecondShift, DReg, SReg, TReg, Inst.getLoc(), Instructions); - emitRRR(Mips::OR, DReg, DReg, ATReg, Inst.getLoc(), Instructions); + TOut.emitRRR(Mips::DSUBu, ATReg, Mips::ZERO, TReg, Inst.getLoc(), STI); + TOut.emitRRR(FirstShift, ATReg, SReg, ATReg, Inst.getLoc(), STI); + TOut.emitRRR(SecondShift, DReg, SReg, TReg, Inst.getLoc(), STI); + TOut.emitRRR(Mips::OR, DReg, DReg, ATReg, Inst.getLoc(), STI); return false; } @@ -3427,8 +4589,9 @@ bool MipsAsmParser::expandDRotation(MCInst &Inst, SMLoc IDLoc, } bool MipsAsmParser::expandDRotationImm(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { - + MCStreamer &Out, + const MCSubtargetInfo *STI) { + MipsTargetStreamer &TOut = getTargetStreamer(); unsigned ATReg = Mips::NoRegister; unsigned DReg = Inst.getOperand(0).getReg(); unsigned SReg = Inst.getOperand(1).getReg(); @@ -3440,7 +4603,6 @@ bool MipsAsmParser::expandDRotationImm(MCInst &Inst, SMLoc IDLoc, MCInst TmpInst; if (hasMips64r2()) { - unsigned FinalOpcode = Mips::NOP; if (ImmValue == 0) FinalOpcode = Mips::DROTR; @@ -3462,15 +4624,14 @@ bool MipsAsmParser::expandDRotationImm(MCInst &Inst, SMLoc IDLoc, if (Inst.getOpcode() == Mips::DROLImm) ShiftValue = (32 - ImmValue % 32) % 32; - emitRRI(FinalOpcode, DReg, SReg, ShiftValue, Inst.getLoc(), Instructions); + TOut.emitRRI(FinalOpcode, DReg, SReg, ShiftValue, Inst.getLoc(), STI); return false; } if (hasMips64()) { - if (ImmValue == 0) { - emitRRI(Mips::DSRL, DReg, SReg, 0, Inst.getLoc(), Instructions); + TOut.emitRRI(Mips::DSRL, DReg, SReg, 0, Inst.getLoc(), STI); return false; } @@ -3511,9 +4672,10 @@ bool MipsAsmParser::expandDRotationImm(MCInst &Inst, SMLoc IDLoc, if (!ATReg) return true; - emitRRI(FirstShift, ATReg, SReg, ImmValue % 32, Inst.getLoc(), Instructions); - emitRRI(SecondShift, DReg, SReg, (32 - ImmValue % 32) % 32, Inst.getLoc(), Instructions); - emitRRR(Mips::OR, DReg, DReg, ATReg, Inst.getLoc(), Instructions); + TOut.emitRRI(FirstShift, ATReg, SReg, ImmValue % 32, Inst.getLoc(), STI); + TOut.emitRRI(SecondShift, DReg, SReg, (32 - ImmValue % 32) % 32, + Inst.getLoc(), STI); + TOut.emitRRR(Mips::OR, DReg, DReg, ATReg, Inst.getLoc(), STI); return false; } @@ -3521,49 +4683,620 @@ bool MipsAsmParser::expandDRotationImm(MCInst &Inst, SMLoc IDLoc, return true; } -void MipsAsmParser::createNop(bool hasShortDelaySlot, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { - if (hasShortDelaySlot) - emitRR(Mips::MOVE16_MM, Mips::ZERO, Mips::ZERO, IDLoc, Instructions); +bool MipsAsmParser::expandAbs(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI) { + MipsTargetStreamer &TOut = getTargetStreamer(); + unsigned FirstRegOp = Inst.getOperand(0).getReg(); + unsigned SecondRegOp = Inst.getOperand(1).getReg(); + + TOut.emitRI(Mips::BGEZ, SecondRegOp, 8, IDLoc, STI); + if (FirstRegOp != SecondRegOp) + TOut.emitRRR(Mips::ADDu, FirstRegOp, SecondRegOp, Mips::ZERO, IDLoc, STI); else - emitRRI(Mips::SLL, Mips::ZERO, Mips::ZERO, 0, IDLoc, Instructions); + TOut.emitEmptyDelaySlot(false, IDLoc, STI); + TOut.emitRRR(Mips::SUB, FirstRegOp, Mips::ZERO, SecondRegOp, IDLoc, STI); + + return false; } -void MipsAsmParser::createAddu(unsigned DstReg, unsigned SrcReg, - unsigned TrgReg, bool Is64Bit, - SmallVectorImpl<MCInst> &Instructions) { - emitRRR(Is64Bit ? Mips::DADDu : Mips::ADDu, DstReg, SrcReg, TrgReg, SMLoc(), - Instructions); +bool MipsAsmParser::expandMulImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI) { + MipsTargetStreamer &TOut = getTargetStreamer(); + unsigned ATReg = Mips::NoRegister; + unsigned DstReg = Inst.getOperand(0).getReg(); + unsigned SrcReg = Inst.getOperand(1).getReg(); + int32_t ImmValue = Inst.getOperand(2).getImm(); + + ATReg = getATReg(IDLoc); + if (!ATReg) + return true; + + loadImmediate(ImmValue, ATReg, Mips::NoRegister, true, false, IDLoc, Out, + STI); + + TOut.emitRR(Inst.getOpcode() == Mips::MULImmMacro ? Mips::MULT : Mips::DMULT, + SrcReg, ATReg, IDLoc, STI); + + TOut.emitR(Mips::MFLO, DstReg, IDLoc, STI); + + return false; +} + +bool MipsAsmParser::expandMulO(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI) { + MipsTargetStreamer &TOut = getTargetStreamer(); + unsigned ATReg = Mips::NoRegister; + unsigned DstReg = Inst.getOperand(0).getReg(); + unsigned SrcReg = Inst.getOperand(1).getReg(); + unsigned TmpReg = Inst.getOperand(2).getReg(); + + ATReg = getATReg(Inst.getLoc()); + if (!ATReg) + return true; + + TOut.emitRR(Inst.getOpcode() == Mips::MULOMacro ? Mips::MULT : Mips::DMULT, + SrcReg, TmpReg, IDLoc, STI); + + TOut.emitR(Mips::MFLO, DstReg, IDLoc, STI); + + TOut.emitRRI(Inst.getOpcode() == Mips::MULOMacro ? Mips::SRA : Mips::DSRA32, + DstReg, DstReg, 0x1F, IDLoc, STI); + + TOut.emitR(Mips::MFHI, ATReg, IDLoc, STI); + + if (useTraps()) { + TOut.emitRRI(Mips::TNE, DstReg, ATReg, 6, IDLoc, STI); + } else { + MCContext & Context = TOut.getStreamer().getContext(); + MCSymbol * BrTarget = Context.createTempSymbol(); + MCOperand LabelOp = + MCOperand::createExpr(MCSymbolRefExpr::create(BrTarget, Context)); + + TOut.emitRRX(Mips::BEQ, DstReg, ATReg, LabelOp, IDLoc, STI); + if (AssemblerOptions.back()->isReorder()) + TOut.emitNop(IDLoc, STI); + TOut.emitII(Mips::BREAK, 6, 0, IDLoc, STI); + + TOut.getStreamer().EmitLabel(BrTarget); + } + TOut.emitR(Mips::MFLO, DstReg, IDLoc, STI); + + return false; } -void MipsAsmParser::createCpRestoreMemOp( - bool IsLoad, int StackOffset, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { - // If the offset can not fit into 16 bits, we need to expand. - if (!isInt<16>(StackOffset)) { - MCInst MemInst; - MemInst.setOpcode(IsLoad ? Mips::LW : Mips::SW); - MemInst.addOperand(MCOperand::createReg(Mips::GP)); - MemInst.addOperand(MCOperand::createReg(Mips::SP)); - MemInst.addOperand(MCOperand::createImm(StackOffset)); - expandMemInst(MemInst, IDLoc, Instructions, IsLoad, true /*HasImmOpnd*/); - return; +bool MipsAsmParser::expandMulOU(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI) { + MipsTargetStreamer &TOut = getTargetStreamer(); + unsigned ATReg = Mips::NoRegister; + unsigned DstReg = Inst.getOperand(0).getReg(); + unsigned SrcReg = Inst.getOperand(1).getReg(); + unsigned TmpReg = Inst.getOperand(2).getReg(); + + ATReg = getATReg(IDLoc); + if (!ATReg) + return true; + + TOut.emitRR(Inst.getOpcode() == Mips::MULOUMacro ? Mips::MULTu : Mips::DMULTu, + SrcReg, TmpReg, IDLoc, STI); + + TOut.emitR(Mips::MFHI, ATReg, IDLoc, STI); + TOut.emitR(Mips::MFLO, DstReg, IDLoc, STI); + if (useTraps()) { + TOut.emitRRI(Mips::TNE, ATReg, Mips::ZERO, 6, IDLoc, STI); + } else { + MCContext & Context = TOut.getStreamer().getContext(); + MCSymbol * BrTarget = Context.createTempSymbol(); + MCOperand LabelOp = + MCOperand::createExpr(MCSymbolRefExpr::create(BrTarget, Context)); + + TOut.emitRRX(Mips::BEQ, ATReg, Mips::ZERO, LabelOp, IDLoc, STI); + if (AssemblerOptions.back()->isReorder()) + TOut.emitNop(IDLoc, STI); + TOut.emitII(Mips::BREAK, 6, 0, IDLoc, STI); + + TOut.getStreamer().EmitLabel(BrTarget); } - emitRRI(IsLoad ? Mips::LW : Mips::SW, Mips::GP, Mips::SP, StackOffset, IDLoc, - Instructions); + return false; +} + +bool MipsAsmParser::expandDMULMacro(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI) { + MipsTargetStreamer &TOut = getTargetStreamer(); + unsigned DstReg = Inst.getOperand(0).getReg(); + unsigned SrcReg = Inst.getOperand(1).getReg(); + unsigned TmpReg = Inst.getOperand(2).getReg(); + + TOut.emitRR(Mips::DMULTu, SrcReg, TmpReg, IDLoc, STI); + TOut.emitR(Mips::MFLO, DstReg, IDLoc, STI); + + return false; +} + +// Expand 'ld $<reg> offset($reg2)' to 'lw $<reg>, offset($reg2); +// lw $<reg+1>>, offset+4($reg2)' +// or expand 'sd $<reg> offset($reg2)' to 'sw $<reg>, offset($reg2); +// sw $<reg+1>>, offset+4($reg2)' +// for O32. +bool MipsAsmParser::expandLoadStoreDMacro(MCInst &Inst, SMLoc IDLoc, + MCStreamer &Out, + const MCSubtargetInfo *STI, + bool IsLoad) { + if (!isABI_O32()) + return true; + + warnIfNoMacro(IDLoc); + + MipsTargetStreamer &TOut = getTargetStreamer(); + unsigned Opcode = IsLoad ? Mips::LW : Mips::SW; + unsigned FirstReg = Inst.getOperand(0).getReg(); + unsigned SecondReg = nextReg(FirstReg); + unsigned BaseReg = Inst.getOperand(1).getReg(); + if (!SecondReg) + return true; + + warnIfRegIndexIsAT(FirstReg, IDLoc); + + assert(Inst.getOperand(2).isImm() && + "Offset for load macro is not immediate!"); + + MCOperand &FirstOffset = Inst.getOperand(2); + signed NextOffset = FirstOffset.getImm() + 4; + MCOperand SecondOffset = MCOperand::createImm(NextOffset); + + if (!isInt<16>(FirstOffset.getImm()) || !isInt<16>(NextOffset)) + return true; + + // For loads, clobber the base register with the second load instead of the + // first if the BaseReg == FirstReg. + if (FirstReg != BaseReg || !IsLoad) { + TOut.emitRRX(Opcode, FirstReg, BaseReg, FirstOffset, IDLoc, STI); + TOut.emitRRX(Opcode, SecondReg, BaseReg, SecondOffset, IDLoc, STI); + } else { + TOut.emitRRX(Opcode, SecondReg, BaseReg, SecondOffset, IDLoc, STI); + TOut.emitRRX(Opcode, FirstReg, BaseReg, FirstOffset, IDLoc, STI); + } + + return false; +} + +bool MipsAsmParser::expandSeq(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI) { + + warnIfNoMacro(IDLoc); + MipsTargetStreamer &TOut = getTargetStreamer(); + + if (Inst.getOperand(1).getReg() != Mips::ZERO && + Inst.getOperand(2).getReg() != Mips::ZERO) { + TOut.emitRRR(Mips::XOR, Inst.getOperand(0).getReg(), + Inst.getOperand(1).getReg(), Inst.getOperand(2).getReg(), + IDLoc, STI); + TOut.emitRRI(Mips::SLTiu, Inst.getOperand(0).getReg(), + Inst.getOperand(0).getReg(), 1, IDLoc, STI); + return false; + } + + unsigned Reg = 0; + if (Inst.getOperand(1).getReg() == Mips::ZERO) { + Reg = Inst.getOperand(2).getReg(); + } else { + Reg = Inst.getOperand(1).getReg(); + } + TOut.emitRRI(Mips::SLTiu, Inst.getOperand(0).getReg(), Reg, 1, IDLoc, STI); + return false; +} + +bool MipsAsmParser::expandSeqI(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI) { + warnIfNoMacro(IDLoc); + MipsTargetStreamer &TOut = getTargetStreamer(); + + unsigned Opc; + int64_t Imm = Inst.getOperand(2).getImm(); + unsigned Reg = Inst.getOperand(1).getReg(); + + if (Imm == 0) { + TOut.emitRRI(Mips::SLTiu, Inst.getOperand(0).getReg(), + Inst.getOperand(1).getReg(), 1, IDLoc, STI); + return false; + } else { + + if (Reg == Mips::ZERO) { + Warning(IDLoc, "comparison is always false"); + TOut.emitRRR(isGP64bit() ? Mips::DADDu : Mips::ADDu, + Inst.getOperand(0).getReg(), Reg, Reg, IDLoc, STI); + return false; + } + + if (Imm > -0x8000 && Imm < 0) { + Imm = -Imm; + Opc = isGP64bit() ? Mips::DADDiu : Mips::ADDiu; + } else { + Opc = Mips::XORi; + } + } + if (!isUInt<16>(Imm)) { + unsigned ATReg = getATReg(IDLoc); + if (!ATReg) + return true; + + if (loadImmediate(Imm, ATReg, Mips::NoRegister, true, isGP64bit(), IDLoc, + Out, STI)) + return true; + + TOut.emitRRR(Mips::XOR, Inst.getOperand(0).getReg(), + Inst.getOperand(1).getReg(), ATReg, IDLoc, STI); + TOut.emitRRI(Mips::SLTiu, Inst.getOperand(0).getReg(), + Inst.getOperand(0).getReg(), 1, IDLoc, STI); + return false; + } + + TOut.emitRRI(Opc, Inst.getOperand(0).getReg(), Inst.getOperand(1).getReg(), + Imm, IDLoc, STI); + TOut.emitRRI(Mips::SLTiu, Inst.getOperand(0).getReg(), + Inst.getOperand(0).getReg(), 1, IDLoc, STI); + return false; +} + +// Map the DSP accumulator and control register to the corresponding gpr +// operand. Unlike the other alias, the m(f|t)t(lo|hi|acx) instructions +// do not map the DSP registers contigously to gpr registers. +static unsigned getRegisterForMxtrDSP(MCInst &Inst, bool IsMFDSP) { + switch (Inst.getOpcode()) { + case Mips::MFTLO: + case Mips::MTTLO: + switch (Inst.getOperand(IsMFDSP ? 1 : 0).getReg()) { + case Mips::AC0: + return Mips::ZERO; + case Mips::AC1: + return Mips::A0; + case Mips::AC2: + return Mips::T0; + case Mips::AC3: + return Mips::T4; + default: + llvm_unreachable("Unknown register for 'mttr' alias!"); + } + case Mips::MFTHI: + case Mips::MTTHI: + switch (Inst.getOperand(IsMFDSP ? 1 : 0).getReg()) { + case Mips::AC0: + return Mips::AT; + case Mips::AC1: + return Mips::A1; + case Mips::AC2: + return Mips::T1; + case Mips::AC3: + return Mips::T5; + default: + llvm_unreachable("Unknown register for 'mttr' alias!"); + } + case Mips::MFTACX: + case Mips::MTTACX: + switch (Inst.getOperand(IsMFDSP ? 1 : 0).getReg()) { + case Mips::AC0: + return Mips::V0; + case Mips::AC1: + return Mips::A2; + case Mips::AC2: + return Mips::T2; + case Mips::AC3: + return Mips::T6; + default: + llvm_unreachable("Unknown register for 'mttr' alias!"); + } + case Mips::MFTDSP: + case Mips::MTTDSP: + return Mips::S0; + default: + llvm_unreachable("Unknown instruction for 'mttr' dsp alias!"); + } +} + +// Map the floating point register operand to the corresponding register +// operand. +static unsigned getRegisterForMxtrFP(MCInst &Inst, bool IsMFTC1) { + switch (Inst.getOperand(IsMFTC1 ? 1 : 0).getReg()) { + case Mips::F0: return Mips::ZERO; + case Mips::F1: return Mips::AT; + case Mips::F2: return Mips::V0; + case Mips::F3: return Mips::V1; + case Mips::F4: return Mips::A0; + case Mips::F5: return Mips::A1; + case Mips::F6: return Mips::A2; + case Mips::F7: return Mips::A3; + case Mips::F8: return Mips::T0; + case Mips::F9: return Mips::T1; + case Mips::F10: return Mips::T2; + case Mips::F11: return Mips::T3; + case Mips::F12: return Mips::T4; + case Mips::F13: return Mips::T5; + case Mips::F14: return Mips::T6; + case Mips::F15: return Mips::T7; + case Mips::F16: return Mips::S0; + case Mips::F17: return Mips::S1; + case Mips::F18: return Mips::S2; + case Mips::F19: return Mips::S3; + case Mips::F20: return Mips::S4; + case Mips::F21: return Mips::S5; + case Mips::F22: return Mips::S6; + case Mips::F23: return Mips::S7; + case Mips::F24: return Mips::T8; + case Mips::F25: return Mips::T9; + case Mips::F26: return Mips::K0; + case Mips::F27: return Mips::K1; + case Mips::F28: return Mips::GP; + case Mips::F29: return Mips::SP; + case Mips::F30: return Mips::FP; + case Mips::F31: return Mips::RA; + default: llvm_unreachable("Unknown register for mttc1 alias!"); + } +} + +// Map the coprocessor operand the corresponding gpr register operand. +static unsigned getRegisterForMxtrC0(MCInst &Inst, bool IsMFTC0) { + switch (Inst.getOperand(IsMFTC0 ? 1 : 0).getReg()) { + case Mips::COP00: return Mips::ZERO; + case Mips::COP01: return Mips::AT; + case Mips::COP02: return Mips::V0; + case Mips::COP03: return Mips::V1; + case Mips::COP04: return Mips::A0; + case Mips::COP05: return Mips::A1; + case Mips::COP06: return Mips::A2; + case Mips::COP07: return Mips::A3; + case Mips::COP08: return Mips::T0; + case Mips::COP09: return Mips::T1; + case Mips::COP010: return Mips::T2; + case Mips::COP011: return Mips::T3; + case Mips::COP012: return Mips::T4; + case Mips::COP013: return Mips::T5; + case Mips::COP014: return Mips::T6; + case Mips::COP015: return Mips::T7; + case Mips::COP016: return Mips::S0; + case Mips::COP017: return Mips::S1; + case Mips::COP018: return Mips::S2; + case Mips::COP019: return Mips::S3; + case Mips::COP020: return Mips::S4; + case Mips::COP021: return Mips::S5; + case Mips::COP022: return Mips::S6; + case Mips::COP023: return Mips::S7; + case Mips::COP024: return Mips::T8; + case Mips::COP025: return Mips::T9; + case Mips::COP026: return Mips::K0; + case Mips::COP027: return Mips::K1; + case Mips::COP028: return Mips::GP; + case Mips::COP029: return Mips::SP; + case Mips::COP030: return Mips::FP; + case Mips::COP031: return Mips::RA; + default: llvm_unreachable("Unknown register for mttc0 alias!"); + } +} + +/// Expand an alias of 'mftr' or 'mttr' into the full instruction, by producing +/// an mftr or mttr with the correctly mapped gpr register, u, sel and h bits. +bool MipsAsmParser::expandMXTRAlias(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI) { + MipsTargetStreamer &TOut = getTargetStreamer(); + unsigned rd = 0; + unsigned u = 1; + unsigned sel = 0; + unsigned h = 0; + bool IsMFTR = false; + switch (Inst.getOpcode()) { + case Mips::MFTC0: + IsMFTR = true; + LLVM_FALLTHROUGH; + case Mips::MTTC0: + u = 0; + rd = getRegisterForMxtrC0(Inst, IsMFTR); + sel = Inst.getOperand(2).getImm(); + break; + case Mips::MFTGPR: + IsMFTR = true; + LLVM_FALLTHROUGH; + case Mips::MTTGPR: + rd = Inst.getOperand(IsMFTR ? 1 : 0).getReg(); + break; + case Mips::MFTLO: + case Mips::MFTHI: + case Mips::MFTACX: + case Mips::MFTDSP: + IsMFTR = true; + LLVM_FALLTHROUGH; + case Mips::MTTLO: + case Mips::MTTHI: + case Mips::MTTACX: + case Mips::MTTDSP: + rd = getRegisterForMxtrDSP(Inst, IsMFTR); + sel = 1; + break; + case Mips::MFTHC1: + h = 1; + LLVM_FALLTHROUGH; + case Mips::MFTC1: + IsMFTR = true; + rd = getRegisterForMxtrFP(Inst, IsMFTR); + sel = 2; + break; + case Mips::MTTHC1: + h = 1; + LLVM_FALLTHROUGH; + case Mips::MTTC1: + rd = getRegisterForMxtrFP(Inst, IsMFTR); + sel = 2; + break; + case Mips::CFTC1: + IsMFTR = true; + LLVM_FALLTHROUGH; + case Mips::CTTC1: + rd = getRegisterForMxtrFP(Inst, IsMFTR); + sel = 3; + break; + } + unsigned Op0 = IsMFTR ? Inst.getOperand(0).getReg() : rd; + unsigned Op1 = + IsMFTR ? rd + : (Inst.getOpcode() != Mips::MTTDSP ? Inst.getOperand(1).getReg() + : Inst.getOperand(0).getReg()); + + TOut.emitRRIII(IsMFTR ? Mips::MFTR : Mips::MTTR, Op0, Op1, u, sel, h, IDLoc, + STI); + return false; +} + +unsigned +MipsAsmParser::checkEarlyTargetMatchPredicate(MCInst &Inst, + const OperandVector &Operands) { + switch (Inst.getOpcode()) { + default: + return Match_Success; + case Mips::DATI: + case Mips::DAHI: + if (static_cast<MipsOperand &>(*Operands[1]) + .isValidForTie(static_cast<MipsOperand &>(*Operands[2]))) + return Match_Success; + return Match_RequiresSameSrcAndDst; + } } unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) { + switch (Inst.getOpcode()) { + // As described by the MIPSR6 spec, daui must not use the zero operand for + // its source operand. + case Mips::DAUI: + if (Inst.getOperand(1).getReg() == Mips::ZERO || + Inst.getOperand(1).getReg() == Mips::ZERO_64) + return Match_RequiresNoZeroRegister; + return Match_Success; // As described by the Mips32r2 spec, the registers Rd and Rs for // jalr.hb must be different. - unsigned Opcode = Inst.getOpcode(); - - if (Opcode == Mips::JALR_HB && - (Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg())) - return Match_RequiresDifferentSrcAndDst; + // It also applies for registers Rt and Rs of microMIPSr6 jalrc.hb instruction + // and registers Rd and Base for microMIPS lwp instruction + case Mips::JALR_HB: + case Mips::JALR_HB64: + case Mips::JALRC_HB_MMR6: + case Mips::JALRC_MMR6: + if (Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg()) + return Match_RequiresDifferentSrcAndDst; + return Match_Success; + case Mips::LWP_MM: + if (Inst.getOperand(0).getReg() == Inst.getOperand(2).getReg()) + return Match_RequiresDifferentSrcAndDst; + return Match_Success; + case Mips::SYNC: + if (Inst.getOperand(0).getImm() != 0 && !hasMips32()) + return Match_NonZeroOperandForSync; + return Match_Success; + case Mips::MFC0: + case Mips::MTC0: + case Mips::MTC2: + case Mips::MFC2: + if (Inst.getOperand(2).getImm() != 0 && !hasMips32()) + return Match_NonZeroOperandForMTCX; + return Match_Success; + // As described the MIPSR6 spec, the compact branches that compare registers + // must: + // a) Not use the zero register. + // b) Not use the same register twice. + // c) rs < rt for bnec, beqc. + // NB: For this case, the encoding will swap the operands as their + // ordering doesn't matter. GAS performs this transformation too. + // Hence, that constraint does not have to be enforced. + // + // The compact branches that branch iff the signed addition of two registers + // would overflow must have rs >= rt. That can be handled like beqc/bnec with + // operand swapping. They do not have restriction of using the zero register. + case Mips::BLEZC: case Mips::BLEZC_MMR6: + case Mips::BGEZC: case Mips::BGEZC_MMR6: + case Mips::BGTZC: case Mips::BGTZC_MMR6: + case Mips::BLTZC: case Mips::BLTZC_MMR6: + case Mips::BEQZC: case Mips::BEQZC_MMR6: + case Mips::BNEZC: case Mips::BNEZC_MMR6: + case Mips::BLEZC64: + case Mips::BGEZC64: + case Mips::BGTZC64: + case Mips::BLTZC64: + case Mips::BEQZC64: + case Mips::BNEZC64: + if (Inst.getOperand(0).getReg() == Mips::ZERO || + Inst.getOperand(0).getReg() == Mips::ZERO_64) + return Match_RequiresNoZeroRegister; + return Match_Success; + case Mips::BGEC: case Mips::BGEC_MMR6: + case Mips::BLTC: case Mips::BLTC_MMR6: + case Mips::BGEUC: case Mips::BGEUC_MMR6: + case Mips::BLTUC: case Mips::BLTUC_MMR6: + case Mips::BEQC: case Mips::BEQC_MMR6: + case Mips::BNEC: case Mips::BNEC_MMR6: + case Mips::BGEC64: + case Mips::BLTC64: + case Mips::BGEUC64: + case Mips::BLTUC64: + case Mips::BEQC64: + case Mips::BNEC64: + if (Inst.getOperand(0).getReg() == Mips::ZERO || + Inst.getOperand(0).getReg() == Mips::ZERO_64) + return Match_RequiresNoZeroRegister; + if (Inst.getOperand(1).getReg() == Mips::ZERO || + Inst.getOperand(1).getReg() == Mips::ZERO_64) + return Match_RequiresNoZeroRegister; + if (Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg()) + return Match_RequiresDifferentOperands; + return Match_Success; + case Mips::DINS: { + assert(Inst.getOperand(2).isImm() && Inst.getOperand(3).isImm() && + "Operands must be immediates for dins!"); + const signed Pos = Inst.getOperand(2).getImm(); + const signed Size = Inst.getOperand(3).getImm(); + if ((0 > (Pos + Size)) || ((Pos + Size) > 32)) + return Match_RequiresPosSizeRange0_32; + return Match_Success; + } + case Mips::DINSM: + case Mips::DINSU: { + assert(Inst.getOperand(2).isImm() && Inst.getOperand(3).isImm() && + "Operands must be immediates for dinsm/dinsu!"); + const signed Pos = Inst.getOperand(2).getImm(); + const signed Size = Inst.getOperand(3).getImm(); + if ((32 >= (Pos + Size)) || ((Pos + Size) > 64)) + return Match_RequiresPosSizeRange33_64; + return Match_Success; + } + case Mips::DEXT: { + assert(Inst.getOperand(2).isImm() && Inst.getOperand(3).isImm() && + "Operands must be immediates for DEXTM!"); + const signed Pos = Inst.getOperand(2).getImm(); + const signed Size = Inst.getOperand(3).getImm(); + if ((1 > (Pos + Size)) || ((Pos + Size) > 63)) + return Match_RequiresPosSizeUImm6; + return Match_Success; + } + case Mips::DEXTM: + case Mips::DEXTU: { + assert(Inst.getOperand(2).isImm() && Inst.getOperand(3).isImm() && + "Operands must be immediates for dextm/dextu!"); + const signed Pos = Inst.getOperand(2).getImm(); + const signed Size = Inst.getOperand(3).getImm(); + if ((32 > (Pos + Size)) || ((Pos + Size) > 64)) + return Match_RequiresPosSizeRange33_64; + return Match_Success; + } + case Mips::CRC32B: case Mips::CRC32CB: + case Mips::CRC32H: case Mips::CRC32CH: + case Mips::CRC32W: case Mips::CRC32CW: + case Mips::CRC32D: case Mips::CRC32CD: + if (Inst.getOperand(0).getReg() != Inst.getOperand(2).getReg()) + return Match_RequiresSameSrcAndDst; + return Match_Success; + } + + uint64_t TSFlags = getInstDesc(Inst.getOpcode()).TSFlags; + if ((TSFlags & MipsII::HasFCCRegOperand) && + (Inst.getOperand(0).getReg() != Mips::FCC0) && !hasEightFccRegisters()) + return Match_NoFCCRegisterForCurrentISA; return Match_Success; + } static SMLoc RefineErrorLoc(const SMLoc Loc, const OperandVector &Operands, @@ -3582,20 +5315,15 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm) { - MCInst Inst; - SmallVector<MCInst, 8> Instructions; unsigned MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm); switch (MatchResult) { - case Match_Success: { - if (processInstruction(Inst, IDLoc, Instructions)) + case Match_Success: + if (processInstruction(Inst, IDLoc, Out, STI)) return true; - for (unsigned i = 0; i < Instructions.size(); i++) - Out.EmitInstruction(Instructions[i], getSTI()); return false; - } case Match_MissingFeature: Error(IDLoc, "instruction requires a CPU feature not currently enabled"); return true; @@ -3612,10 +5340,24 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, return Error(ErrorLoc, "invalid operand for instruction"); } + case Match_NonZeroOperandForSync: + return Error(IDLoc, + "s-type must be zero or unspecified for pre-MIPS32 ISAs"); + case Match_NonZeroOperandForMTCX: + return Error(IDLoc, "selector must be zero for pre-MIPS32 ISAs"); case Match_MnemonicFail: return Error(IDLoc, "invalid instruction"); case Match_RequiresDifferentSrcAndDst: return Error(IDLoc, "source and destination must be different"); + case Match_RequiresDifferentOperands: + return Error(IDLoc, "registers must be different"); + case Match_RequiresNoZeroRegister: + return Error(IDLoc, "invalid operand ($zero) for instruction"); + case Match_RequiresSameSrcAndDst: + return Error(IDLoc, "source and destination must match"); + case Match_NoFCCRegisterForCurrentISA: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "non-zero fcc register doesn't exist in current ISA level"); case Match_Immz: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected '0'"); case Match_UImm1_0: @@ -3633,9 +5375,15 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, case Match_UImm4_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 4-bit unsigned immediate"); + case Match_SImm4_0: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 4-bit signed immediate"); case Match_UImm5_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 5-bit unsigned immediate"); + case Match_SImm5_0: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 5-bit signed immediate"); case Match_UImm5_1: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range 1 .. 32"); @@ -3653,21 +5401,109 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, case Match_UImm5_Lsl2: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected both 7-bit unsigned immediate and multiple of 4"); + case Match_UImmRange2_64: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range 2 .. 64"); case Match_UImm6_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 6-bit unsigned immediate"); - case Match_SImm6: + case Match_UImm6_Lsl2: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected both 8-bit unsigned immediate and multiple of 4"); + case Match_SImm6_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 6-bit signed immediate"); case Match_UImm7_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 7-bit unsigned immediate"); + case Match_UImm7_N1: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range -1 .. 126"); + case Match_SImm7_Lsl2: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected both 9-bit signed immediate and multiple of 4"); case Match_UImm8_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 8-bit unsigned immediate"); case Match_UImm10_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 10-bit unsigned immediate"); + case Match_SImm10_0: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 10-bit signed immediate"); + case Match_SImm11_0: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 11-bit signed immediate"); + case Match_UImm16: + case Match_UImm16_Relaxed: + case Match_UImm16_AltRelaxed: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 16-bit unsigned immediate"); + case Match_SImm16: + case Match_SImm16_Relaxed: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 16-bit signed immediate"); + case Match_SImm19_Lsl2: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected both 19-bit signed immediate and multiple of 4"); + case Match_UImm20_0: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 20-bit unsigned immediate"); + case Match_UImm26_0: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 26-bit unsigned immediate"); + case Match_SImm32: + case Match_SImm32_Relaxed: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 32-bit signed immediate"); + case Match_UImm32_Coerced: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 32-bit immediate"); + case Match_MemSImm9: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected memory with 9-bit signed offset"); + case Match_MemSImm10: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected memory with 10-bit signed offset"); + case Match_MemSImm10Lsl1: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected memory with 11-bit signed offset and multiple of 2"); + case Match_MemSImm10Lsl2: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected memory with 12-bit signed offset and multiple of 4"); + case Match_MemSImm10Lsl3: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected memory with 13-bit signed offset and multiple of 8"); + case Match_MemSImm11: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected memory with 11-bit signed offset"); + case Match_MemSImm12: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected memory with 12-bit signed offset"); + case Match_MemSImm16: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected memory with 16-bit signed offset"); + case Match_MemSImmPtr: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected memory with 32-bit signed offset"); + case Match_RequiresPosSizeRange0_32: { + SMLoc ErrorStart = Operands[3]->getStartLoc(); + SMLoc ErrorEnd = Operands[4]->getEndLoc(); + return Error(ErrorStart, "size plus position are not in the range 0 .. 32", + SMRange(ErrorStart, ErrorEnd)); + } + case Match_RequiresPosSizeUImm6: { + SMLoc ErrorStart = Operands[3]->getStartLoc(); + SMLoc ErrorEnd = Operands[4]->getEndLoc(); + return Error(ErrorStart, "size plus position are not in the range 1 .. 63", + SMRange(ErrorStart, ErrorEnd)); + } + case Match_RequiresPosSizeRange33_64: { + SMLoc ErrorStart = Operands[3]->getStartLoc(); + SMLoc ErrorEnd = Operands[4]->getEndLoc(); + return Error(ErrorStart, "size plus position are not in the range 33 .. 64", + SMRange(ErrorStart, ErrorEnd)); + } } llvm_unreachable("Implement any new match types added!"); @@ -3684,6 +5520,17 @@ void MipsAsmParser::warnIfNoMacro(SMLoc Loc) { Warning(Loc, "macro instruction expanded into multiple instructions"); } +void MipsAsmParser::ConvertXWPOperands(MCInst &Inst, + const OperandVector &Operands) { + assert( + (Inst.getOpcode() == Mips::LWP_MM || Inst.getOpcode() == Mips::SWP_MM) && + "Unexpected instruction!"); + ((MipsOperand &)*Operands[1]).addGPR32ZeroAsmRegOperands(Inst, 1); + int NextReg = nextReg(((MipsOperand &)*Operands[1]).getGPR32Reg()); + Inst.addOperand(MCOperand::createReg(NextReg)); + ((MipsOperand &)*Operands[2]).addMemOperands(Inst, 2); +} + void MipsAsmParser::printWarningWithFixIt(const Twine &Msg, const Twine &FixMsg, SMRange Range, bool ShowColors) { @@ -3697,7 +5544,7 @@ int MipsAsmParser::matchCPURegisterName(StringRef Name) { CC = StringSwitch<unsigned>(Name) .Case("zero", 0) - .Case("at", 1) + .Cases("at", "AT", 1) .Case("a0", 4) .Case("a1", 5) .Case("a2", 6) @@ -3785,7 +5632,6 @@ int MipsAsmParser::matchHWRegsRegisterName(StringRef Name) { } int MipsAsmParser::matchFPURegisterName(StringRef Name) { - if (Name[0] == 'f') { StringRef NumString = Name.substr(1); unsigned IntVal; @@ -3799,7 +5645,6 @@ int MipsAsmParser::matchFPURegisterName(StringRef Name) { } int MipsAsmParser::matchFCCRegisterName(StringRef Name) { - if (Name.startswith("fcc")) { StringRef NumString = Name.substr(3); unsigned IntVal; @@ -3813,7 +5658,6 @@ int MipsAsmParser::matchFCCRegisterName(StringRef Name) { } int MipsAsmParser::matchACRegisterName(StringRef Name) { - if (Name.startswith("ac")) { StringRef NumString = Name.substr(2); unsigned IntVal; @@ -3855,6 +5699,10 @@ int MipsAsmParser::matchMSA128CtrlRegisterName(StringRef Name) { return CC; } +bool MipsAsmParser::canUseATReg() { + return AssemblerOptions.back()->getATRegIndex() != 0; +} + unsigned MipsAsmParser::getATReg(SMLoc Loc) { unsigned ATIndex = AssemblerOptions.back()->getATRegIndex(); if (ATIndex == 0) { @@ -3871,22 +5719,9 @@ unsigned MipsAsmParser::getReg(int RC, int RegNo) { return *(getContext().getRegisterInfo()->getRegClass(RC).begin() + RegNo); } -unsigned MipsAsmParser::getGPR(int RegNo) { - return getReg(isGP64bit() ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, - RegNo); -} - -int MipsAsmParser::matchRegisterByNumber(unsigned RegNum, unsigned RegClass) { - if (RegNum > - getContext().getRegisterInfo()->getRegClass(RegClass).getNumRegs() - 1) - return -1; - - return getReg(RegClass, RegNum); -} - bool MipsAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { MCAsmParser &Parser = getParser(); - DEBUG(dbgs() << "parseOperand\n"); + LLVM_DEBUG(dbgs() << "parseOperand\n"); // Check if the current operand has a custom associated parser, if so, try to // custom parse the operand, or fallback to the general approach. @@ -3899,12 +5734,9 @@ bool MipsAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { if (ResTy == MatchOperand_ParseFail) return true; - DEBUG(dbgs() << ".. Generic Parser\n"); + LLVM_DEBUG(dbgs() << ".. Generic Parser\n"); switch (getLexer().getKind()) { - default: - Error(Parser.getTok().getLoc(), "unexpected token in operand"); - return true; case AsmToken::Dollar: { // Parse the register. SMLoc S = Parser.getTok().getLoc(); @@ -3931,107 +5763,35 @@ bool MipsAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { Operands.push_back(MipsOperand::CreateImm(Res, S, E, *this)); return false; } - // Else drop to expression parsing. - case AsmToken::LParen: - case AsmToken::Minus: - case AsmToken::Plus: - case AsmToken::Integer: - case AsmToken::Tilde: - case AsmToken::String: { - DEBUG(dbgs() << ".. generic integer\n"); - OperandMatchResultTy ResTy = parseImm(Operands); - return ResTy != MatchOperand_Success; - } - case AsmToken::Percent: { - // It is a symbol reference or constant expression. - const MCExpr *IdVal; + default: { + LLVM_DEBUG(dbgs() << ".. generic integer expression\n"); + + const MCExpr *Expr; SMLoc S = Parser.getTok().getLoc(); // Start location of the operand. - if (parseRelocOperand(IdVal)) + if (getParser().parseExpression(Expr)) return true; SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); - Operands.push_back(MipsOperand::CreateImm(IdVal, S, E, *this)); + Operands.push_back(MipsOperand::CreateImm(Expr, S, E, *this)); return false; - } // case AsmToken::Percent + } } // switch(getLexer().getKind()) return true; } -const MCExpr *MipsAsmParser::evaluateRelocExpr(const MCExpr *Expr, - StringRef RelocStr) { - const MCExpr *Res; - // Check the type of the expression. - if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Expr)) { - // It's a constant, evaluate reloc value. - int16_t Val; - switch (getVariantKind(RelocStr)) { - case MCSymbolRefExpr::VK_Mips_ABS_LO: - // Get the 1st 16-bits. - Val = MCE->getValue() & 0xffff; - break; - case MCSymbolRefExpr::VK_Mips_ABS_HI: - // Get the 2nd 16-bits. Also add 1 if bit 15 is 1, to compensate for low - // 16 bits being negative. - Val = ((MCE->getValue() + 0x8000) >> 16) & 0xffff; - break; - case MCSymbolRefExpr::VK_Mips_HIGHER: - // Get the 3rd 16-bits. - Val = ((MCE->getValue() + 0x80008000LL) >> 32) & 0xffff; - break; - case MCSymbolRefExpr::VK_Mips_HIGHEST: - // Get the 4th 16-bits. - Val = ((MCE->getValue() + 0x800080008000LL) >> 48) & 0xffff; - break; - default: - report_fatal_error("unsupported reloc value"); - } - return MCConstantExpr::create(Val, getContext()); - } - - if (const MCSymbolRefExpr *MSRE = dyn_cast<MCSymbolRefExpr>(Expr)) { - // It's a symbol, create a symbolic expression from the symbol. - const MCSymbol *Symbol = &MSRE->getSymbol(); - MCSymbolRefExpr::VariantKind VK = getVariantKind(RelocStr); - Res = MCSymbolRefExpr::create(Symbol, VK, getContext()); - return Res; - } - - if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr)) { - MCSymbolRefExpr::VariantKind VK = getVariantKind(RelocStr); - - // Try to create target expression. - if (MipsMCExpr::isSupportedBinaryExpr(VK, BE)) - return MipsMCExpr::create(VK, Expr, getContext()); - - const MCExpr *LExp = evaluateRelocExpr(BE->getLHS(), RelocStr); - const MCExpr *RExp = evaluateRelocExpr(BE->getRHS(), RelocStr); - Res = MCBinaryExpr::create(BE->getOpcode(), LExp, RExp, getContext()); - return Res; - } - - if (const MCUnaryExpr *UN = dyn_cast<MCUnaryExpr>(Expr)) { - const MCExpr *UnExp = evaluateRelocExpr(UN->getSubExpr(), RelocStr); - Res = MCUnaryExpr::create(UN->getOpcode(), UnExp, getContext()); - return Res; - } - // Just return the original expression. - return Expr; -} - 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: - if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr)) { - if (!isEvaluated(BE->getLHS())) - return false; - return isEvaluated(BE->getRHS()); - } + 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: @@ -4040,49 +5800,6 @@ bool MipsAsmParser::isEvaluated(const MCExpr *Expr) { return false; } -bool MipsAsmParser::parseRelocOperand(const MCExpr *&Res) { - MCAsmParser &Parser = getParser(); - Parser.Lex(); // Eat the % token. - const AsmToken &Tok = Parser.getTok(); // Get next token, operation. - if (Tok.isNot(AsmToken::Identifier)) - return true; - - std::string Str = Tok.getIdentifier(); - - Parser.Lex(); // Eat the identifier. - // Now make an expression from the rest of the operand. - const MCExpr *IdVal; - SMLoc EndLoc; - - if (getLexer().getKind() == AsmToken::LParen) { - while (1) { - Parser.Lex(); // Eat the '(' token. - if (getLexer().getKind() == AsmToken::Percent) { - Parser.Lex(); // Eat the % token. - const AsmToken &nextTok = Parser.getTok(); - if (nextTok.isNot(AsmToken::Identifier)) - return true; - Str += "(%"; - Str += nextTok.getIdentifier(); - Parser.Lex(); // Eat the identifier. - if (getLexer().getKind() != AsmToken::LParen) - return true; - } else - break; - } - if (getParser().parseParenExpression(IdVal, EndLoc)) - return true; - - while (getLexer().getKind() == AsmToken::RParen) - Parser.Lex(); // Eat the ')' token. - - } else - return true; // Parenthesis must follow the relocation operand. - - Res = evaluateRelocExpr(IdVal, Str); - return false; -} - bool MipsAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { SmallVector<std::unique_ptr<MCParsedAsmOperand>, 1> Operands; @@ -4110,45 +5827,21 @@ bool MipsAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, } bool MipsAsmParser::parseMemOffset(const MCExpr *&Res, bool isParenExpr) { - MCAsmParser &Parser = getParser(); SMLoc S; - bool Result = true; - unsigned NumOfLParen = 0; - while (getLexer().getKind() == AsmToken::LParen) { - Parser.Lex(); - ++NumOfLParen; - } - - switch (getLexer().getKind()) { - default: - return true; - case AsmToken::Identifier: - case AsmToken::LParen: - case AsmToken::Integer: - case AsmToken::Minus: - case AsmToken::Plus: - if (isParenExpr) - Result = getParser().parseParenExprOfDepth(NumOfLParen, Res, S); - else - Result = (getParser().parseExpression(Res)); - while (getLexer().getKind() == AsmToken::RParen) - Parser.Lex(); - break; - case AsmToken::Percent: - Result = parseRelocOperand(Res); - } - return Result; + if (isParenExpr) + return getParser().parseParenExprOfDepth(0, Res, S); + return getParser().parseExpression(Res); } -MipsAsmParser::OperandMatchResultTy +OperandMatchResultTy MipsAsmParser::parseMemOperand(OperandVector &Operands) { MCAsmParser &Parser = getParser(); - DEBUG(dbgs() << "parseMemOperand\n"); + LLVM_DEBUG(dbgs() << "parseMemOperand\n"); const MCExpr *IdVal = nullptr; SMLoc S; bool isParenExpr = false; - MipsAsmParser::OperandMatchResultTy Res = MatchOperand_NoMatch; + OperandMatchResultTy Res = MatchOperand_NoMatch; // First operand is the offset. S = Parser.getTok().getLoc(); @@ -4176,14 +5869,66 @@ MipsAsmParser::parseMemOperand(OperandVector &Operands) { // Zero register assumed, add a memory operand with ZERO as its base. // "Base" will be managed by k_Memory. - auto Base = MipsOperand::createGPRReg(0, getContext().getRegisterInfo(), - S, E, *this); + auto Base = MipsOperand::createGPRReg( + 0, "0", getContext().getRegisterInfo(), S, E, *this); Operands.push_back( MipsOperand::CreateMem(std::move(Base), IdVal, S, E, *this)); return MatchOperand_Success; } - Error(Parser.getTok().getLoc(), "'(' expected"); - return MatchOperand_ParseFail; + MCBinaryExpr::Opcode Opcode; + // GAS and LLVM treat comparison operators different. GAS will generate -1 + // or 0, while LLVM will generate 0 or 1. Since a comparsion operator is + // highly unlikely to be found in a memory offset expression, we don't + // handle them. + switch (Tok.getKind()) { + case AsmToken::Plus: + Opcode = MCBinaryExpr::Add; + Parser.Lex(); + break; + case AsmToken::Minus: + Opcode = MCBinaryExpr::Sub; + Parser.Lex(); + break; + case AsmToken::Star: + Opcode = MCBinaryExpr::Mul; + Parser.Lex(); + break; + case AsmToken::Pipe: + Opcode = MCBinaryExpr::Or; + Parser.Lex(); + break; + case AsmToken::Amp: + Opcode = MCBinaryExpr::And; + Parser.Lex(); + break; + case AsmToken::LessLess: + Opcode = MCBinaryExpr::Shl; + Parser.Lex(); + break; + case AsmToken::GreaterGreater: + Opcode = MCBinaryExpr::LShr; + Parser.Lex(); + break; + case AsmToken::Caret: + Opcode = MCBinaryExpr::Xor; + Parser.Lex(); + break; + case AsmToken::Slash: + Opcode = MCBinaryExpr::Div; + Parser.Lex(); + break; + case AsmToken::Percent: + Opcode = MCBinaryExpr::Mod; + Parser.Lex(); + break; + default: + Error(Parser.getTok().getLoc(), "'(' or expression expected"); + return MatchOperand_ParseFail; + } + const MCExpr * NextExpr; + if (getParser().parseExpression(NextExpr)) + return MatchOperand_ParseFail; + IdVal = MCBinaryExpr::create(Opcode, IdVal, NextExpr, getContext()); } Parser.Lex(); // Eat the '(' token. @@ -4228,13 +5973,12 @@ MipsAsmParser::parseMemOperand(OperandVector &Operands) { bool MipsAsmParser::searchSymbolAlias(OperandVector &Operands) { MCAsmParser &Parser = getParser(); MCSymbol *Sym = getContext().lookupSymbol(Parser.getTok().getIdentifier()); - if (Sym) { - SMLoc S = Parser.getTok().getLoc(); - const MCExpr *Expr; - if (Sym->isVariable()) - Expr = Sym->getVariableValue(); - else - return false; + if (!Sym) + return false; + + SMLoc S = Parser.getTok().getLoc(); + if (Sym->isVariable()) { + const MCExpr *Expr = Sym->getVariableValue(); if (Expr->getKind() == MCExpr::SymbolRef) { const MCSymbolRefExpr *Ref = static_cast<const MCSymbolRefExpr *>(Expr); StringRef DefSymbol = Ref->getSymbol().getName(); @@ -4244,120 +5988,146 @@ bool MipsAsmParser::searchSymbolAlias(OperandVector &Operands) { if (ResTy == MatchOperand_Success) { Parser.Lex(); return true; - } else if (ResTy == MatchOperand_ParseFail) + } + if (ResTy == MatchOperand_ParseFail) llvm_unreachable("Should never ParseFail"); - return false; } - } else if (Expr->getKind() == MCExpr::Constant) { - Parser.Lex(); - const MCConstantExpr *Const = static_cast<const MCConstantExpr *>(Expr); - Operands.push_back( - MipsOperand::CreateImm(Const, S, Parser.getTok().getLoc(), *this)); - return true; + } + } else if (Sym->isUnset()) { + // If symbol is unset, it might be created in the `parseSetAssignment` + // routine as an alias for a numeric register name. + // Lookup in the aliases list. + auto Entry = RegisterSets.find(Sym->getName()); + if (Entry != RegisterSets.end()) { + OperandMatchResultTy ResTy = + matchAnyRegisterWithoutDollar(Operands, Entry->getValue(), S); + if (ResTy == MatchOperand_Success) { + Parser.Lex(); + return true; + } } } + return false; } -MipsAsmParser::OperandMatchResultTy +OperandMatchResultTy MipsAsmParser::matchAnyRegisterNameWithoutDollar(OperandVector &Operands, StringRef Identifier, SMLoc S) { int Index = matchCPURegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createGPRReg( - Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + Index, Identifier, getContext().getRegisterInfo(), S, + getLexer().getLoc(), *this)); return MatchOperand_Success; } Index = matchHWRegsRegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createHWRegsReg( - Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + Index, Identifier, getContext().getRegisterInfo(), S, + getLexer().getLoc(), *this)); return MatchOperand_Success; } Index = matchFPURegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createFGRReg( - Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + Index, Identifier, getContext().getRegisterInfo(), S, + getLexer().getLoc(), *this)); return MatchOperand_Success; } Index = matchFCCRegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createFCCReg( - Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + Index, Identifier, getContext().getRegisterInfo(), S, + getLexer().getLoc(), *this)); return MatchOperand_Success; } Index = matchACRegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createACCReg( - Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + Index, Identifier, getContext().getRegisterInfo(), S, + getLexer().getLoc(), *this)); return MatchOperand_Success; } Index = matchMSA128RegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createMSA128Reg( - Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + Index, Identifier, getContext().getRegisterInfo(), S, + getLexer().getLoc(), *this)); return MatchOperand_Success; } Index = matchMSA128CtrlRegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createMSACtrlReg( - Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + Index, Identifier, getContext().getRegisterInfo(), S, + getLexer().getLoc(), *this)); return MatchOperand_Success; } return MatchOperand_NoMatch; } -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::matchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S) { - MCAsmParser &Parser = getParser(); - auto Token = Parser.getLexer().peekTok(false); - +OperandMatchResultTy +MipsAsmParser::matchAnyRegisterWithoutDollar(OperandVector &Operands, + const AsmToken &Token, SMLoc S) { if (Token.is(AsmToken::Identifier)) { - DEBUG(dbgs() << ".. identifier\n"); + LLVM_DEBUG(dbgs() << ".. identifier\n"); StringRef Identifier = Token.getIdentifier(); OperandMatchResultTy ResTy = matchAnyRegisterNameWithoutDollar(Operands, Identifier, S); return ResTy; } else if (Token.is(AsmToken::Integer)) { - DEBUG(dbgs() << ".. integer\n"); + LLVM_DEBUG(dbgs() << ".. integer\n"); + int64_t RegNum = Token.getIntVal(); + if (RegNum < 0 || RegNum > 31) { + // Show the error, but treat invalid register + // number as a normal one to continue parsing + // and catch other possible errors. + Error(getLexer().getLoc(), "invalid register number"); + } Operands.push_back(MipsOperand::createNumericReg( - Token.getIntVal(), getContext().getRegisterInfo(), S, Token.getLoc(), - *this)); + RegNum, Token.getString(), getContext().getRegisterInfo(), S, + Token.getLoc(), *this)); return MatchOperand_Success; } - DEBUG(dbgs() << Parser.getTok().getKind() << "\n"); + LLVM_DEBUG(dbgs() << Token.getKind() << "\n"); return MatchOperand_NoMatch; } -MipsAsmParser::OperandMatchResultTy +OperandMatchResultTy +MipsAsmParser::matchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S) { + auto Token = getLexer().peekTok(false); + return matchAnyRegisterWithoutDollar(Operands, Token, S); +} + +OperandMatchResultTy MipsAsmParser::parseAnyRegister(OperandVector &Operands) { MCAsmParser &Parser = getParser(); - DEBUG(dbgs() << "parseAnyRegister\n"); + LLVM_DEBUG(dbgs() << "parseAnyRegister\n"); auto Token = Parser.getTok(); SMLoc S = Token.getLoc(); if (Token.isNot(AsmToken::Dollar)) { - DEBUG(dbgs() << ".. !$ -> try sym aliasing\n"); + LLVM_DEBUG(dbgs() << ".. !$ -> try sym aliasing\n"); if (Token.is(AsmToken::Identifier)) { if (searchSymbolAlias(Operands)) return MatchOperand_Success; } - DEBUG(dbgs() << ".. !symalias -> NoMatch\n"); + LLVM_DEBUG(dbgs() << ".. !symalias -> NoMatch\n"); return MatchOperand_NoMatch; } - DEBUG(dbgs() << ".. $\n"); + LLVM_DEBUG(dbgs() << ".. $\n"); OperandMatchResultTy ResTy = matchAnyRegisterWithoutDollar(Operands, S); if (ResTy == MatchOperand_Success) { @@ -4367,48 +6137,19 @@ MipsAsmParser::parseAnyRegister(OperandVector &Operands) { return ResTy; } -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseImm(OperandVector &Operands) { - MCAsmParser &Parser = getParser(); - switch (getLexer().getKind()) { - default: - return MatchOperand_NoMatch; - case AsmToken::LParen: - case AsmToken::Minus: - case AsmToken::Plus: - case AsmToken::Integer: - case AsmToken::Tilde: - case AsmToken::String: - break; - } - - const MCExpr *IdVal; - SMLoc S = Parser.getTok().getLoc(); - if (getParser().parseExpression(IdVal)) - return MatchOperand_ParseFail; - - SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); - Operands.push_back(MipsOperand::CreateImm(IdVal, S, E, *this)); - return MatchOperand_Success; -} - -MipsAsmParser::OperandMatchResultTy +OperandMatchResultTy MipsAsmParser::parseJumpTarget(OperandVector &Operands) { MCAsmParser &Parser = getParser(); - DEBUG(dbgs() << "parseJumpTarget\n"); + LLVM_DEBUG(dbgs() << "parseJumpTarget\n"); SMLoc S = getLexer().getLoc(); - // Integers and expressions are acceptable - OperandMatchResultTy ResTy = parseImm(Operands); - if (ResTy != MatchOperand_NoMatch) - return ResTy; - // Registers are a valid target and have priority over symbols. - ResTy = parseAnyRegister(Operands); + OperandMatchResultTy ResTy = parseAnyRegister(Operands); if (ResTy != MatchOperand_NoMatch) return ResTy; + // Integers and expressions are acceptable const MCExpr *Expr = nullptr; if (Parser.parseExpression(Expr)) { // We have no way of knowing if a symbol was consumed so we must ParseFail @@ -4419,18 +6160,25 @@ MipsAsmParser::parseJumpTarget(OperandVector &Operands) { return MatchOperand_Success; } -MipsAsmParser::OperandMatchResultTy +OperandMatchResultTy MipsAsmParser::parseInvNum(OperandVector &Operands) { MCAsmParser &Parser = getParser(); const MCExpr *IdVal; - // If the first token is '$' we may have register operand. - if (Parser.getTok().is(AsmToken::Dollar)) - return MatchOperand_NoMatch; + // If the first token is '$' we may have register operand. We have to reject + // cases where it is not a register. Complicating the matter is that + // register names are not reserved across all ABIs. + // Peek past the dollar to see if it's a register name for this ABI. SMLoc S = Parser.getTok().getLoc(); + if (Parser.getTok().is(AsmToken::Dollar)) { + return matchCPURegisterName(Parser.getLexer().peekTok().getString()) == -1 + ? MatchOperand_ParseFail + : MatchOperand_NoMatch; + } if (getParser().parseExpression(IdVal)) return MatchOperand_ParseFail; const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(IdVal); - assert(MCE && "Unexpected MCExpr type."); + if (!MCE) + return MatchOperand_NoMatch; int64_t Val = MCE->getValue(); SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); Operands.push_back(MipsOperand::CreateImm( @@ -4438,47 +6186,7 @@ MipsAsmParser::parseInvNum(OperandVector &Operands) { return MatchOperand_Success; } -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseLSAImm(OperandVector &Operands) { - MCAsmParser &Parser = getParser(); - switch (getLexer().getKind()) { - default: - return MatchOperand_NoMatch; - case AsmToken::LParen: - case AsmToken::Plus: - case AsmToken::Minus: - case AsmToken::Integer: - break; - } - - const MCExpr *Expr; - SMLoc S = Parser.getTok().getLoc(); - - if (getParser().parseExpression(Expr)) - return MatchOperand_ParseFail; - - int64_t Val; - if (!Expr->evaluateAsAbsolute(Val)) { - Error(S, "expected immediate value"); - return MatchOperand_ParseFail; - } - - // The LSA instruction allows a 2-bit unsigned immediate. For this reason - // and because the CPU always adds one to the immediate field, the allowed - // range becomes 1..4. We'll only check the range here and will deal - // with the addition/subtraction when actually decoding/encoding - // the instruction. - if (Val < 1 || Val > 4) { - Error(S, "immediate not in range (1..4)"); - return MatchOperand_ParseFail; - } - - Operands.push_back( - MipsOperand::CreateImm(Expr, S, Parser.getTok().getLoc(), *this)); - return MatchOperand_Success; -} - -MipsAsmParser::OperandMatchResultTy +OperandMatchResultTy MipsAsmParser::parseRegisterList(OperandVector &Operands) { MCAsmParser &Parser = getParser(); SmallVector<unsigned, 10> Regs; @@ -4564,97 +6272,6 @@ MipsAsmParser::parseRegisterList(OperandVector &Operands) { return MatchOperand_Success; } -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseRegisterPair(OperandVector &Operands) { - MCAsmParser &Parser = getParser(); - - SMLoc S = Parser.getTok().getLoc(); - if (parseAnyRegister(Operands) != MatchOperand_Success) - return MatchOperand_ParseFail; - - SMLoc E = Parser.getTok().getLoc(); - MipsOperand &Op = static_cast<MipsOperand &>(*Operands.back()); - unsigned Reg = Op.getGPR32Reg(); - Operands.pop_back(); - Operands.push_back(MipsOperand::CreateRegPair(Reg, S, E, *this)); - return MatchOperand_Success; -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseMovePRegPair(OperandVector &Operands) { - MCAsmParser &Parser = getParser(); - SmallVector<std::unique_ptr<MCParsedAsmOperand>, 8> TmpOperands; - SmallVector<unsigned, 10> Regs; - - if (Parser.getTok().isNot(AsmToken::Dollar)) - return MatchOperand_ParseFail; - - SMLoc S = Parser.getTok().getLoc(); - - if (parseAnyRegister(TmpOperands) != MatchOperand_Success) - return MatchOperand_ParseFail; - - MipsOperand *Reg = &static_cast<MipsOperand &>(*TmpOperands.back()); - unsigned RegNo = isGP64bit() ? Reg->getGPR64Reg() : Reg->getGPR32Reg(); - Regs.push_back(RegNo); - - SMLoc E = Parser.getTok().getLoc(); - if (Parser.getTok().isNot(AsmToken::Comma)) { - Error(E, "',' expected"); - return MatchOperand_ParseFail; - } - - // Remove comma. - Parser.Lex(); - - if (parseAnyRegister(TmpOperands) != MatchOperand_Success) - return MatchOperand_ParseFail; - - Reg = &static_cast<MipsOperand &>(*TmpOperands.back()); - RegNo = isGP64bit() ? Reg->getGPR64Reg() : Reg->getGPR32Reg(); - Regs.push_back(RegNo); - - Operands.push_back(MipsOperand::CreateRegList(Regs, S, E, *this)); - - return MatchOperand_Success; -} - -MCSymbolRefExpr::VariantKind MipsAsmParser::getVariantKind(StringRef Symbol) { - - MCSymbolRefExpr::VariantKind VK = - StringSwitch<MCSymbolRefExpr::VariantKind>(Symbol) - .Case("hi", MCSymbolRefExpr::VK_Mips_ABS_HI) - .Case("lo", MCSymbolRefExpr::VK_Mips_ABS_LO) - .Case("gp_rel", MCSymbolRefExpr::VK_Mips_GPREL) - .Case("call16", MCSymbolRefExpr::VK_Mips_GOT_CALL) - .Case("got", MCSymbolRefExpr::VK_Mips_GOT) - .Case("tlsgd", MCSymbolRefExpr::VK_Mips_TLSGD) - .Case("tlsldm", MCSymbolRefExpr::VK_Mips_TLSLDM) - .Case("dtprel_hi", MCSymbolRefExpr::VK_Mips_DTPREL_HI) - .Case("dtprel_lo", MCSymbolRefExpr::VK_Mips_DTPREL_LO) - .Case("gottprel", MCSymbolRefExpr::VK_Mips_GOTTPREL) - .Case("tprel_hi", MCSymbolRefExpr::VK_Mips_TPREL_HI) - .Case("tprel_lo", MCSymbolRefExpr::VK_Mips_TPREL_LO) - .Case("got_disp", MCSymbolRefExpr::VK_Mips_GOT_DISP) - .Case("got_page", MCSymbolRefExpr::VK_Mips_GOT_PAGE) - .Case("got_ofst", MCSymbolRefExpr::VK_Mips_GOT_OFST) - .Case("hi(%neg(%gp_rel", MCSymbolRefExpr::VK_Mips_GPOFF_HI) - .Case("lo(%neg(%gp_rel", MCSymbolRefExpr::VK_Mips_GPOFF_LO) - .Case("got_hi", MCSymbolRefExpr::VK_Mips_GOT_HI16) - .Case("got_lo", MCSymbolRefExpr::VK_Mips_GOT_LO16) - .Case("call_hi", MCSymbolRefExpr::VK_Mips_CALL_HI16) - .Case("call_lo", MCSymbolRefExpr::VK_Mips_CALL_LO16) - .Case("higher", MCSymbolRefExpr::VK_Mips_HIGHER) - .Case("highest", MCSymbolRefExpr::VK_Mips_HIGHEST) - .Case("pcrel_hi", MCSymbolRefExpr::VK_Mips_PCREL_HI16) - .Case("pcrel_lo", MCSymbolRefExpr::VK_Mips_PCREL_LO16) - .Default(MCSymbolRefExpr::VK_None); - - assert(VK != MCSymbolRefExpr::VK_None); - - return VK; -} - /// Sometimes (i.e. load/stores) the operand may be followed immediately by /// either this. /// ::= '(', register, ')' @@ -4668,12 +6285,10 @@ bool MipsAsmParser::parseParenSuffix(StringRef Name, OperandVector &Operands) { Parser.Lex(); if (parseOperand(Operands, Name)) { SMLoc Loc = getLexer().getLoc(); - Parser.eatToEndOfStatement(); return Error(Loc, "unexpected token in argument list"); } if (Parser.getTok().isNot(AsmToken::RParen)) { SMLoc Loc = getLexer().getLoc(); - Parser.eatToEndOfStatement(); return Error(Loc, "unexpected token, expected ')'"); } Operands.push_back( @@ -4698,12 +6313,10 @@ bool MipsAsmParser::parseBracketSuffix(StringRef Name, Parser.Lex(); if (parseOperand(Operands, Name)) { SMLoc Loc = getLexer().getLoc(); - Parser.eatToEndOfStatement(); return Error(Loc, "unexpected token in argument list"); } if (Parser.getTok().isNot(AsmToken::RBrac)) { SMLoc Loc = getLexer().getLoc(); - Parser.eatToEndOfStatement(); return Error(Loc, "unexpected token, expected ']'"); } Operands.push_back( @@ -4713,18 +6326,22 @@ bool MipsAsmParser::parseBracketSuffix(StringRef Name, return false; } +static std::string MipsMnemonicSpellCheck(StringRef S, uint64_t FBS, + unsigned VariantID = 0); + bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) { MCAsmParser &Parser = getParser(); - DEBUG(dbgs() << "ParseInstruction\n"); + LLVM_DEBUG(dbgs() << "ParseInstruction\n"); // We have reached first instruction, module directive are now forbidden. getTargetStreamer().forbidModuleDirective(); // Check if we have valid mnemonic if (!mnemonicIsValid(Name, 0)) { - Parser.eatToEndOfStatement(); - return Error(NameLoc, "unknown instruction"); + uint64_t FBS = ComputeAvailableFeatures(getSTI().getFeatureBits()); + std::string Suggestion = MipsMnemonicSpellCheck(Name, FBS); + return Error(NameLoc, "unknown instruction" + Suggestion); } // First operand in MCInst is instruction mnemonic. Operands.push_back(MipsOperand::CreateToken(Name, NameLoc, *this)); @@ -4734,7 +6351,6 @@ bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, // Read the first operand. if (parseOperand(Operands, Name)) { SMLoc Loc = getLexer().getLoc(); - Parser.eatToEndOfStatement(); return Error(Loc, "unexpected token in argument list"); } if (getLexer().is(AsmToken::LBrac) && parseBracketSuffix(Name, Operands)) @@ -4746,7 +6362,6 @@ bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, // Parse and remember the operand. if (parseOperand(Operands, Name)) { SMLoc Loc = getLexer().getLoc(); - Parser.eatToEndOfStatement(); return Error(Loc, "unexpected token in argument list"); } // Parse bracket and parenthesis suffixes before we iterate @@ -4760,17 +6375,16 @@ bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, } if (getLexer().isNot(AsmToken::EndOfStatement)) { SMLoc Loc = getLexer().getLoc(); - Parser.eatToEndOfStatement(); return Error(Loc, "unexpected token in argument list"); } Parser.Lex(); // Consume the EndOfStatement. return false; } +// FIXME: Given that these have the same name, these should both be +// consistent on affecting the Parser. bool MipsAsmParser::reportParseError(Twine ErrorMsg) { - MCAsmParser &Parser = getParser(); SMLoc Loc = getLexer().getLoc(); - Parser.eatToEndOfStatement(); return Error(Loc, ErrorMsg); } @@ -5049,6 +6663,90 @@ bool MipsAsmParser::parseSetNoOddSPRegDirective() { return false; } +bool MipsAsmParser::parseSetMtDirective() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); // Eat "mt". + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + setFeatureBits(Mips::FeatureMT, "mt"); + getTargetStreamer().emitDirectiveSetMt(); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseSetNoMtDirective() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); // Eat "nomt". + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + clearFeatureBits(Mips::FeatureMT, "mt"); + + getTargetStreamer().emitDirectiveSetNoMt(); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseSetNoCRCDirective() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); // Eat "nocrc". + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + clearFeatureBits(Mips::FeatureCRC, "crc"); + + getTargetStreamer().emitDirectiveSetNoCRC(); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseSetNoVirtDirective() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); // Eat "novirt". + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + clearFeatureBits(Mips::FeatureVirt, "virt"); + + getTargetStreamer().emitDirectiveSetNoVirt(); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseSetNoGINVDirective() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); // Eat "noginv". + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + clearFeatureBits(Mips::FeatureGINV, "ginv"); + + getTargetStreamer().emitDirectiveSetNoGINV(); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + bool MipsAsmParser::parseSetPopDirective() { MCAsmParser &Parser = getParser(); SMLoc Loc = getLexer().getLoc(); @@ -5080,7 +6778,7 @@ bool MipsAsmParser::parseSetPushDirective() { // Create a copy of the current assembler options environment and push it. AssemblerOptions.push_back( - make_unique<MipsAssemblerOptions>(AssemblerOptions.back().get())); + llvm::make_unique<MipsAssemblerOptions>(AssemblerOptions.back().get())); getTargetStreamer().emitDirectiveSetPush(); return false; @@ -5114,17 +6812,30 @@ bool MipsAsmParser::parseSetAssignment() { MCAsmParser &Parser = getParser(); if (Parser.parseIdentifier(Name)) - reportParseError("expected identifier after .set"); + return reportParseError("expected identifier after .set"); if (getLexer().isNot(AsmToken::Comma)) return reportParseError("unexpected token, expected comma"); Lex(); // Eat comma - if (Parser.parseExpression(Value)) + if (getLexer().is(AsmToken::Dollar) && + getLexer().peekTok().is(AsmToken::Integer)) { + // Parse assignment of a numeric register: + // .set r1,$1 + Parser.Lex(); // Eat $. + RegisterSets[Name] = Parser.getTok(); + Parser.Lex(); // Eat identifier. + getContext().getOrCreateSymbol(Name); + } else if (!Parser.parseExpression(Value)) { + // Parse assignment of an expression including + // symbolic registers: + // .set $tmp, $BB0-$BB1 + // .set r2, $f2 + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + Sym->setVariableValue(Value); + } else { return reportParseError("expected valid expression after comma"); - - MCSymbol *Sym = getContext().getOrCreateSymbol(Name); - Sym->setVariableValue(Value); + } return false; } @@ -5174,13 +6885,16 @@ bool MipsAsmParser::parseSetArchDirective() { .Case("mips64r3", "mips64r3") .Case("mips64r5", "mips64r5") .Case("mips64r6", "mips64r6") - .Case("cnmips", "cnmips") + .Case("octeon", "cnmips") .Case("r4000", "mips3") // This is an implementation of Mips3. .Default(""); if (ArchFeatureName.empty()) return reportParseError("unsupported architecture"); + if (ArchFeatureName == "mips64r6" && inMicroMipsMode()) + return reportParseError("mips64r6 does not support microMIPS"); + selectArch(ArchFeatureName); getTargetStreamer().emitDirectiveSetArch(Arch); return false; @@ -5199,7 +6913,12 @@ bool MipsAsmParser::parseSetFeature(uint64_t Feature) { setFeatureBits(Mips::FeatureDSP, "dsp"); getTargetStreamer().emitDirectiveSetDsp(); break; + case Mips::FeatureDSPR2: + setFeatureBits(Mips::FeatureDSPR2, "dspr2"); + getTargetStreamer().emitDirectiveSetDspr2(); + break; case Mips::FeatureMicroMips: + setFeatureBits(Mips::FeatureMicroMips, "micromips"); getTargetStreamer().emitDirectiveSetMicroMips(); break; case Mips::FeatureMips1: @@ -5262,6 +6981,18 @@ bool MipsAsmParser::parseSetFeature(uint64_t Feature) { selectArch("mips64r6"); getTargetStreamer().emitDirectiveSetMips64R6(); break; + case Mips::FeatureCRC: + setFeatureBits(Mips::FeatureCRC, "crc"); + getTargetStreamer().emitDirectiveSetCRC(); + break; + case Mips::FeatureVirt: + setFeatureBits(Mips::FeatureVirt, "virt"); + getTargetStreamer().emitDirectiveSetVirt(); + break; + case Mips::FeatureGINV: + setFeatureBits(Mips::FeatureGINV, "ginv"); + getTargetStreamer().emitDirectiveSetGINV(); + break; } return false; } @@ -5270,7 +7001,6 @@ bool MipsAsmParser::eatComma(StringRef ErrorStr) { MCAsmParser &Parser = getParser(); if (getLexer().isNot(AsmToken::Comma)) { SMLoc Loc = getLexer().getLoc(); - Parser.eatToEndOfStatement(); return Error(Loc, ErrorStr); } @@ -5356,12 +7086,9 @@ bool MipsAsmParser::parseDirectiveCpRestore(SMLoc Loc) { return false; } - // Store the $gp on the stack. - SmallVector<MCInst, 3> StoreInsts; - createCpRestoreMemOp(false /*IsLoad*/, CpRestoreOffset /*StackOffset*/, Loc, - StoreInsts); - - getTargetStreamer().emitDirectiveCpRestore(StoreInsts, CpRestoreOffset); + if (!getTargetStreamer().emitDirectiveCpRestore( + CpRestoreOffset, [&]() { return getATReg(Loc); }, Loc, STI)) + return true; Parser.Lex(); // Consume the EndOfStatement. return false; } @@ -5376,14 +7103,12 @@ bool MipsAsmParser::parseDirectiveCPSetup() { OperandMatchResultTy ResTy = parseAnyRegister(TmpReg); if (ResTy == MatchOperand_NoMatch) { reportParseError("expected register containing function address"); - Parser.eatToEndOfStatement(); return false; } MipsOperand &FuncRegOpnd = static_cast<MipsOperand &>(*TmpReg[0]); if (!FuncRegOpnd.isGPRAsmReg()) { reportParseError(FuncRegOpnd.getStartLoc(), "invalid register"); - Parser.eatToEndOfStatement(); return false; } @@ -5402,7 +7127,6 @@ bool MipsAsmParser::parseDirectiveCPSetup() { if (Parser.parseExpression(OffsetExpr) || !OffsetExpr->evaluateAsAbsolute(OffsetVal)) { reportParseError(ExprLoc, "expected save register or stack offset"); - Parser.eatToEndOfStatement(); return false; } @@ -5412,7 +7136,6 @@ bool MipsAsmParser::parseDirectiveCPSetup() { MipsOperand &SaveOpnd = static_cast<MipsOperand &>(*TmpReg[0]); if (!SaveOpnd.isGPRAsmReg()) { reportParseError(SaveOpnd.getStartLoc(), "invalid register"); - Parser.eatToEndOfStatement(); return false; } Save = SaveOpnd.getGPR32Reg(); @@ -5469,120 +7192,131 @@ bool MipsAsmParser::parseDirectiveNaN() { } bool MipsAsmParser::parseDirectiveSet() { - MCAsmParser &Parser = getParser(); - // Get the next token. - const AsmToken &Tok = Parser.getTok(); + const AsmToken &Tok = getParser().getTok(); + StringRef IdVal = Tok.getString(); + SMLoc Loc = Tok.getLoc(); - if (Tok.getString() == "noat") { + if (IdVal == "noat") return parseSetNoAtDirective(); - } else if (Tok.getString() == "at") { + if (IdVal == "at") return parseSetAtDirective(); - } else if (Tok.getString() == "arch") { + if (IdVal == "arch") return parseSetArchDirective(); - } else if (Tok.getString() == "fp") { + if (IdVal == "bopt") { + Warning(Loc, "'bopt' feature is unsupported"); + getParser().Lex(); + return false; + } + if (IdVal == "nobopt") { + // We're already running in nobopt mode, so nothing to do. + getParser().Lex(); + return false; + } + if (IdVal == "fp") return parseSetFpDirective(); - } else if (Tok.getString() == "oddspreg") { + if (IdVal == "oddspreg") return parseSetOddSPRegDirective(); - } else if (Tok.getString() == "nooddspreg") { + if (IdVal == "nooddspreg") return parseSetNoOddSPRegDirective(); - } else if (Tok.getString() == "pop") { + if (IdVal == "pop") return parseSetPopDirective(); - } else if (Tok.getString() == "push") { + if (IdVal == "push") return parseSetPushDirective(); - } else if (Tok.getString() == "reorder") { + if (IdVal == "reorder") return parseSetReorderDirective(); - } else if (Tok.getString() == "noreorder") { + if (IdVal == "noreorder") return parseSetNoReorderDirective(); - } else if (Tok.getString() == "macro") { + if (IdVal == "macro") return parseSetMacroDirective(); - } else if (Tok.getString() == "nomacro") { + if (IdVal == "nomacro") return parseSetNoMacroDirective(); - } else if (Tok.getString() == "mips16") { + if (IdVal == "mips16") return parseSetMips16Directive(); - } else if (Tok.getString() == "nomips16") { + if (IdVal == "nomips16") return parseSetNoMips16Directive(); - } else if (Tok.getString() == "nomicromips") { + if (IdVal == "nomicromips") { + clearFeatureBits(Mips::FeatureMicroMips, "micromips"); getTargetStreamer().emitDirectiveSetNoMicroMips(); - Parser.eatToEndOfStatement(); + getParser().eatToEndOfStatement(); return false; - } else if (Tok.getString() == "micromips") { + } + if (IdVal == "micromips") { + if (hasMips64r6()) { + Error(Loc, ".set micromips directive is not supported with MIPS64R6"); + return false; + } return parseSetFeature(Mips::FeatureMicroMips); - } else if (Tok.getString() == "mips0") { + } + if (IdVal == "mips0") return parseSetMips0Directive(); - } else if (Tok.getString() == "mips1") { + if (IdVal == "mips1") return parseSetFeature(Mips::FeatureMips1); - } else if (Tok.getString() == "mips2") { + if (IdVal == "mips2") return parseSetFeature(Mips::FeatureMips2); - } else if (Tok.getString() == "mips3") { + if (IdVal == "mips3") return parseSetFeature(Mips::FeatureMips3); - } else if (Tok.getString() == "mips4") { + if (IdVal == "mips4") return parseSetFeature(Mips::FeatureMips4); - } else if (Tok.getString() == "mips5") { + if (IdVal == "mips5") return parseSetFeature(Mips::FeatureMips5); - } else if (Tok.getString() == "mips32") { + if (IdVal == "mips32") return parseSetFeature(Mips::FeatureMips32); - } else if (Tok.getString() == "mips32r2") { + if (IdVal == "mips32r2") return parseSetFeature(Mips::FeatureMips32r2); - } else if (Tok.getString() == "mips32r3") { + if (IdVal == "mips32r3") return parseSetFeature(Mips::FeatureMips32r3); - } else if (Tok.getString() == "mips32r5") { + if (IdVal == "mips32r5") return parseSetFeature(Mips::FeatureMips32r5); - } else if (Tok.getString() == "mips32r6") { + if (IdVal == "mips32r6") return parseSetFeature(Mips::FeatureMips32r6); - } else if (Tok.getString() == "mips64") { + if (IdVal == "mips64") return parseSetFeature(Mips::FeatureMips64); - } else if (Tok.getString() == "mips64r2") { + if (IdVal == "mips64r2") return parseSetFeature(Mips::FeatureMips64r2); - } else if (Tok.getString() == "mips64r3") { + if (IdVal == "mips64r3") return parseSetFeature(Mips::FeatureMips64r3); - } else if (Tok.getString() == "mips64r5") { + if (IdVal == "mips64r5") return parseSetFeature(Mips::FeatureMips64r5); - } else if (Tok.getString() == "mips64r6") { + if (IdVal == "mips64r6") { + if (inMicroMipsMode()) { + Error(Loc, "MIPS64R6 is not supported with microMIPS"); + return false; + } return parseSetFeature(Mips::FeatureMips64r6); - } else if (Tok.getString() == "dsp") { + } + if (IdVal == "dsp") return parseSetFeature(Mips::FeatureDSP); - } else if (Tok.getString() == "nodsp") { + if (IdVal == "dspr2") + return parseSetFeature(Mips::FeatureDSPR2); + if (IdVal == "nodsp") return parseSetNoDspDirective(); - } else if (Tok.getString() == "msa") { + if (IdVal == "msa") return parseSetMsaDirective(); - } else if (Tok.getString() == "nomsa") { + if (IdVal == "nomsa") return parseSetNoMsaDirective(); - } else if (Tok.getString() == "softfloat") { + if (IdVal == "mt") + return parseSetMtDirective(); + if (IdVal == "nomt") + return parseSetNoMtDirective(); + if (IdVal == "softfloat") return parseSetSoftFloatDirective(); - } else if (Tok.getString() == "hardfloat") { + if (IdVal == "hardfloat") return parseSetHardFloatDirective(); - } else { - // It is just an identifier, look for an assignment. - parseSetAssignment(); - return false; - } - - return true; -} - -/// parseDataDirective -/// ::= .word [ expression (, expression)* ] -bool MipsAsmParser::parseDataDirective(unsigned Size, SMLoc L) { - MCAsmParser &Parser = getParser(); - if (getLexer().isNot(AsmToken::EndOfStatement)) { - for (;;) { - const MCExpr *Value; - if (getParser().parseExpression(Value)) - return true; - - getParser().getStreamer().EmitValue(Value, Size); - - if (getLexer().is(AsmToken::EndOfStatement)) - break; - - if (getLexer().isNot(AsmToken::Comma)) - return Error(L, "unexpected token, expected comma"); - Parser.Lex(); - } - } - - Parser.Lex(); - return false; + if (IdVal == "crc") + return parseSetFeature(Mips::FeatureCRC); + if (IdVal == "nocrc") + return parseSetNoCRCDirective(); + if (IdVal == "virt") + return parseSetFeature(Mips::FeatureVirt); + if (IdVal == "novirt") + return parseSetNoVirtDirective(); + if (IdVal == "ginv") + return parseSetFeature(Mips::FeatureGINV); + if (IdVal == "noginv") + return parseSetNoGINVDirective(); + + // It is just an identifier, look for an assignment. + return parseSetAssignment(); } /// parseDirectiveGpWord @@ -5597,7 +7331,7 @@ bool MipsAsmParser::parseDirectiveGpWord() { getParser().getStreamer().EmitGPRel32Value(Value); if (getLexer().isNot(AsmToken::EndOfStatement)) - return Error(getLexer().getLoc(), + return Error(getLexer().getLoc(), "unexpected token, expected end of statement"); Parser.Lex(); // Eat EndOfStatement token. return false; @@ -5615,7 +7349,79 @@ bool MipsAsmParser::parseDirectiveGpDWord() { getParser().getStreamer().EmitGPRel64Value(Value); if (getLexer().isNot(AsmToken::EndOfStatement)) - return Error(getLexer().getLoc(), + return Error(getLexer().getLoc(), + "unexpected token, expected end of statement"); + Parser.Lex(); // Eat EndOfStatement token. + return false; +} + +/// parseDirectiveDtpRelWord +/// ::= .dtprelword tls_sym +bool MipsAsmParser::parseDirectiveDtpRelWord() { + MCAsmParser &Parser = getParser(); + const MCExpr *Value; + // EmitDTPRel32Value requires an expression, so we are using base class + // method to evaluate the expression. + if (getParser().parseExpression(Value)) + return true; + getParser().getStreamer().EmitDTPRel32Value(Value); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getLoc(), + "unexpected token, expected end of statement"); + Parser.Lex(); // Eat EndOfStatement token. + return false; +} + +/// parseDirectiveDtpRelDWord +/// ::= .dtpreldword tls_sym +bool MipsAsmParser::parseDirectiveDtpRelDWord() { + MCAsmParser &Parser = getParser(); + const MCExpr *Value; + // EmitDTPRel64Value requires an expression, so we are using base class + // method to evaluate the expression. + if (getParser().parseExpression(Value)) + return true; + getParser().getStreamer().EmitDTPRel64Value(Value); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getLoc(), + "unexpected token, expected end of statement"); + Parser.Lex(); // Eat EndOfStatement token. + return false; +} + +/// parseDirectiveTpRelWord +/// ::= .tprelword tls_sym +bool MipsAsmParser::parseDirectiveTpRelWord() { + MCAsmParser &Parser = getParser(); + const MCExpr *Value; + // EmitTPRel32Value requires an expression, so we are using base class + // method to evaluate the expression. + if (getParser().parseExpression(Value)) + return true; + getParser().getStreamer().EmitTPRel32Value(Value); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getLoc(), + "unexpected token, expected end of statement"); + Parser.Lex(); // Eat EndOfStatement token. + return false; +} + +/// parseDirectiveTpRelDWord +/// ::= .tpreldword tls_sym +bool MipsAsmParser::parseDirectiveTpRelDWord() { + MCAsmParser &Parser = getParser(); + const MCExpr *Value; + // EmitTPRel64Value requires an expression, so we are using base class + // method to evaluate the expression. + if (getParser().parseExpression(Value)) + return true; + getParser().getStreamer().EmitTPRel64Value(Value); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getLoc(), "unexpected token, expected end of statement"); Parser.Lex(); // Eat EndOfStatement token. return false; @@ -5627,9 +7433,8 @@ bool MipsAsmParser::parseDirectiveOption() { AsmToken Tok = Parser.getTok(); // At the moment only identifiers are supported. if (Tok.isNot(AsmToken::Identifier)) { - Error(Parser.getTok().getLoc(), "unexpected token, expected identifier"); - Parser.eatToEndOfStatement(); - return false; + return Error(Parser.getTok().getLoc(), + "unexpected token, expected identifier"); } StringRef Option = Tok.getIdentifier(); @@ -5641,9 +7446,8 @@ bool MipsAsmParser::parseDirectiveOption() { getTargetStreamer().emitDirectiveOptionPic0(); Parser.Lex(); if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { - Error(Parser.getTok().getLoc(), - "unexpected token, expected end of statement"); - Parser.eatToEndOfStatement(); + return Error(Parser.getTok().getLoc(), + "unexpected token, expected end of statement"); } return false; } @@ -5655,15 +7459,14 @@ bool MipsAsmParser::parseDirectiveOption() { getTargetStreamer().emitDirectiveOptionPic2(); Parser.Lex(); if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { - Error(Parser.getTok().getLoc(), - "unexpected token, expected end of statement"); - Parser.eatToEndOfStatement(); + return Error(Parser.getTok().getLoc(), + "unexpected token, expected end of statement"); } return false; } // Unknown option. - Warning(Parser.getTok().getLoc(), + Warning(Parser.getTok().getLoc(), "unknown option, expected 'pic0' or 'pic2'"); Parser.eatToEndOfStatement(); return false; @@ -5686,12 +7489,54 @@ bool MipsAsmParser::parseInsnDirective() { return false; } +/// parseRSectionDirective +/// ::= .rdata +bool MipsAsmParser::parseRSectionDirective(StringRef Section) { + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + MCSection *ELFSection = getContext().getELFSection( + Section, ELF::SHT_PROGBITS, ELF::SHF_ALLOC); + getParser().getStreamer().SwitchSection(ELFSection); + + getParser().Lex(); // Eat EndOfStatement token. + return false; +} + +/// parseSSectionDirective +/// ::= .sbss +/// ::= .sdata +bool MipsAsmParser::parseSSectionDirective(StringRef Section, unsigned Type) { + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + MCSection *ELFSection = getContext().getELFSection( + Section, Type, ELF::SHF_WRITE | ELF::SHF_ALLOC | ELF::SHF_MIPS_GPREL); + getParser().getStreamer().SwitchSection(ELFSection); + + getParser().Lex(); // Eat EndOfStatement token. + return false; +} + /// parseDirectiveModule /// ::= .module oddspreg /// ::= .module nooddspreg /// ::= .module fp=value /// ::= .module softfloat /// ::= .module hardfloat +/// ::= .module mt +/// ::= .module crc +/// ::= .module nocrc +/// ::= .module virt +/// ::= .module novirt +/// ::= .module ginv +/// ::= .module noginv bool MipsAsmParser::parseDirectiveModule() { MCAsmParser &Parser = getParser(); MCAsmLexer &Lexer = getLexer(); @@ -5730,8 +7575,7 @@ bool MipsAsmParser::parseDirectiveModule() { return false; // parseDirectiveModule has finished successfully. } else if (Option == "nooddspreg") { if (!isABI_O32()) { - Error(L, "'.module nooddspreg' requires the O32 ABI"); - return false; + return Error(L, "'.module nooddspreg' requires the O32 ABI"); } setModuleFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg"); @@ -5792,6 +7636,139 @@ bool MipsAsmParser::parseDirectiveModule() { } return false; // parseDirectiveModule has finished successfully. + } else if (Option == "mt") { + setModuleFeatureBits(Mips::FeatureMT, "mt"); + + // Synchronize the ABI Flags information with the FeatureBits information we + // updated above. + getTargetStreamer().updateABIInfo(*this); + + // If printing assembly, use the recently updated ABI Flags information. + // If generating ELF, don't do anything (the .MIPS.abiflags section gets + // emitted later). + getTargetStreamer().emitDirectiveModuleMT(); + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + return false; // parseDirectiveModule has finished successfully. + } else if (Option == "crc") { + setModuleFeatureBits(Mips::FeatureCRC, "crc"); + + // Synchronize the ABI Flags information with the FeatureBits information we + // updated above. + getTargetStreamer().updateABIInfo(*this); + + // If printing assembly, use the recently updated ABI Flags information. + // If generating ELF, don't do anything (the .MIPS.abiflags section gets + // emitted later). + getTargetStreamer().emitDirectiveModuleCRC(); + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + return false; // parseDirectiveModule has finished successfully. + } else if (Option == "nocrc") { + clearModuleFeatureBits(Mips::FeatureCRC, "crc"); + + // Synchronize the ABI Flags information with the FeatureBits information we + // updated above. + getTargetStreamer().updateABIInfo(*this); + + // If printing assembly, use the recently updated ABI Flags information. + // If generating ELF, don't do anything (the .MIPS.abiflags section gets + // emitted later). + getTargetStreamer().emitDirectiveModuleNoCRC(); + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + return false; // parseDirectiveModule has finished successfully. + } else if (Option == "virt") { + setModuleFeatureBits(Mips::FeatureVirt, "virt"); + + // Synchronize the ABI Flags information with the FeatureBits information we + // updated above. + getTargetStreamer().updateABIInfo(*this); + + // If printing assembly, use the recently updated ABI Flags information. + // If generating ELF, don't do anything (the .MIPS.abiflags section gets + // emitted later). + getTargetStreamer().emitDirectiveModuleVirt(); + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + return false; // parseDirectiveModule has finished successfully. + } else if (Option == "novirt") { + clearModuleFeatureBits(Mips::FeatureVirt, "virt"); + + // Synchronize the ABI Flags information with the FeatureBits information we + // updated above. + getTargetStreamer().updateABIInfo(*this); + + // If printing assembly, use the recently updated ABI Flags information. + // If generating ELF, don't do anything (the .MIPS.abiflags section gets + // emitted later). + getTargetStreamer().emitDirectiveModuleNoVirt(); + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + return false; // parseDirectiveModule has finished successfully. + } else if (Option == "ginv") { + setModuleFeatureBits(Mips::FeatureGINV, "ginv"); + + // Synchronize the ABI Flags information with the FeatureBits information we + // updated above. + getTargetStreamer().updateABIInfo(*this); + + // If printing assembly, use the recently updated ABI Flags information. + // If generating ELF, don't do anything (the .MIPS.abiflags section gets + // emitted later). + getTargetStreamer().emitDirectiveModuleGINV(); + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + return false; // parseDirectiveModule has finished successfully. + } else if (Option == "noginv") { + clearModuleFeatureBits(Mips::FeatureGINV, "ginv"); + + // Synchronize the ABI Flags information with the FeatureBits information we + // updated above. + getTargetStreamer().updateABIInfo(*this); + + // If printing assembly, use the recently updated ABI Flags information. + // If generating ELF, don't do anything (the .MIPS.abiflags section gets + // emitted later). + getTargetStreamer().emitDirectiveModuleNoGINV(); + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + return false; // parseDirectiveModule has finished successfully. } else { return Error(L, "'" + Twine(Option) + "' is not a valid .module option."); } @@ -5905,15 +7882,20 @@ bool MipsAsmParser::parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI, } bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { + // This returns false if this function recognizes the directive + // regardless of whether it is successfully handles or reports an + // error. Otherwise it returns true to give the generic parser a + // chance at recognizing it. + MCAsmParser &Parser = getParser(); StringRef IDVal = DirectiveID.getString(); - if (IDVal == ".cpload") - return parseDirectiveCpLoad(DirectiveID.getLoc()); - if (IDVal == ".cprestore") - return parseDirectiveCpRestore(DirectiveID.getLoc()); - if (IDVal == ".dword") { - parseDataDirective(8, DirectiveID.getLoc()); + if (IDVal == ".cpload") { + parseDirectiveCpLoad(DirectiveID.getLoc()); + return false; + } + if (IDVal == ".cprestore") { + parseDirectiveCpRestore(DirectiveID.getLoc()); return false; } if (IDVal == ".ent") { @@ -6068,7 +8050,8 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { } if (IDVal == ".set") { - return parseDirectiveSet(); + parseDirectiveSet(); + return false; } if (IDVal == ".mask" || IDVal == ".fmask") { @@ -6142,39 +8125,72 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { return false; } - if (IDVal == ".word") { - parseDataDirective(4, DirectiveID.getLoc()); + if (IDVal == ".dtprelword") { + parseDirectiveDtpRelWord(); + return false; + } + + if (IDVal == ".dtpreldword") { + parseDirectiveDtpRelDWord(); return false; } - if (IDVal == ".option") - return parseDirectiveOption(); + if (IDVal == ".tprelword") { + parseDirectiveTpRelWord(); + return false; + } + + if (IDVal == ".tpreldword") { + parseDirectiveTpRelDWord(); + return false; + } + + if (IDVal == ".option") { + parseDirectiveOption(); + return false; + } if (IDVal == ".abicalls") { getTargetStreamer().emitDirectiveAbiCalls(); if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { - Error(Parser.getTok().getLoc(), + Error(Parser.getTok().getLoc(), "unexpected token, expected end of statement"); - // Clear line - Parser.eatToEndOfStatement(); } return false; } - if (IDVal == ".cpsetup") - return parseDirectiveCPSetup(); - - if (IDVal == ".cpreturn") - return parseDirectiveCPReturn(); - - if (IDVal == ".module") - return parseDirectiveModule(); - - if (IDVal == ".llvm_internal_mips_reallow_module_directive") - return parseInternalDirectiveReallowModule(); - - if (IDVal == ".insn") - return parseInsnDirective(); + if (IDVal == ".cpsetup") { + parseDirectiveCPSetup(); + return false; + } + if (IDVal == ".cpreturn") { + parseDirectiveCPReturn(); + return false; + } + if (IDVal == ".module") { + parseDirectiveModule(); + return false; + } + if (IDVal == ".llvm_internal_mips_reallow_module_directive") { + parseInternalDirectiveReallowModule(); + return false; + } + if (IDVal == ".insn") { + parseInsnDirective(); + return false; + } + if (IDVal == ".rdata") { + parseRSectionDirective(".rodata"); + return false; + } + if (IDVal == ".sbss") { + parseSSectionDirective(IDVal, ELF::SHT_NOBITS); + return false; + } + if (IDVal == ".sdata") { + parseSSectionDirective(IDVal, ELF::SHT_PROGBITS); + return false; + } return true; } @@ -6193,12 +8209,25 @@ bool MipsAsmParser::parseInternalDirectiveReallowModule() { } extern "C" void LLVMInitializeMipsAsmParser() { - RegisterMCAsmParser<MipsAsmParser> X(TheMipsTarget); - RegisterMCAsmParser<MipsAsmParser> Y(TheMipselTarget); - RegisterMCAsmParser<MipsAsmParser> A(TheMips64Target); - RegisterMCAsmParser<MipsAsmParser> B(TheMips64elTarget); + RegisterMCAsmParser<MipsAsmParser> X(getTheMipsTarget()); + RegisterMCAsmParser<MipsAsmParser> Y(getTheMipselTarget()); + RegisterMCAsmParser<MipsAsmParser> A(getTheMips64Target()); + RegisterMCAsmParser<MipsAsmParser> B(getTheMips64elTarget()); } #define GET_REGISTER_MATCHER #define GET_MATCHER_IMPLEMENTATION +#define GET_MNEMONIC_SPELL_CHECKER #include "MipsGenAsmMatcher.inc" + +bool MipsAsmParser::mnemonicIsValid(StringRef Mnemonic, unsigned VariantID) { + // Find the appropriate table for this asm variant. + const MatchEntry *Start, *End; + switch (VariantID) { + default: llvm_unreachable("invalid variant!"); + case 0: Start = std::begin(MatchTable0); End = std::end(MatchTable0); break; + } + // Search the table. + auto MnemonicRange = std::equal_range(Start, End, Mnemonic, LessOpcode()); + return MnemonicRange.first != MnemonicRange.second; +} |