diff options
Diffstat (limited to 'contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp')
-rw-r--r-- | contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp | 1303 |
1 files changed, 908 insertions, 395 deletions
diff --git a/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index 699dfae..9c054e5 100644 --- a/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "MCTargetDesc/MipsABIInfo.h" #include "MCTargetDesc/MipsMCExpr.h" #include "MCTargetDesc/MipsMCTargetDesc.h" #include "MipsRegisterInfo.h" @@ -28,6 +29,7 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" #include <memory> using namespace llvm; @@ -41,18 +43,24 @@ class MCInstrInfo; namespace { class MipsAssemblerOptions { public: - MipsAssemblerOptions(uint64_t Features_) : + MipsAssemblerOptions(const FeatureBitset &Features_) : ATReg(1), Reorder(true), Macro(true), Features(Features_) {} MipsAssemblerOptions(const MipsAssemblerOptions *Opts) { - ATReg = Opts->getATRegNum(); + ATReg = Opts->getATRegIndex(); Reorder = Opts->isReorder(); Macro = Opts->isMacro(); Features = Opts->getFeatures(); } - unsigned getATRegNum() const { return ATReg; } - bool setATReg(unsigned Reg); + unsigned getATRegIndex() const { return ATReg; } + bool setATRegIndex(unsigned Reg) { + if (Reg > 31) + return false; + + ATReg = Reg; + return true; + } bool isReorder() const { return Reorder; } void setReorder() { Reorder = true; } @@ -62,31 +70,35 @@ public: void setMacro() { Macro = true; } void setNoMacro() { Macro = false; } - uint64_t getFeatures() const { return Features; } - void setFeatures(uint64_t Features_) { Features = Features_; } + const FeatureBitset &getFeatures() const { return Features; } + void setFeatures(const FeatureBitset &Features_) { Features = Features_; } // Set of features that are either architecture features or referenced // by them (e.g.: FeatureNaN2008 implied by FeatureMips32r6). // The full table can be found in MipsGenSubtargetInfo.inc (MipsFeatureKV[]). // The reason we need this mask is explained in the selectArch function. // FIXME: Ideally we would like TableGen to generate this information. - static const uint64_t AllArchRelatedMask = - Mips::FeatureMips1 | Mips::FeatureMips2 | Mips::FeatureMips3 | - Mips::FeatureMips3_32 | Mips::FeatureMips3_32r2 | Mips::FeatureMips4 | - Mips::FeatureMips4_32 | Mips::FeatureMips4_32r2 | Mips::FeatureMips5 | - Mips::FeatureMips5_32r2 | Mips::FeatureMips32 | Mips::FeatureMips32r2 | - Mips::FeatureMips32r6 | Mips::FeatureMips64 | Mips::FeatureMips64r2 | - Mips::FeatureMips64r6 | Mips::FeatureCnMips | Mips::FeatureFP64Bit | - Mips::FeatureGP64Bit | Mips::FeatureNaN2008; + static const FeatureBitset AllArchRelatedMask; private: unsigned ATReg; bool Reorder; bool Macro; - uint64_t Features; + FeatureBitset Features; }; } +const FeatureBitset MipsAssemblerOptions::AllArchRelatedMask = { + Mips::FeatureMips1, Mips::FeatureMips2, Mips::FeatureMips3, + Mips::FeatureMips3_32, Mips::FeatureMips3_32r2, Mips::FeatureMips4, + Mips::FeatureMips4_32, Mips::FeatureMips4_32r2, Mips::FeatureMips5, + Mips::FeatureMips5_32r2, Mips::FeatureMips32, Mips::FeatureMips32r2, + Mips::FeatureMips32r3, Mips::FeatureMips32r5, Mips::FeatureMips32r6, + Mips::FeatureMips64, Mips::FeatureMips64r2, Mips::FeatureMips64r3, + Mips::FeatureMips64r5, Mips::FeatureMips64r6, Mips::FeatureCnMips, + Mips::FeatureFP64Bit, Mips::FeatureGP64Bit, Mips::FeatureNaN2008 +}; + namespace { class MipsAsmParser : public MCTargetAsmParser { MipsTargetStreamer &getTargetStreamer() { @@ -95,6 +107,7 @@ class MipsAsmParser : public MCTargetAsmParser { } MCSubtargetInfo &STI; + MipsABIInfo ABI; SmallVector<std::unique_ptr<MipsAssemblerOptions>, 2> AssemblerOptions; MCSymbol *CurrentFn; // Pointer to the function being parsed. It may be a // nullptr, which indicates that no function is currently @@ -150,6 +163,9 @@ class MipsAsmParser : public MCTargetAsmParser { parseRegisterPair (OperandVector &Operands); MipsAsmParser::OperandMatchResultTy + parseMovePRegPair(OperandVector &Operands); + + MipsAsmParser::OperandMatchResultTy parseRegisterList (OperandVector &Operands); bool searchSymbolAlias(OperandVector &Operands); @@ -163,21 +179,41 @@ class MipsAsmParser : public MCTargetAsmParser { bool expandInstruction(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions); - bool expandLoadImm(MCInst &Inst, SMLoc IDLoc, + bool expandJalWithRegs(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + bool loadImmediate(int64_t ImmValue, unsigned DstReg, unsigned SrcReg, + bool Is32BitImm, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + bool expandLoadImm(MCInst &Inst, bool Is32BitImm, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions); - bool expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc, + bool expandLoadAddressImm(MCInst &Inst, bool Is32BitImm, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions); - bool expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc, + bool expandLoadAddressReg(MCInst &Inst, bool Is32BitImm, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions); + bool expandUncondBranchMMPseudo(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); - void expandLoadAddressSym(MCInst &Inst, SMLoc IDLoc, + void expandLoadAddressSym(const MCOperand &DstRegOp, const MCOperand &SymOp, + bool Is32BitSym, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions); void expandMemInst(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions, bool isLoad, bool isImmOpnd); + + bool expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + void createNop(bool hasShortDelaySlot, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + void createAddu(unsigned DstReg, unsigned SrcReg, unsigned TrgReg, + SmallVectorImpl<MCInst> &Instructions); + bool reportParseError(Twine ErrorMsg); bool reportParseError(SMLoc Loc, Twine ErrorMsg); @@ -195,6 +231,7 @@ class MipsAsmParser : public MCTargetAsmParser { bool parseDirectiveNaN(); bool parseDirectiveSet(); bool parseDirectiveOption(); + bool parseInsnDirective(); bool parseSetAtDirective(); bool parseSetNoAtDirective(); @@ -210,6 +247,8 @@ class MipsAsmParser : public MCTargetAsmParser { bool parseSetFpDirective(); bool parseSetPopDirective(); bool parseSetPushDirective(); + bool parseSetSoftFloatDirective(); + bool parseSetHardFloatDirective(); bool parseSetAssignment(); @@ -221,6 +260,8 @@ class MipsAsmParser : public MCTargetAsmParser { bool parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI, StringRef Directive); + bool parseInternalDirectiveReallowModule(); + MCSymbolRefExpr::VariantKind getVariantKind(StringRef Symbol); bool eatComma(StringRef ErrorStr); @@ -245,7 +286,10 @@ class MipsAsmParser : public MCTargetAsmParser { unsigned getGPR(int RegNo); - int getATReg(SMLoc Loc); + /// 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); @@ -278,28 +322,28 @@ class MipsAsmParser : public MCTargetAsmParser { // FeatureMipsGP64 | FeatureMips1) // Clearing Mips3 is equivalent to clear (FeatureMips3 | FeatureMips4). void selectArch(StringRef ArchFeature) { - uint64_t FeatureBits = STI.getFeatureBits(); + FeatureBitset FeatureBits = STI.getFeatureBits(); FeatureBits &= ~MipsAssemblerOptions::AllArchRelatedMask; STI.setFeatureBits(FeatureBits); setAvailableFeatures( ComputeAvailableFeatures(STI.ToggleFeature(ArchFeature))); - AssemblerOptions.back()->setFeatures(getAvailableFeatures()); + AssemblerOptions.back()->setFeatures(STI.getFeatureBits()); } void setFeatureBits(uint64_t Feature, StringRef FeatureString) { - if (!(STI.getFeatureBits() & Feature)) { + if (!(STI.getFeatureBits()[Feature])) { setAvailableFeatures( ComputeAvailableFeatures(STI.ToggleFeature(FeatureString))); + AssemblerOptions.back()->setFeatures(STI.getFeatureBits()); } - AssemblerOptions.back()->setFeatures(getAvailableFeatures()); } void clearFeatureBits(uint64_t Feature, StringRef FeatureString) { - if (STI.getFeatureBits() & Feature) { + if (STI.getFeatureBits()[Feature]) { setAvailableFeatures( ComputeAvailableFeatures(STI.ToggleFeature(FeatureString))); + AssemblerOptions.back()->setFeatures(STI.getFeatureBits()); } - AssemblerOptions.back()->setFeatures(getAvailableFeatures()); } public: @@ -313,28 +357,26 @@ public: MipsAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser, const MCInstrInfo &MII, const MCTargetOptions &Options) - : MCTargetAsmParser(), STI(sti) { + : MCTargetAsmParser(), STI(sti), + ABI(MipsABIInfo::computeTargetABI(Triple(sti.getTargetTriple()), + sti.getCPU(), Options)) { MCAsmParserExtension::Initialize(parser); + parser.addAliasForDirective(".asciiz", ".asciz"); + // Initialize the set of available features. setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); // Remember the initial assembler options. The user can not modify these. AssemblerOptions.push_back( - make_unique<MipsAssemblerOptions>(getAvailableFeatures())); + llvm::make_unique<MipsAssemblerOptions>(STI.getFeatureBits())); // Create an assembler options environment for the user to modify. AssemblerOptions.push_back( - make_unique<MipsAssemblerOptions>(getAvailableFeatures())); + llvm::make_unique<MipsAssemblerOptions>(STI.getFeatureBits())); getTargetStreamer().updateABIInfo(*this); - // Assert exactly one ABI was chosen. - assert((((STI.getFeatureBits() & Mips::FeatureO32) != 0) + - ((STI.getFeatureBits() & Mips::FeatureEABI) != 0) + - ((STI.getFeatureBits() & Mips::FeatureN32) != 0) + - ((STI.getFeatureBits() & Mips::FeatureN64) != 0)) == 1); - if (!isABI_O32() && !useOddSPReg() != 0) report_fatal_error("-mno-odd-spreg requires the O32 ABI"); @@ -344,55 +386,76 @@ public: /// True if all of $fcc0 - $fcc7 exist for the current ISA. bool hasEightFccRegisters() const { return hasMips4() || hasMips32(); } - bool isGP64bit() const { return STI.getFeatureBits() & Mips::FeatureGP64Bit; } - bool isFP64bit() const { return STI.getFeatureBits() & Mips::FeatureFP64Bit; } - bool isABI_N32() const { return STI.getFeatureBits() & Mips::FeatureN32; } - bool isABI_N64() const { return STI.getFeatureBits() & Mips::FeatureN64; } - bool isABI_O32() const { return STI.getFeatureBits() & Mips::FeatureO32; } - bool isABI_FPXX() const { return STI.getFeatureBits() & Mips::FeatureFPXX; } + bool isGP64bit() const { return STI.getFeatureBits()[Mips::FeatureGP64Bit]; } + bool isFP64bit() const { return STI.getFeatureBits()[Mips::FeatureFP64Bit]; } + const MipsABIInfo &getABI() const { return ABI; } + bool isABI_N32() const { return ABI.IsN32(); } + bool isABI_N64() const { return ABI.IsN64(); } + bool isABI_O32() const { return ABI.IsO32(); } + bool isABI_FPXX() const { return STI.getFeatureBits()[Mips::FeatureFPXX]; } bool useOddSPReg() const { - return !(STI.getFeatureBits() & Mips::FeatureNoOddSPReg); + return !(STI.getFeatureBits()[Mips::FeatureNoOddSPReg]); } bool inMicroMipsMode() const { - return STI.getFeatureBits() & Mips::FeatureMicroMips; + return STI.getFeatureBits()[Mips::FeatureMicroMips]; } - bool hasMips1() const { return STI.getFeatureBits() & Mips::FeatureMips1; } - bool hasMips2() const { return STI.getFeatureBits() & Mips::FeatureMips2; } - bool hasMips3() const { return STI.getFeatureBits() & Mips::FeatureMips3; } - bool hasMips4() const { return STI.getFeatureBits() & Mips::FeatureMips4; } - bool hasMips5() const { return STI.getFeatureBits() & Mips::FeatureMips5; } + bool hasMips1() const { return STI.getFeatureBits()[Mips::FeatureMips1]; } + bool hasMips2() const { return STI.getFeatureBits()[Mips::FeatureMips2]; } + bool hasMips3() const { return STI.getFeatureBits()[Mips::FeatureMips3]; } + bool hasMips4() const { return STI.getFeatureBits()[Mips::FeatureMips4]; } + bool hasMips5() const { return STI.getFeatureBits()[Mips::FeatureMips5]; } bool hasMips32() const { - return (STI.getFeatureBits() & Mips::FeatureMips32); + return STI.getFeatureBits()[Mips::FeatureMips32]; } bool hasMips64() const { - return (STI.getFeatureBits() & Mips::FeatureMips64); + return STI.getFeatureBits()[Mips::FeatureMips64]; } bool hasMips32r2() const { - return (STI.getFeatureBits() & Mips::FeatureMips32r2); + return STI.getFeatureBits()[Mips::FeatureMips32r2]; } bool hasMips64r2() const { - return (STI.getFeatureBits() & Mips::FeatureMips64r2); + return STI.getFeatureBits()[Mips::FeatureMips64r2]; + } + bool hasMips32r3() const { + return (STI.getFeatureBits()[Mips::FeatureMips32r3]); + } + bool hasMips64r3() const { + return (STI.getFeatureBits()[Mips::FeatureMips64r3]); + } + bool hasMips32r5() const { + return (STI.getFeatureBits()[Mips::FeatureMips32r5]); + } + bool hasMips64r5() const { + return (STI.getFeatureBits()[Mips::FeatureMips64r5]); } bool hasMips32r6() const { - return (STI.getFeatureBits() & Mips::FeatureMips32r6); + return STI.getFeatureBits()[Mips::FeatureMips32r6]; } bool hasMips64r6() const { - return (STI.getFeatureBits() & Mips::FeatureMips64r6); + return STI.getFeatureBits()[Mips::FeatureMips64r6]; + } + + bool hasDSP() const { return STI.getFeatureBits()[Mips::FeatureDSP]; } + bool hasDSPR2() const { return STI.getFeatureBits()[Mips::FeatureDSPR2]; } + bool hasMSA() const { return STI.getFeatureBits()[Mips::FeatureMSA]; } + bool hasCnMips() const { + return (STI.getFeatureBits()[Mips::FeatureCnMips]); } - bool hasDSP() const { return (STI.getFeatureBits() & Mips::FeatureDSP); } - bool hasDSPR2() const { return (STI.getFeatureBits() & Mips::FeatureDSPR2); } - bool hasMSA() const { return (STI.getFeatureBits() & Mips::FeatureMSA); } bool inMips16Mode() const { - return STI.getFeatureBits() & Mips::FeatureMips16; + return STI.getFeatureBits()[Mips::FeatureMips16]; } - // TODO: see how can we get this info. - bool abiUsesSoftFloat() const { return false; } - /// Warn if RegNo is the current assembler temporary. - void warnIfAssemblerTemporary(int RegNo, SMLoc Loc); + bool useSoftFloat() const { + return STI.getFeatureBits()[Mips::FeatureSoftFloat]; + } + + /// Warn if RegIndex is the same as the current AT. + void warnIfRegIndexIsAT(unsigned RegIndex, SMLoc Loc); + + void warnIfNoMacro(SMLoc Loc); }; } @@ -501,7 +564,7 @@ public: /// target. unsigned getGPR32Reg() const { assert(isRegIdx() && (RegIdx.Kind & RegKind_GPR) && "Invalid access!"); - AsmParser.warnIfAssemblerTemporary(RegIdx.Index, StartLoc); + AsmParser.warnIfRegIndexIsAT(RegIdx.Index, StartLoc); unsigned ClassID = Mips::GPR32RegClassID; return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); } @@ -643,11 +706,11 @@ public: void addExpr(MCInst &Inst, const MCExpr *Expr) const { // Add as immediate when possible. Null MCExpr = 0. if (!Expr) - Inst.addOperand(MCOperand::CreateImm(0)); + Inst.addOperand(MCOperand::createImm(0)); else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr)) - Inst.addOperand(MCOperand::CreateImm(CE->getValue())); + Inst.addOperand(MCOperand::createImm(CE->getValue())); else - Inst.addOperand(MCOperand::CreateExpr(Expr)); + Inst.addOperand(MCOperand::createExpr(Expr)); } void addRegOperands(MCInst &Inst, unsigned N) const { @@ -659,17 +722,22 @@ public: /// is not a k_RegisterIndex compatible with RegKind_GPR void addGPR32AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getGPR32Reg())); + Inst.addOperand(MCOperand::createReg(getGPR32Reg())); } void addGPRMM16AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getGPRMM16Reg())); + Inst.addOperand(MCOperand::createReg(getGPRMM16Reg())); } void addGPRMM16AsmRegZeroOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getGPRMM16Reg())); + Inst.addOperand(MCOperand::createReg(getGPRMM16Reg())); + } + + void addGPRMM16AsmRegMovePOperands(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 @@ -677,22 +745,22 @@ public: /// is not a k_RegisterIndex compatible with RegKind_GPR void addGPR64AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getGPR64Reg())); + Inst.addOperand(MCOperand::createReg(getGPR64Reg())); } void addAFGR64AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getAFGR64Reg())); + Inst.addOperand(MCOperand::createReg(getAFGR64Reg())); } void addFGR64AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getFGR64Reg())); + Inst.addOperand(MCOperand::createReg(getFGR64Reg())); } void addFGR32AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getFGR32Reg())); + 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 " @@ -701,57 +769,57 @@ public: void addFGRH32AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getFGRH32Reg())); + Inst.addOperand(MCOperand::createReg(getFGRH32Reg())); } void addFCCAsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getFCCReg())); + Inst.addOperand(MCOperand::createReg(getFCCReg())); } void addMSA128AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getMSA128Reg())); + Inst.addOperand(MCOperand::createReg(getMSA128Reg())); } void addMSACtrlAsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getMSACtrlReg())); + Inst.addOperand(MCOperand::createReg(getMSACtrlReg())); } void addCOP2AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getCOP2Reg())); + Inst.addOperand(MCOperand::createReg(getCOP2Reg())); } void addCOP3AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getCOP3Reg())); + Inst.addOperand(MCOperand::createReg(getCOP3Reg())); } void addACC64DSPAsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getACC64DSPReg())); + Inst.addOperand(MCOperand::createReg(getACC64DSPReg())); } void addHI32DSPAsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getHI32DSPReg())); + Inst.addOperand(MCOperand::createReg(getHI32DSPReg())); } void addLO32DSPAsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getLO32DSPReg())); + Inst.addOperand(MCOperand::createReg(getLO32DSPReg())); } void addCCRAsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getCCRReg())); + Inst.addOperand(MCOperand::createReg(getCCRReg())); } void addHWRegsAsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getHWRegsReg())); + Inst.addOperand(MCOperand::createReg(getHWRegsReg())); } void addImmOperands(MCInst &Inst, unsigned N) const { @@ -763,7 +831,7 @@ public: void addMemOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getMemBase()->getGPR32Reg())); + Inst.addOperand(MCOperand::createReg(getMemBase()->getGPR32Reg())); const MCExpr *Expr = getMemOff(); addExpr(Inst, Expr); @@ -772,7 +840,7 @@ public: void addMicroMipsMemOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getMemBase()->getGPRMM16Reg())); + Inst.addOperand(MCOperand::createReg(getMemBase()->getGPRMM16Reg())); const MCExpr *Expr = getMemOff(); addExpr(Inst, Expr); @@ -782,14 +850,20 @@ public: assert(N == 1 && "Invalid number of operands!"); for (auto RegNo : getRegList()) - Inst.addOperand(MCOperand::CreateReg(RegNo)); + 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)); + 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 { @@ -856,6 +930,25 @@ public: 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; + } StringRef getToken() const { assert(Kind == k_Token && "Invalid access!"); @@ -1009,9 +1102,7 @@ public: assert (Regs.size() > 0 && "Empty list not allowed"); auto Op = make_unique<MipsOperand>(k_RegList, Parser); - Op->RegList.List = new SmallVector<unsigned, 10>(); - for (auto Reg : Regs) - Op->RegList.List->push_back(Reg); + Op->RegList.List = new SmallVector<unsigned, 10>(Regs.begin(), Regs.end()); Op->StartLoc = StartLoc; Op->EndLoc = EndLoc; return Op; @@ -1042,6 +1133,12 @@ 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 isFGRAsmReg() const { // AFGR64 is $0-$15 but we handle this in getAFGR64() return isRegIdx() && RegIdx.Kind & RegKind_FGR && RegIdx.Index <= 31; @@ -1101,14 +1198,14 @@ public: switch (Kind) { case k_Immediate: OS << "Imm<"; - Imm.Val->print(OS); + OS << *Imm.Val; OS << ">"; break; case k_Memory: OS << "Mem<"; Mem.Base->print(OS); OS << ", "; - Mem.Off->print(OS); + OS << *Mem.Off; OS << ">"; break; case k_PhysRegister: @@ -1167,6 +1264,13 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, switch (Opcode) { default: break; + case Mips::BBIT0: + case Mips::BBIT032: + case Mips::BBIT1: + case Mips::BBIT132: + assert(hasCnMips() && "instruction only valid for octeon cpus"); + // Fall through + case Mips::BEQ: case Mips::BNE: case Mips::BEQ_MM: @@ -1229,23 +1333,72 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, "nop instruction"); } - if (MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder()) { - // If this instruction has a delay slot and .set reorder is active, - // emit a NOP after it. - Instructions.push_back(Inst); - MCInst NopInst; - if (hasShortDelaySlot(Inst.getOpcode())) { - NopInst.setOpcode(Mips::MOVE16_MM); - NopInst.addOperand(MCOperand::CreateReg(Mips::ZERO)); - NopInst.addOperand(MCOperand::CreateReg(Mips::ZERO)); - } else { - NopInst.setOpcode(Mips::SLL); - NopInst.addOperand(MCOperand::CreateReg(Mips::ZERO)); - NopInst.addOperand(MCOperand::CreateReg(Mips::ZERO)); - NopInst.addOperand(MCOperand::CreateImm(0)); + if (hasCnMips()) { + const unsigned Opcode = Inst.getOpcode(); + MCOperand Opnd; + int Imm; + + switch (Opcode) { + default: + break; + + case Mips::BBIT0: + case Mips::BBIT032: + case Mips::BBIT1: + case Mips::BBIT132: + assert(MCID.getNumOperands() == 3 && "unexpected number of operands"); + // The offset is handled above + Opnd = Inst.getOperand(1); + if (!Opnd.isImm()) + return Error(IDLoc, "expected immediate operand kind"); + Imm = Opnd.getImm(); + if (Imm < 0 || Imm > (Opcode == Mips::BBIT0 || + Opcode == Mips::BBIT1 ? 63 : 31)) + return Error(IDLoc, "immediate operand value out of range"); + if (Imm > 31) { + Inst.setOpcode(Opcode == Mips::BBIT0 ? Mips::BBIT032 + : Mips::BBIT132); + Inst.getOperand(1).setImm(Imm - 32); + } + break; + + case Mips::CINS: + case Mips::CINS32: + case Mips::EXTS: + case Mips::EXTS32: + assert(MCID.getNumOperands() == 4 && "unexpected number of operands"); + // Check length + Opnd = Inst.getOperand(3); + if (!Opnd.isImm()) + return Error(IDLoc, "expected immediate operand kind"); + Imm = Opnd.getImm(); + if (Imm < 0 || Imm > 31) + return Error(IDLoc, "immediate operand value out of range"); + // Check position + Opnd = Inst.getOperand(2); + if (!Opnd.isImm()) + return Error(IDLoc, "expected immediate operand kind"); + Imm = Opnd.getImm(); + if (Imm < 0 || Imm > (Opcode == Mips::CINS || + Opcode == Mips::EXTS ? 63 : 31)) + return Error(IDLoc, "immediate operand value out of range"); + if (Imm > 31) { + Inst.setOpcode(Opcode == Mips::CINS ? Mips::CINS32 : Mips::EXTS32); + Inst.getOperand(2).setImm(Imm - 32); + } + break; + + case Mips::SEQi: + case Mips::SNEi: + assert(MCID.getNumOperands() == 3 && "unexpected number of operands"); + Opnd = Inst.getOperand(2); + if (!Opnd.isImm()) + return Error(IDLoc, "expected immediate operand kind"); + Imm = Opnd.getImm(); + if (!isInt<10>(Imm)) + return Error(IDLoc, "immediate operand value out of range"); + break; } - Instructions.push_back(NopInst); - return false; } if (MCID.mayLoad() || MCID.mayStore()) { @@ -1282,8 +1435,38 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, } // for } // if load/store - // TODO: Handle this with the AsmOperandClass.PredicateMethod. if (inMicroMipsMode()) { + if (MCID.mayLoad()) { + // Try to create 16-bit GP relative load instruction. + for (unsigned i = 0; i < MCID.getNumOperands(); i++) { + const MCOperandInfo &OpInfo = MCID.OpInfo[i]; + if ((OpInfo.OperandType == MCOI::OPERAND_MEMORY) || + (OpInfo.OperandType == MCOI::OPERAND_UNKNOWN)) { + MCOperand &Op = Inst.getOperand(i); + if (Op.isImm()) { + int MemOffset = Op.getImm(); + MCOperand &DstReg = Inst.getOperand(0); + MCOperand &BaseReg = Inst.getOperand(1); + if (isIntN(9, MemOffset) && (MemOffset % 4 == 0) && + getContext().getRegisterInfo()->getRegClass( + Mips::GPRMM16RegClassID).contains(DstReg.getReg()) && + BaseReg.getReg() == Mips::GP) { + MCInst TmpInst; + TmpInst.setLoc(IDLoc); + TmpInst.setOpcode(Mips::LWGP_MM); + TmpInst.addOperand(MCOperand::createReg(DstReg.getReg())); + TmpInst.addOperand(MCOperand::createReg(Mips::GP)); + TmpInst.addOperand(MCOperand::createImm(MemOffset)); + Instructions.push_back(TmpInst); + return false; + } + } + } + } // for + } // if load + + // TODO: Handle this with the AsmOperandClass.PredicateMethod. + MCOperand Opnd; int Imm; @@ -1396,24 +1579,43 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, if (!isUInt<5>(Imm)) return Error(IDLoc, "immediate operand value out of range"); break; + case Mips::ADDIUPC_MM: + MCOperand Opnd = Inst.getOperand(1); + if (!Opnd.isImm()) + return Error(IDLoc, "expected immediate operand kind"); + int Imm = Opnd.getImm(); + if ((Imm % 4 != 0) || !isIntN(25, Imm)) + return Error(IDLoc, "immediate operand value out of range"); + break; } } - if (needsExpansion(Inst)) - return expandInstruction(Inst, IDLoc, Instructions); - else + if (needsExpansion(Inst)) { + if (expandInstruction(Inst, IDLoc, Instructions)) + return true; + } else Instructions.push_back(Inst); + // 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); + return false; } bool MipsAsmParser::needsExpansion(MCInst &Inst) { switch (Inst.getOpcode()) { - case Mips::LoadImm32Reg: - case Mips::LoadAddr32Imm: - case Mips::LoadAddr32Reg: - case Mips::LoadImm64Reg: + case Mips::LoadImm32: + case Mips::LoadImm64: + case Mips::LoadAddrImm32: + case Mips::LoadAddrReg32: + case Mips::B_MM_Pseudo: + case Mips::LWM_MM: + case Mips::SWM_MM: + case Mips::JalOneReg: + case Mips::JalTwoReg: return true; default: return false; @@ -1424,264 +1626,334 @@ bool MipsAsmParser::expandInstruction(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { switch (Inst.getOpcode()) { default: llvm_unreachable("unimplemented expansion"); - case Mips::LoadImm32Reg: - return expandLoadImm(Inst, IDLoc, Instructions); - case Mips::LoadImm64Reg: - if (!isGP64bit()) { - Error(IDLoc, "instruction requires a 64-bit architecture"); - return true; - } - return expandLoadImm(Inst, IDLoc, Instructions); - case Mips::LoadAddr32Imm: - return expandLoadAddressImm(Inst, IDLoc, Instructions); - case Mips::LoadAddr32Reg: - return expandLoadAddressReg(Inst, IDLoc, Instructions); + case Mips::LoadImm32: + return expandLoadImm(Inst, true, IDLoc, Instructions); + case Mips::LoadImm64: + return expandLoadImm(Inst, false, IDLoc, Instructions); + case Mips::LoadAddrImm32: + return expandLoadAddressImm(Inst, true, IDLoc, Instructions); + case Mips::LoadAddrReg32: + return expandLoadAddressReg(Inst, true, IDLoc, Instructions); + case Mips::B_MM_Pseudo: + return expandUncondBranchMMPseudo(Inst, IDLoc, Instructions); + case Mips::SWM_MM: + case Mips::LWM_MM: + return expandLoadStoreMultiple(Inst, IDLoc, Instructions); + case Mips::JalOneReg: + case Mips::JalTwoReg: + return expandJalWithRegs(Inst, IDLoc, Instructions); } } namespace { -template <bool PerformShift> -void createShiftOr(MCOperand Operand, unsigned RegNo, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { +template <unsigned ShiftAmount> +void createLShiftOri(MCOperand Operand, unsigned RegNo, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { MCInst tmpInst; - if (PerformShift) { + if (ShiftAmount >= 32) { + tmpInst.setOpcode(Mips::DSLL32); + tmpInst.addOperand(MCOperand::createReg(RegNo)); + tmpInst.addOperand(MCOperand::createReg(RegNo)); + tmpInst.addOperand(MCOperand::createImm(ShiftAmount - 32)); + tmpInst.setLoc(IDLoc); + Instructions.push_back(tmpInst); + tmpInst.clear(); + } else if (ShiftAmount > 0) { tmpInst.setOpcode(Mips::DSLL); - tmpInst.addOperand(MCOperand::CreateReg(RegNo)); - tmpInst.addOperand(MCOperand::CreateReg(RegNo)); - tmpInst.addOperand(MCOperand::CreateImm(16)); + tmpInst.addOperand(MCOperand::createReg(RegNo)); + tmpInst.addOperand(MCOperand::createReg(RegNo)); + tmpInst.addOperand(MCOperand::createImm(ShiftAmount)); tmpInst.setLoc(IDLoc); Instructions.push_back(tmpInst); tmpInst.clear(); } + // There's no need for an ORi if the immediate is 0. + if (Operand.isImm() && Operand.getImm() == 0) + return; + tmpInst.setOpcode(Mips::ORi); - tmpInst.addOperand(MCOperand::CreateReg(RegNo)); - tmpInst.addOperand(MCOperand::CreateReg(RegNo)); + tmpInst.addOperand(MCOperand::createReg(RegNo)); + tmpInst.addOperand(MCOperand::createReg(RegNo)); tmpInst.addOperand(Operand); tmpInst.setLoc(IDLoc); Instructions.push_back(tmpInst); } -template <int Shift, bool PerformShift> -void createShiftOr(int64_t Value, unsigned RegNo, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { - createShiftOr<PerformShift>( - MCOperand::CreateImm(((Value & (0xffffLL << Shift)) >> Shift)), RegNo, - IDLoc, Instructions); +template <unsigned ShiftAmount> +void createLShiftOri(int64_t Value, unsigned RegNo, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + createLShiftOri<ShiftAmount>(MCOperand::createImm(Value), RegNo, IDLoc, + Instructions); } } -bool MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc, +bool MipsAsmParser::expandJalWithRegs(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + // Create a JALR instruction which is going to replace the pseudo-JAL. + MCInst JalrInst; + JalrInst.setLoc(IDLoc); + const MCOperand FirstRegOp = Inst.getOperand(0); + const unsigned Opcode = Inst.getOpcode(); + + if (Opcode == Mips::JalOneReg) { + // jal $rs => jalr $rs + if (inMicroMipsMode()) { + JalrInst.setOpcode(Mips::JALR16_MM); + JalrInst.addOperand(FirstRegOp); + } else { + JalrInst.setOpcode(Mips::JALR); + JalrInst.addOperand(MCOperand::createReg(Mips::RA)); + JalrInst.addOperand(FirstRegOp); + } + } else if (Opcode == Mips::JalTwoReg) { + // jal $rd, $rs => jalr $rd, $rs + JalrInst.setOpcode(inMicroMipsMode() ? Mips::JALR_MM : Mips::JALR); + JalrInst.addOperand(FirstRegOp); + const MCOperand SecondRegOp = Inst.getOperand(1); + JalrInst.addOperand(SecondRegOp); + } + Instructions.push_back(JalrInst); + + // If .set reorder is active, emit a NOP after it. + if (AssemblerOptions.back()->isReorder()) { + // This is a 32-bit NOP because these 2 pseudo-instructions + // do not have a short delay slot. + MCInst NopInst; + NopInst.setOpcode(Mips::SLL); + NopInst.addOperand(MCOperand::createReg(Mips::ZERO)); + NopInst.addOperand(MCOperand::createReg(Mips::ZERO)); + NopInst.addOperand(MCOperand::createImm(0)); + Instructions.push_back(NopInst); + } + + return false; +} + +bool MipsAsmParser::loadImmediate(int64_t ImmValue, unsigned DstReg, + unsigned SrcReg, bool Is32BitImm, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { + if (!Is32BitImm && !isGP64bit()) { + Error(IDLoc, "instruction requires a 64-bit architecture"); + return true; + } + + bool UseSrcReg = false; + if (SrcReg != Mips::NoRegister) + UseSrcReg = true; + MCInst tmpInst; - const MCOperand &ImmOp = Inst.getOperand(1); - assert(ImmOp.isImm() && "expected immediate operand kind"); - const MCOperand &RegOp = Inst.getOperand(0); - assert(RegOp.isReg() && "expected register operand kind"); - int64_t ImmValue = ImmOp.getImm(); tmpInst.setLoc(IDLoc); // FIXME: gas has a special case for values that are 000...1111, which // becomes a li -1 and then a dsrl if (0 <= ImmValue && ImmValue <= 65535) { - // For 0 <= j <= 65535. + // For unsigned and positive signed 16-bit values (0 <= j <= 65535): // li d,j => ori d,$zero,j + if (!UseSrcReg) + SrcReg = isGP64bit() ? Mips::ZERO_64 : Mips::ZERO; tmpInst.setOpcode(Mips::ORi); - tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); - tmpInst.addOperand(MCOperand::CreateReg(Mips::ZERO)); - tmpInst.addOperand(MCOperand::CreateImm(ImmValue)); + tmpInst.addOperand(MCOperand::createReg(DstReg)); + tmpInst.addOperand(MCOperand::createReg(SrcReg)); + tmpInst.addOperand(MCOperand::createImm(ImmValue)); Instructions.push_back(tmpInst); } else if (ImmValue < 0 && ImmValue >= -32768) { - // For -32768 <= j < 0. + // For negative signed 16-bit values (-32768 <= j < 0): // li d,j => addiu d,$zero,j + if (!UseSrcReg) + SrcReg = Mips::ZERO; tmpInst.setOpcode(Mips::ADDiu); - tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); - tmpInst.addOperand(MCOperand::CreateReg(Mips::ZERO)); - tmpInst.addOperand(MCOperand::CreateImm(ImmValue)); + tmpInst.addOperand(MCOperand::createReg(DstReg)); + tmpInst.addOperand(MCOperand::createReg(SrcReg)); + tmpInst.addOperand(MCOperand::createImm(ImmValue)); Instructions.push_back(tmpInst); - } else if ((ImmValue & 0xffffffff) == ImmValue) { - // For any value of j that is representable as a 32-bit integer, create - // a sequence of: + } else if (isInt<32>(ImmValue) || isUInt<32>(ImmValue)) { + warnIfNoMacro(IDLoc); + + // For all other values which are representable as a 32-bit integer: // li d,j => lui d,hi16(j) // ori d,d,lo16(j) - tmpInst.setOpcode(Mips::LUi); - tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); - tmpInst.addOperand(MCOperand::CreateImm((ImmValue & 0xffff0000) >> 16)); - Instructions.push_back(tmpInst); - createShiftOr<0, false>(ImmValue, RegOp.getReg(), IDLoc, Instructions); + uint16_t Bits31To16 = (ImmValue >> 16) & 0xffff; + uint16_t Bits15To0 = ImmValue & 0xffff; + + if (!Is32BitImm && !isInt<32>(ImmValue)) { + // For DLI, expand to an ORi instead of a LUi to avoid sign-extending the + // upper 32 bits. + tmpInst.setOpcode(Mips::ORi); + tmpInst.addOperand(MCOperand::createReg(DstReg)); + tmpInst.addOperand(MCOperand::createReg(Mips::ZERO)); + tmpInst.addOperand(MCOperand::createImm(Bits31To16)); + tmpInst.setLoc(IDLoc); + Instructions.push_back(tmpInst); + // Move the value to the upper 16 bits by doing a 16-bit left shift. + createLShiftOri<16>(0, DstReg, IDLoc, Instructions); + } else { + tmpInst.setOpcode(Mips::LUi); + tmpInst.addOperand(MCOperand::createReg(DstReg)); + tmpInst.addOperand(MCOperand::createImm(Bits31To16)); + Instructions.push_back(tmpInst); + } + createLShiftOri<0>(Bits15To0, DstReg, IDLoc, Instructions); + + if (UseSrcReg) + createAddu(DstReg, DstReg, SrcReg, Instructions); + } else if ((ImmValue & (0xffffLL << 48)) == 0) { - if (!isGP64bit()) { - Error(IDLoc, "instruction requires a 64-bit architecture"); + if (Is32BitImm) { + Error(IDLoc, "instruction requires a 32-bit immediate"); return true; } + warnIfNoMacro(IDLoc); // <------- lo32 ------> // <------- hi32 ------> // <- hi16 -> <- lo16 -> // _________________________________ // | | | | - // | 16-bytes | 16-bytes | 16-bytes | + // | 16-bits | 16-bits | 16-bits | // |__________|__________|__________| // - // For any value of j that is representable as a 48-bit integer, create - // a sequence of: + // For any 64-bit value that is representable as a 48-bit integer: // li d,j => lui d,hi16(j) // ori d,d,hi16(lo32(j)) // dsll d,d,16 // ori d,d,lo16(lo32(j)) + uint16_t Bits47To32 = (ImmValue >> 32) & 0xffff; + uint16_t Bits31To16 = (ImmValue >> 16) & 0xffff; + uint16_t Bits15To0 = ImmValue & 0xffff; + tmpInst.setOpcode(Mips::LUi); - tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); - tmpInst.addOperand( - MCOperand::CreateImm((ImmValue & (0xffffLL << 32)) >> 32)); + tmpInst.addOperand(MCOperand::createReg(DstReg)); + tmpInst.addOperand(MCOperand::createImm(Bits47To32)); Instructions.push_back(tmpInst); - createShiftOr<16, false>(ImmValue, RegOp.getReg(), IDLoc, Instructions); - createShiftOr<0, true>(ImmValue, RegOp.getReg(), IDLoc, Instructions); + createLShiftOri<0>(Bits31To16, DstReg, IDLoc, Instructions); + createLShiftOri<16>(Bits15To0, DstReg, IDLoc, Instructions); + + if (UseSrcReg) + createAddu(DstReg, DstReg, SrcReg, Instructions); + } else { - if (!isGP64bit()) { - Error(IDLoc, "instruction requires a 64-bit architecture"); + if (Is32BitImm) { + Error(IDLoc, "instruction requires a 32-bit immediate"); return true; } + warnIfNoMacro(IDLoc); // <------- hi32 ------> <------- lo32 ------> // <- hi16 -> <- lo16 -> // ___________________________________________ // | | | | | - // | 16-bytes | 16-bytes | 16-bytes | 16-bytes | + // | 16-bits | 16-bits | 16-bits | 16-bits | // |__________|__________|__________|__________| // - // For any value of j that isn't representable as a 48-bit integer. + // For all other values which are representable as a 64-bit integer: // li d,j => lui d,hi16(j) // ori d,d,lo16(hi32(j)) // dsll d,d,16 // ori d,d,hi16(lo32(j)) // dsll d,d,16 // ori d,d,lo16(lo32(j)) + uint16_t Bits63To48 = (ImmValue >> 48) & 0xffff; + uint16_t Bits47To32 = (ImmValue >> 32) & 0xffff; + uint16_t Bits31To16 = (ImmValue >> 16) & 0xffff; + uint16_t Bits15To0 = ImmValue & 0xffff; + tmpInst.setOpcode(Mips::LUi); - tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); - tmpInst.addOperand( - MCOperand::CreateImm((ImmValue & (0xffffLL << 48)) >> 48)); + tmpInst.addOperand(MCOperand::createReg(DstReg)); + tmpInst.addOperand(MCOperand::createImm(Bits63To48)); Instructions.push_back(tmpInst); - createShiftOr<32, false>(ImmValue, RegOp.getReg(), IDLoc, Instructions); - createShiftOr<16, true>(ImmValue, RegOp.getReg(), IDLoc, Instructions); - createShiftOr<0, true>(ImmValue, RegOp.getReg(), IDLoc, Instructions); + createLShiftOri<0>(Bits47To32, DstReg, IDLoc, Instructions); + + // When Bits31To16 is 0, do a left shift of 32 bits instead of doing + // two left shifts of 16 bits. + if (Bits31To16 == 0) { + createLShiftOri<32>(Bits15To0, DstReg, IDLoc, Instructions); + } else { + createLShiftOri<16>(Bits31To16, DstReg, IDLoc, Instructions); + createLShiftOri<16>(Bits15To0, DstReg, IDLoc, Instructions); + } + + if (UseSrcReg) + createAddu(DstReg, DstReg, SrcReg, Instructions); } return false; } +bool MipsAsmParser::expandLoadImm(MCInst &Inst, bool Is32BitImm, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + 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, IDLoc, Instructions)) + return true; + + return false; +} + bool -MipsAsmParser::expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc, +MipsAsmParser::expandLoadAddressReg(MCInst &Inst, bool Is32BitImm, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { - MCInst tmpInst; + const MCOperand &DstRegOp = Inst.getOperand(0); + assert(DstRegOp.isReg() && "expected register operand kind"); + const MCOperand &ImmOp = Inst.getOperand(2); assert((ImmOp.isImm() || ImmOp.isExpr()) && "expected immediate operand kind"); if (!ImmOp.isImm()) { - expandLoadAddressSym(Inst, IDLoc, Instructions); + expandLoadAddressSym(DstRegOp, ImmOp, Is32BitImm, IDLoc, Instructions); return false; } const MCOperand &SrcRegOp = Inst.getOperand(1); assert(SrcRegOp.isReg() && "expected register operand kind"); - const MCOperand &DstRegOp = Inst.getOperand(0); - assert(DstRegOp.isReg() && "expected register operand kind"); - int ImmValue = ImmOp.getImm(); - if (-32768 <= ImmValue && ImmValue <= 65535) { - // For -32768 <= j <= 65535. - // la d,j(s) => addiu d,s,j - tmpInst.setOpcode(Mips::ADDiu); - tmpInst.addOperand(MCOperand::CreateReg(DstRegOp.getReg())); - tmpInst.addOperand(MCOperand::CreateReg(SrcRegOp.getReg())); - tmpInst.addOperand(MCOperand::CreateImm(ImmValue)); - Instructions.push_back(tmpInst); - } else { - // For any other value of j that is representable as a 32-bit integer. - // la d,j(s) => lui d,hi16(j) - // ori d,d,lo16(j) - // addu d,d,s - tmpInst.setOpcode(Mips::LUi); - tmpInst.addOperand(MCOperand::CreateReg(DstRegOp.getReg())); - tmpInst.addOperand(MCOperand::CreateImm((ImmValue & 0xffff0000) >> 16)); - Instructions.push_back(tmpInst); - tmpInst.clear(); - tmpInst.setOpcode(Mips::ORi); - tmpInst.addOperand(MCOperand::CreateReg(DstRegOp.getReg())); - tmpInst.addOperand(MCOperand::CreateReg(DstRegOp.getReg())); - tmpInst.addOperand(MCOperand::CreateImm(ImmValue & 0xffff)); - Instructions.push_back(tmpInst); - tmpInst.clear(); - tmpInst.setOpcode(Mips::ADDu); - tmpInst.addOperand(MCOperand::CreateReg(DstRegOp.getReg())); - tmpInst.addOperand(MCOperand::CreateReg(DstRegOp.getReg())); - tmpInst.addOperand(MCOperand::CreateReg(SrcRegOp.getReg())); - Instructions.push_back(tmpInst); - } + + if (loadImmediate(ImmOp.getImm(), DstRegOp.getReg(), SrcRegOp.getReg(), + Is32BitImm, IDLoc, Instructions)) + return true; + return false; } bool -MipsAsmParser::expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc, +MipsAsmParser::expandLoadAddressImm(MCInst &Inst, bool Is32BitImm, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { - MCInst tmpInst; + const MCOperand &DstRegOp = Inst.getOperand(0); + assert(DstRegOp.isReg() && "expected register operand kind"); + const MCOperand &ImmOp = Inst.getOperand(1); assert((ImmOp.isImm() || ImmOp.isExpr()) && "expected immediate operand kind"); if (!ImmOp.isImm()) { - expandLoadAddressSym(Inst, IDLoc, Instructions); + expandLoadAddressSym(DstRegOp, ImmOp, Is32BitImm, IDLoc, Instructions); return false; } - const MCOperand &RegOp = Inst.getOperand(0); - assert(RegOp.isReg() && "expected register operand kind"); - int ImmValue = ImmOp.getImm(); - if (-32768 <= ImmValue && ImmValue <= 65535) { - // For -32768 <= j <= 65535. - // la d,j => addiu d,$zero,j - tmpInst.setOpcode(Mips::ADDiu); - tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); - tmpInst.addOperand(MCOperand::CreateReg(Mips::ZERO)); - tmpInst.addOperand(MCOperand::CreateImm(ImmValue)); - Instructions.push_back(tmpInst); - } else { - // For any other value of j that is representable as a 32-bit integer. - // la d,j => lui d,hi16(j) - // ori d,d,lo16(j) - tmpInst.setOpcode(Mips::LUi); - tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); - tmpInst.addOperand(MCOperand::CreateImm((ImmValue & 0xffff0000) >> 16)); - Instructions.push_back(tmpInst); - tmpInst.clear(); - tmpInst.setOpcode(Mips::ORi); - tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); - tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); - tmpInst.addOperand(MCOperand::CreateImm(ImmValue & 0xffff)); - Instructions.push_back(tmpInst); - } + + if (loadImmediate(ImmOp.getImm(), DstRegOp.getReg(), Mips::NoRegister, + Is32BitImm, IDLoc, Instructions)) + return true; + return false; } -void -MipsAsmParser::expandLoadAddressSym(MCInst &Inst, SMLoc IDLoc, - SmallVectorImpl<MCInst> &Instructions) { - // FIXME: If we do have a valid at register to use, we should generate a - // slightly shorter sequence here. +void MipsAsmParser::expandLoadAddressSym( + const MCOperand &DstRegOp, const MCOperand &SymOp, bool Is32BitSym, + SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { + warnIfNoMacro(IDLoc); + + if (Is32BitSym && isABI_N64()) + Warning(IDLoc, "instruction loads the 32-bit address of a 64-bit symbol"); + MCInst tmpInst; - int ExprOperandNo = 1; - // Sometimes the assembly parser will get the immediate expression as - // a $zero + an immediate. - if (Inst.getNumOperands() == 3) { - assert(Inst.getOperand(1).getReg() == - (isGP64bit() ? Mips::ZERO_64 : Mips::ZERO)); - ExprOperandNo = 2; - } - const MCOperand &SymOp = Inst.getOperand(ExprOperandNo); - assert(SymOp.isExpr() && "expected symbol operand kind"); - const MCOperand &RegOp = Inst.getOperand(0); - unsigned RegNo = RegOp.getReg(); + unsigned RegNo = DstRegOp.getReg(); const MCSymbolRefExpr *Symbol = cast<MCSymbolRefExpr>(SymOp.getExpr()); const MCSymbolRefExpr *HiExpr = - MCSymbolRefExpr::Create(Symbol->getSymbol().getName(), + MCSymbolRefExpr::create(Symbol->getSymbol().getName(), MCSymbolRefExpr::VK_Mips_ABS_HI, getContext()); const MCSymbolRefExpr *LoExpr = - MCSymbolRefExpr::Create(Symbol->getSymbol().getName(), + MCSymbolRefExpr::create(Symbol->getSymbol().getName(), MCSymbolRefExpr::VK_Mips_ABS_LO, getContext()); - if (isGP64bit()) { + if (!Is32BitSym) { // If it's a 64-bit architecture, expand to: // la d,sym => lui d,highest(sym) // ori d,d,higher(sym) @@ -1690,37 +1962,76 @@ MipsAsmParser::expandLoadAddressSym(MCInst &Inst, SMLoc IDLoc, // dsll d,d,16 // ori d,d,lo16(sym) const MCSymbolRefExpr *HighestExpr = - MCSymbolRefExpr::Create(Symbol->getSymbol().getName(), + MCSymbolRefExpr::create(Symbol->getSymbol().getName(), MCSymbolRefExpr::VK_Mips_HIGHEST, getContext()); const MCSymbolRefExpr *HigherExpr = - MCSymbolRefExpr::Create(Symbol->getSymbol().getName(), + MCSymbolRefExpr::create(Symbol->getSymbol().getName(), MCSymbolRefExpr::VK_Mips_HIGHER, getContext()); tmpInst.setOpcode(Mips::LUi); - tmpInst.addOperand(MCOperand::CreateReg(RegNo)); - tmpInst.addOperand(MCOperand::CreateExpr(HighestExpr)); + tmpInst.addOperand(MCOperand::createReg(RegNo)); + tmpInst.addOperand(MCOperand::createExpr(HighestExpr)); Instructions.push_back(tmpInst); - createShiftOr<false>(MCOperand::CreateExpr(HigherExpr), RegNo, SMLoc(), - Instructions); - createShiftOr<true>(MCOperand::CreateExpr(HiExpr), RegNo, SMLoc(), + createLShiftOri<0>(MCOperand::createExpr(HigherExpr), RegNo, SMLoc(), + Instructions); + createLShiftOri<16>(MCOperand::createExpr(HiExpr), RegNo, SMLoc(), Instructions); - createShiftOr<true>(MCOperand::CreateExpr(LoExpr), RegNo, SMLoc(), + createLShiftOri<16>(MCOperand::createExpr(LoExpr), RegNo, SMLoc(), Instructions); } else { // Otherwise, expand to: // la d,sym => lui d,hi16(sym) // ori d,d,lo16(sym) tmpInst.setOpcode(Mips::LUi); - tmpInst.addOperand(MCOperand::CreateReg(RegNo)); - tmpInst.addOperand(MCOperand::CreateExpr(HiExpr)); + tmpInst.addOperand(MCOperand::createReg(RegNo)); + tmpInst.addOperand(MCOperand::createExpr(HiExpr)); Instructions.push_back(tmpInst); - createShiftOr<false>(MCOperand::CreateExpr(LoExpr), RegNo, SMLoc(), - Instructions); + createLShiftOri<0>(MCOperand::createExpr(LoExpr), RegNo, SMLoc(), + Instructions); } } +bool MipsAsmParser::expandUncondBranchMMPseudo( + MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { + assert(getInstDesc(Inst.getOpcode()).getNumOperands() == 1 && + "unexpected number of operands"); + + MCOperand Offset = Inst.getOperand(0); + if (Offset.isExpr()) { + Inst.clear(); + Inst.setOpcode(Mips::BEQ_MM); + Inst.addOperand(MCOperand::createReg(Mips::ZERO)); + Inst.addOperand(MCOperand::createReg(Mips::ZERO)); + Inst.addOperand(MCOperand::createExpr(Offset.getExpr())); + } else { + assert(Offset.isImm() && "expected immediate operand kind"); + if (isIntN(11, Offset.getImm())) { + // If offset fits into 11 bits then this instruction becomes microMIPS + // 16-bit unconditional branch instruction. + Inst.setOpcode(Mips::B16_MM); + } else { + if (!isIntN(17, Offset.getImm())) + Error(IDLoc, "branch target out of range"); + if (OffsetToAlignment(Offset.getImm(), 1LL << 1)) + Error(IDLoc, "branch to misaligned address"); + Inst.clear(); + Inst.setOpcode(Mips::BEQ_MM); + Inst.addOperand(MCOperand::createReg(Mips::ZERO)); + Inst.addOperand(MCOperand::createReg(Mips::ZERO)); + Inst.addOperand(MCOperand::createImm(Offset.getImm())); + } + } + Instructions.push_back(Inst); + + // If .set reorder is active, emit a NOP after the branch instruction. + if (AssemblerOptions.back()->isReorder()) + createNop(true, IDLoc, Instructions); + + return false; +} + void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions, bool isLoad, bool isImmOpnd) { @@ -1779,29 +2090,27 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, if (isLoad && IsGPR && (BaseRegNum != RegOpNum)) TmpRegNum = RegOpNum; else { - int AT = getATReg(IDLoc); // At this point we need AT to perform the expansions and we exit if it is // not available. - if (!AT) + TmpRegNum = getATReg(IDLoc); + if (!TmpRegNum) return; - TmpRegNum = getReg( - (isGP64bit()) ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, AT); } TempInst.setOpcode(Mips::LUi); - TempInst.addOperand(MCOperand::CreateReg(TmpRegNum)); + TempInst.addOperand(MCOperand::createReg(TmpRegNum)); if (isImmOpnd) - TempInst.addOperand(MCOperand::CreateImm(HiOffset)); + TempInst.addOperand(MCOperand::createImm(HiOffset)); else { if (ExprOffset->getKind() == MCExpr::SymbolRef) { SR = static_cast<const MCSymbolRefExpr *>(ExprOffset); - const MCSymbolRefExpr *HiExpr = MCSymbolRefExpr::Create( + const MCSymbolRefExpr *HiExpr = MCSymbolRefExpr::create( SR->getSymbol().getName(), MCSymbolRefExpr::VK_Mips_ABS_HI, getContext()); - TempInst.addOperand(MCOperand::CreateExpr(HiExpr)); + TempInst.addOperand(MCOperand::createExpr(HiExpr)); } else { const MCExpr *HiExpr = evaluateRelocExpr(ExprOffset, "hi"); - TempInst.addOperand(MCOperand::CreateExpr(HiExpr)); + TempInst.addOperand(MCOperand::createExpr(HiExpr)); } } // Add the instruction to the list. @@ -1809,34 +2118,86 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, // Prepare TempInst for next instruction. TempInst.clear(); // Add temp register to base. - TempInst.setOpcode(Mips::ADDu); - TempInst.addOperand(MCOperand::CreateReg(TmpRegNum)); - TempInst.addOperand(MCOperand::CreateReg(TmpRegNum)); - TempInst.addOperand(MCOperand::CreateReg(BaseRegNum)); - Instructions.push_back(TempInst); - TempInst.clear(); + if (BaseRegNum != Mips::ZERO) { + TempInst.setOpcode(Mips::ADDu); + TempInst.addOperand(MCOperand::createReg(TmpRegNum)); + TempInst.addOperand(MCOperand::createReg(TmpRegNum)); + TempInst.addOperand(MCOperand::createReg(BaseRegNum)); + Instructions.push_back(TempInst); + TempInst.clear(); + } // And finally, create original instruction with low part // of offset and new base. TempInst.setOpcode(Inst.getOpcode()); - TempInst.addOperand(MCOperand::CreateReg(RegOpNum)); - TempInst.addOperand(MCOperand::CreateReg(TmpRegNum)); + TempInst.addOperand(MCOperand::createReg(RegOpNum)); + TempInst.addOperand(MCOperand::createReg(TmpRegNum)); if (isImmOpnd) - TempInst.addOperand(MCOperand::CreateImm(LoOffset)); + TempInst.addOperand(MCOperand::createImm(LoOffset)); else { if (ExprOffset->getKind() == MCExpr::SymbolRef) { - const MCSymbolRefExpr *LoExpr = MCSymbolRefExpr::Create( + const MCSymbolRefExpr *LoExpr = MCSymbolRefExpr::create( SR->getSymbol().getName(), MCSymbolRefExpr::VK_Mips_ABS_LO, getContext()); - TempInst.addOperand(MCOperand::CreateExpr(LoExpr)); + TempInst.addOperand(MCOperand::createExpr(LoExpr)); } else { const MCExpr *LoExpr = evaluateRelocExpr(ExprOffset, "lo"); - TempInst.addOperand(MCOperand::CreateExpr(LoExpr)); + TempInst.addOperand(MCOperand::createExpr(LoExpr)); } } Instructions.push_back(TempInst); TempInst.clear(); } +bool +MipsAsmParser::expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + 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."); + + if (OpNum < 8 && Inst.getOperand(OpNum - 1).getImm() <= 60 && + Inst.getOperand(OpNum - 1).getImm() >= 0 && + Inst.getOperand(OpNum - 2).getReg() == Mips::SP && + Inst.getOperand(OpNum - 3).getReg() == Mips::RA) + // It can be implemented as SWM16 or LWM16 instruction. + NewOpcode = Opcode == Mips::SWM_MM ? Mips::SWM16_MM : Mips::LWM16_MM; + + Inst.setOpcode(NewOpcode); + Instructions.push_back(Inst); + return false; +} + +void MipsAsmParser::createNop(bool hasShortDelaySlot, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + MCInst NopInst; + if (hasShortDelaySlot) { + NopInst.setOpcode(Mips::MOVE16_MM); + NopInst.addOperand(MCOperand::createReg(Mips::ZERO)); + NopInst.addOperand(MCOperand::createReg(Mips::ZERO)); + } else { + NopInst.setOpcode(Mips::SLL); + NopInst.addOperand(MCOperand::createReg(Mips::ZERO)); + NopInst.addOperand(MCOperand::createReg(Mips::ZERO)); + NopInst.addOperand(MCOperand::createImm(0)); + } + Instructions.push_back(NopInst); +} + +void MipsAsmParser::createAddu(unsigned DstReg, unsigned SrcReg, + unsigned TrgReg, + SmallVectorImpl<MCInst> &Instructions) { + MCInst AdduInst; + AdduInst.setOpcode(Mips::ADDu); + AdduInst.addOperand(MCOperand::createReg(DstReg)); + AdduInst.addOperand(MCOperand::createReg(SrcReg)); + AdduInst.addOperand(MCOperand::createReg(TrgReg)); + Instructions.push_back(AdduInst); +} + unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) { // As described by the Mips32r2 spec, the registers Rd and Rs for // jalr.hb must be different. @@ -1893,15 +2254,15 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, llvm_unreachable("Implement any new match types added!"); } -void MipsAsmParser::warnIfAssemblerTemporary(int RegIndex, SMLoc Loc) { - if ((RegIndex != 0) && - ((int)AssemblerOptions.back()->getATRegNum() == RegIndex)) { - if (RegIndex == 1) - Warning(Loc, "used $at without \".set noat\""); - else - Warning(Loc, Twine("used $") + Twine(RegIndex) + " with \".set at=$" + - Twine(RegIndex) + "\""); - } +void MipsAsmParser::warnIfRegIndexIsAT(unsigned RegIndex, SMLoc Loc) { + if (RegIndex != 0 && AssemblerOptions.back()->getATRegIndex() == RegIndex) + Warning(Loc, "used $at (currently $" + Twine(RegIndex) + + ") without \".set noat\""); +} + +void MipsAsmParser::warnIfNoMacro(SMLoc Loc) { + if (!AssemblerOptions.back()->isMacro()) + Warning(Loc, "macro instruction expanded into multiple instructions"); } void @@ -2075,19 +2436,15 @@ int MipsAsmParser::matchMSA128CtrlRegisterName(StringRef Name) { return CC; } -bool MipsAssemblerOptions::setATReg(unsigned Reg) { - if (Reg > 31) - return false; - - ATReg = Reg; - return true; -} - -int MipsAsmParser::getATReg(SMLoc Loc) { - int AT = AssemblerOptions.back()->getATRegNum(); - if (AT == 0) +unsigned MipsAsmParser::getATReg(SMLoc Loc) { + unsigned ATIndex = AssemblerOptions.back()->getATRegIndex(); + if (ATIndex == 0) { reportParseError(Loc, "pseudo-instruction requires $at, which is not available"); + return 0; + } + unsigned AT = getReg( + (isGP64bit()) ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, ATIndex); return AT; } @@ -2147,10 +2504,10 @@ bool MipsAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { return true; SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); - MCSymbol *Sym = getContext().GetOrCreateSymbol("$" + Identifier); + MCSymbol *Sym = getContext().getOrCreateSymbol("$" + Identifier); // Otherwise create a symbol reference. const MCExpr *Res = - MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_None, getContext()); + MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); Operands.push_back(MipsOperand::CreateImm(Res, S, E, *this)); return false; @@ -2210,14 +2567,14 @@ const MCExpr *MipsAsmParser::evaluateRelocExpr(const MCExpr *Expr, default: report_fatal_error("unsupported reloc value"); } - return MCConstantExpr::Create(Val, getContext()); + return MCConstantExpr::create(Val, getContext()); } if (const MCSymbolRefExpr *MSRE = dyn_cast<MCSymbolRefExpr>(Expr)) { // It's a symbol, create a symbolic expression from the symbol. StringRef Symbol = MSRE->getSymbol().getName(); MCSymbolRefExpr::VariantKind VK = getVariantKind(RelocStr); - Res = MCSymbolRefExpr::Create(Symbol, VK, getContext()); + Res = MCSymbolRefExpr::create(Symbol, VK, getContext()); return Res; } @@ -2226,17 +2583,17 @@ const MCExpr *MipsAsmParser::evaluateRelocExpr(const MCExpr *Expr, // Try to create target expression. if (MipsMCExpr::isSupportedBinaryExpr(VK, BE)) - return MipsMCExpr::Create(VK, Expr, getContext()); + 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()); + 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()); + Res = MCUnaryExpr::create(UN->getOpcode(), UnExp, getContext()); return Res; } // Just return the original expression. @@ -2271,7 +2628,7 @@ bool MipsAsmParser::parseRelocOperand(const MCExpr *&Res) { if (Tok.isNot(AsmToken::Identifier)) return true; - std::string Str = Tok.getIdentifier().str(); + std::string Str = Tok.getIdentifier(); Parser.Lex(); // Eat the identifier. // Now make an expression from the rest of the operand. @@ -2424,7 +2781,7 @@ MipsAsmParser::parseMemOperand(OperandVector &Operands) { Parser.Lex(); // Eat the ')' token. if (!IdVal) - IdVal = MCConstantExpr::Create(0, getContext()); + IdVal = MCConstantExpr::create(0, getContext()); // Replace the register operand with the memory operand. std::unique_ptr<MipsOperand> op( @@ -2435,10 +2792,10 @@ MipsAsmParser::parseMemOperand(OperandVector &Operands) { // Add the memory operand. if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(IdVal)) { int64_t Imm; - if (IdVal->EvaluateAsAbsolute(Imm)) - IdVal = MCConstantExpr::Create(Imm, getContext()); + if (IdVal->evaluateAsAbsolute(Imm)) + IdVal = MCConstantExpr::create(Imm, getContext()); else if (BE->getLHS()->getKind() != MCExpr::SymbolRef) - IdVal = MCBinaryExpr::Create(BE->getOpcode(), BE->getRHS(), BE->getLHS(), + IdVal = MCBinaryExpr::create(BE->getOpcode(), BE->getRHS(), BE->getLHS(), getContext()); } @@ -2448,7 +2805,7 @@ MipsAsmParser::parseMemOperand(OperandVector &Operands) { bool MipsAsmParser::searchSymbolAlias(OperandVector &Operands) { MCAsmParser &Parser = getParser(); - MCSymbol *Sym = getContext().LookupSymbol(Parser.getTok().getIdentifier()); + MCSymbol *Sym = getContext().lookupSymbol(Parser.getTok().getIdentifier()); if (Sym) { SMLoc S = Parser.getTok().getLoc(); const MCExpr *Expr; @@ -2655,7 +3012,7 @@ MipsAsmParser::parseInvNum(OperandVector &Operands) { int64_t Val = MCE->getValue(); SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); Operands.push_back(MipsOperand::CreateImm( - MCConstantExpr::Create(0 - Val, getContext()), S, E, *this)); + MCConstantExpr::create(0 - Val, getContext()), S, E, *this)); return MatchOperand_Success; } @@ -2679,7 +3036,7 @@ MipsAsmParser::parseLSAImm(OperandVector &Operands) { return MatchOperand_ParseFail; int64_t Val; - if (!Expr->EvaluateAsAbsolute(Val)) { + if (!Expr->evaluateAsAbsolute(Val)) { Error(S, "expected immediate value"); return MatchOperand_ParseFail; } @@ -2791,6 +3148,45 @@ MipsAsmParser::parseRegisterPair(OperandVector &Operands) { 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 = @@ -2953,67 +3349,84 @@ bool MipsAsmParser::reportParseError(SMLoc Loc, Twine ErrorMsg) { bool MipsAsmParser::parseSetNoAtDirective() { MCAsmParser &Parser = getParser(); // Line should look like: ".set noat". - // set at reg to 0. - AssemblerOptions.back()->setATReg(0); - // eat noat - Parser.Lex(); + + // Set the $at register to $0. + AssemblerOptions.back()->setATRegIndex(0); + + Parser.Lex(); // Eat "noat". + // 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; } + + getTargetStreamer().emitDirectiveSetNoAt(); Parser.Lex(); // Consume the EndOfStatement. return false; } bool MipsAsmParser::parseSetAtDirective() { + // Line can be: ".set at", which sets $at to $1 + // or ".set at=$reg", which sets $at to $reg. MCAsmParser &Parser = getParser(); - // Line can be .set at - defaults to $1 - // or .set at=$reg - int AtRegNo; - getParser().Lex(); + Parser.Lex(); // Eat "at". + if (getLexer().is(AsmToken::EndOfStatement)) { - AssemblerOptions.back()->setATReg(1); + // No register was specified, so we set $at to $1. + AssemblerOptions.back()->setATRegIndex(1); + + getTargetStreamer().emitDirectiveSetAt(); Parser.Lex(); // Consume the EndOfStatement. return false; - } else if (getLexer().is(AsmToken::Equal)) { - getParser().Lex(); // Eat the '='. - if (getLexer().isNot(AsmToken::Dollar)) { - reportParseError("unexpected token, expected dollar sign '$'"); + } + + if (getLexer().isNot(AsmToken::Equal)) { + reportParseError("unexpected token, expected equals sign"); + return false; + } + Parser.Lex(); // Eat "=". + + if (getLexer().isNot(AsmToken::Dollar)) { + if (getLexer().is(AsmToken::EndOfStatement)) { + reportParseError("no register specified"); return false; - } - Parser.Lex(); // Eat the '$'. - const AsmToken &Reg = Parser.getTok(); - if (Reg.is(AsmToken::Identifier)) { - AtRegNo = matchCPURegisterName(Reg.getIdentifier()); - } else if (Reg.is(AsmToken::Integer)) { - AtRegNo = Reg.getIntVal(); } else { - reportParseError("unexpected token, expected identifier or integer"); - return false; - } - - if (AtRegNo < 0 || AtRegNo > 31) { - reportParseError("unexpected token in statement"); + reportParseError("unexpected token, expected dollar sign '$'"); return false; } + } + Parser.Lex(); // Eat "$". - if (!AssemblerOptions.back()->setATReg(AtRegNo)) { - reportParseError("invalid register"); - return false; - } - getParser().Lex(); // Eat the register. + // Find out what "reg" is. + unsigned AtRegNo; + const AsmToken &Reg = Parser.getTok(); + if (Reg.is(AsmToken::Identifier)) { + AtRegNo = matchCPURegisterName(Reg.getIdentifier()); + } else if (Reg.is(AsmToken::Integer)) { + AtRegNo = Reg.getIntVal(); + } else { + reportParseError("unexpected token, expected identifier or integer"); + return false; + } - if (getLexer().isNot(AsmToken::EndOfStatement)) { - reportParseError("unexpected token, expected end of statement"); - return false; - } - Parser.Lex(); // Consume the EndOfStatement. + // Check if $reg is a valid register. If it is, set $at to $reg. + if (!AssemblerOptions.back()->setATRegIndex(AtRegNo)) { + reportParseError("invalid register"); return false; - } else { - reportParseError("unexpected token in statement"); + } + Parser.Lex(); // Eat "reg". + + // 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; } + + getTargetStreamer().emitDirectiveSetAtWithArg(AtRegNo); + + Parser.Lex(); // Consume the EndOfStatement. + return false; } bool MipsAsmParser::parseSetReorderDirective() { @@ -3053,6 +3466,7 @@ bool MipsAsmParser::parseSetMacroDirective() { return false; } AssemblerOptions.back()->setMacro(); + getTargetStreamer().emitDirectiveSetMacro(); Parser.Lex(); // Consume the EndOfStatement. return false; } @@ -3070,6 +3484,7 @@ bool MipsAsmParser::parseSetNoMacroDirective() { return false; } AssemblerOptions.back()->setNoMacro(); + getTargetStreamer().emitDirectiveSetNoMacro(); Parser.Lex(); // Consume the EndOfStatement. return false; } @@ -3188,7 +3603,9 @@ bool MipsAsmParser::parseSetPopDirective() { return reportParseError(Loc, ".set pop with no .set push"); AssemblerOptions.pop_back(); - setAvailableFeatures(AssemblerOptions.back()->getFeatures()); + setAvailableFeatures( + ComputeAvailableFeatures(AssemblerOptions.back()->getFeatures())); + STI.setFeatureBits(AssemblerOptions.back()->getFeatures()); getTargetStreamer().emitDirectiveSetPop(); return false; @@ -3208,6 +3625,28 @@ bool MipsAsmParser::parseSetPushDirective() { return false; } +bool MipsAsmParser::parseSetSoftFloatDirective() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return reportParseError("unexpected token, expected end of statement"); + + setFeatureBits(Mips::FeatureSoftFloat, "soft-float"); + getTargetStreamer().emitDirectiveSetSoftFloat(); + return false; +} + +bool MipsAsmParser::parseSetHardFloatDirective() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return reportParseError("unexpected token, expected end of statement"); + + clearFeatureBits(Mips::FeatureSoftFloat, "soft-float"); + getTargetStreamer().emitDirectiveSetHardFloat(); + return false; +} + bool MipsAsmParser::parseSetAssignment() { StringRef Name; const MCExpr *Value; @@ -3223,11 +3662,7 @@ bool MipsAsmParser::parseSetAssignment() { if (Parser.parseExpression(Value)) return reportParseError("expected valid expression after comma"); - // Check if the Name already exists as a symbol. - MCSymbol *Sym = getContext().LookupSymbol(Name); - if (Sym) - return reportParseError("symbol already defined"); - Sym = getContext().GetOrCreateSymbol(Name); + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); Sym->setVariableValue(Value); return false; @@ -3240,7 +3675,9 @@ bool MipsAsmParser::parseSetMips0Directive() { return reportParseError("unexpected token, expected end of statement"); // Reset assembler options to their initial values. - setAvailableFeatures(AssemblerOptions.front()->getFeatures()); + setAvailableFeatures( + ComputeAvailableFeatures(AssemblerOptions.front()->getFeatures())); + STI.setFeatureBits(AssemblerOptions.front()->getFeatures()); AssemblerOptions.back()->setFeatures(AssemblerOptions.front()->getFeatures()); getTargetStreamer().emitDirectiveSetMips0(); @@ -3267,9 +3704,13 @@ bool MipsAsmParser::parseSetArchDirective() { .Case("mips5", "mips5") .Case("mips32", "mips32") .Case("mips32r2", "mips32r2") + .Case("mips32r3", "mips32r3") + .Case("mips32r5", "mips32r5") .Case("mips32r6", "mips32r6") .Case("mips64", "mips64") .Case("mips64r2", "mips64r2") + .Case("mips64r3", "mips64r3") + .Case("mips64r5", "mips64r5") .Case("mips64r6", "mips64r6") .Case("cnmips", "cnmips") .Case("r4000", "mips3") // This is an implementation of Mips3. @@ -3327,6 +3768,14 @@ bool MipsAsmParser::parseSetFeature(uint64_t Feature) { selectArch("mips32r2"); getTargetStreamer().emitDirectiveSetMips32R2(); break; + case Mips::FeatureMips32r3: + selectArch("mips32r3"); + getTargetStreamer().emitDirectiveSetMips32R3(); + break; + case Mips::FeatureMips32r5: + selectArch("mips32r5"); + getTargetStreamer().emitDirectiveSetMips32R5(); + break; case Mips::FeatureMips32r6: selectArch("mips32r6"); getTargetStreamer().emitDirectiveSetMips32R6(); @@ -3339,6 +3788,14 @@ bool MipsAsmParser::parseSetFeature(uint64_t Feature) { selectArch("mips64r2"); getTargetStreamer().emitDirectiveSetMips64R2(); break; + case Mips::FeatureMips64r3: + selectArch("mips64r3"); + getTargetStreamer().emitDirectiveSetMips64R3(); + break; + case Mips::FeatureMips64r5: + selectArch("mips64r5"); + getTargetStreamer().emitDirectiveSetMips64R5(); + break; case Mips::FeatureMips64r6: selectArch("mips64r6"); getTargetStreamer().emitDirectiveSetMips64R6(); @@ -3443,12 +3900,20 @@ bool MipsAsmParser::parseDirectiveCPSetup() { if (!eatComma("unexpected token, expected comma")) return true; - StringRef Name; - if (Parser.parseIdentifier(Name)) - reportParseError("expected identifier"); - MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); + const MCExpr *Expr; + if (Parser.parseExpression(Expr)) { + reportParseError("expected expression"); + return false; + } - getTargetStreamer().emitDirectiveCpsetup(FuncReg, Save, *Sym, SaveIsReg); + if (Expr->getKind() != MCExpr::SymbolRef) { + reportParseError("expected symbol"); + return false; + } + const MCSymbolRefExpr *Ref = static_cast<const MCSymbolRefExpr *>(Expr); + + getTargetStreamer().emitDirectiveCpsetup(FuncReg, Save, Ref->getSymbol(), + SaveIsReg); return false; } @@ -3524,12 +3989,20 @@ bool MipsAsmParser::parseDirectiveSet() { return parseSetFeature(Mips::FeatureMips32); } else if (Tok.getString() == "mips32r2") { return parseSetFeature(Mips::FeatureMips32r2); + } else if (Tok.getString() == "mips32r3") { + return parseSetFeature(Mips::FeatureMips32r3); + } else if (Tok.getString() == "mips32r5") { + return parseSetFeature(Mips::FeatureMips32r5); } else if (Tok.getString() == "mips32r6") { return parseSetFeature(Mips::FeatureMips32r6); } else if (Tok.getString() == "mips64") { return parseSetFeature(Mips::FeatureMips64); } else if (Tok.getString() == "mips64r2") { return parseSetFeature(Mips::FeatureMips64r2); + } else if (Tok.getString() == "mips64r3") { + return parseSetFeature(Mips::FeatureMips64r3); + } else if (Tok.getString() == "mips64r5") { + return parseSetFeature(Mips::FeatureMips64r5); } else if (Tok.getString() == "mips64r6") { return parseSetFeature(Mips::FeatureMips64r6); } else if (Tok.getString() == "dsp") { @@ -3540,6 +4013,10 @@ bool MipsAsmParser::parseDirectiveSet() { return parseSetMsaDirective(); } else if (Tok.getString() == "nomsa") { return parseSetNoMsaDirective(); + } else if (Tok.getString() == "softfloat") { + return parseSetSoftFloatDirective(); + } else if (Tok.getString() == "hardfloat") { + return parseSetHardFloatDirective(); } else { // It is just an identifier, look for an assignment. parseSetAssignment(); @@ -3652,6 +4129,23 @@ bool MipsAsmParser::parseDirectiveOption() { return false; } +/// parseInsnDirective +/// ::= .insn +bool MipsAsmParser::parseInsnDirective() { + // 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; + } + + // The actual label marking happens in + // MipsELFStreamer::createPendingLabelRelocs(). + getTargetStreamer().emitDirectiveInsn(); + + getParser().Lex(); // Eat EndOfStatement token. + return false; +} + /// parseDirectiveModule /// ::= .module oddspreg /// ::= .module nooddspreg @@ -3824,7 +4318,7 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { reportParseError("expected number after comma"); return false; } - if (!DummyNumber->EvaluateAsAbsolute(DummyNumberVal)) { + if (!DummyNumber->evaluateAsAbsolute(DummyNumberVal)) { reportParseError("expected an absolute expression after comma"); return false; } @@ -3836,7 +4330,7 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { return false; } - MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName); + MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName); getTargetStreamer().emitDirectiveEnt(*Sym); CurrentFn = Sym; @@ -3904,7 +4398,7 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { return false; } - if (!FrameSize->EvaluateAsAbsolute(FrameSizeVal)) { + if (!FrameSize->evaluateAsAbsolute(FrameSizeVal)) { reportParseError("frame size not an absolute expression"); return false; } @@ -3965,7 +4459,7 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { return false; } - if (!BitMask->EvaluateAsAbsolute(BitMaskVal)) { + if (!BitMask->evaluateAsAbsolute(BitMaskVal)) { reportParseError("bitmask not an absolute expression"); return false; } @@ -3986,7 +4480,7 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { return false; } - if (!FrameOffset->EvaluateAsAbsolute(FrameOffsetVal)) { + if (!FrameOffset->evaluateAsAbsolute(FrameOffsetVal)) { reportParseError("frame offset not an absolute expression"); return false; } @@ -4042,9 +4536,28 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { if (IDVal == ".module") return parseDirectiveModule(); + if (IDVal == ".llvm_internal_mips_reallow_module_directive") + return parseInternalDirectiveReallowModule(); + + if (IDVal == ".insn") + return parseInsnDirective(); + return true; } +bool MipsAsmParser::parseInternalDirectiveReallowModule() { + // 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; + } + + getTargetStreamer().reallowModuleDirective(); + + getParser().Lex(); // Eat EndOfStatement token. + return false; +} + extern "C" void LLVMInitializeMipsAsmParser() { RegisterMCAsmParser<MipsAsmParser> X(TheMipsTarget); RegisterMCAsmParser<MipsAsmParser> Y(TheMipselTarget); |