//
//===----------------------------------------------------------------------===//
+#include "MCTargetDesc/MipsABIInfo.h"
#include "MCTargetDesc/MipsMCExpr.h"
#include "MCTargetDesc/MipsMCTargetDesc.h"
#include "MipsRegisterInfo.h"
#include "MipsTargetStreamer.h"
#include "llvm/ADT/APInt.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCTargetAsmParser.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
-#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/raw_ostream.h"
#include <memory>
using namespace llvm;
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; }
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() {
}
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
// selected. This usually happens after an '.end func'
// directive.
+ bool IsLittleEndian;
// Print a warning along with its fix-it message at the given range.
void printWarningWithFixIt(const Twine &Msg, const Twine &FixMsg,
MipsAsmParser::OperandMatchResultTy parseLSAImm(OperandVector &Operands);
+ MipsAsmParser::OperandMatchResultTy
+ parseRegisterPair (OperandVector &Operands);
+
+ MipsAsmParser::OperandMatchResultTy
+ parseMovePRegPair(OperandVector &Operands);
+
MipsAsmParser::OperandMatchResultTy
parseRegisterList (OperandVector &Operands);
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 expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc,
- SmallVectorImpl<MCInst> &Instructions);
+ bool loadAndAddSymbolAddress(const MCExpr *SymExpr, unsigned DstReg,
+ unsigned SrcReg, bool Is32BitSym, SMLoc IDLoc,
+ SmallVectorImpl<MCInst> &Instructions);
+
+ bool expandLoadImm(MCInst &Inst, bool Is32BitImm, SMLoc IDLoc,
+ SmallVectorImpl<MCInst> &Instructions);
- bool expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc,
+ bool expandLoadAddressImm(MCInst &Inst, bool Is32BitImm, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions);
- void expandLoadAddressSym(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 expandMemInst(MCInst &Inst, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions, bool isLoad,
bool isImmOpnd);
+
+ bool expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc,
+ SmallVectorImpl<MCInst> &Instructions);
+
+ bool expandBranchImm(MCInst &Inst, SMLoc IDLoc,
+ SmallVectorImpl<MCInst> &Instructions);
+
+ bool expandCondBranches(MCInst &Inst, SMLoc IDLoc,
+ SmallVectorImpl<MCInst> &Instructions);
+
+ bool expandUlhu(MCInst &Inst, SMLoc IDLoc,
+ SmallVectorImpl<MCInst> &Instructions);
+
+ void createNop(bool hasShortDelaySlot, SMLoc IDLoc,
+ SmallVectorImpl<MCInst> &Instructions);
+
+ void createAddu(unsigned DstReg, unsigned SrcReg, unsigned TrgReg,
+ bool Is64Bit, SmallVectorImpl<MCInst> &Instructions);
+
bool reportParseError(Twine ErrorMsg);
bool reportParseError(SMLoc Loc, Twine ErrorMsg);
bool parseDirectiveNaN();
bool parseDirectiveSet();
bool parseDirectiveOption();
+ bool parseInsnDirective();
bool parseSetAtDirective();
bool parseSetNoAtDirective();
bool parseSetFpDirective();
bool parseSetPopDirective();
bool parseSetPushDirective();
+ bool parseSetSoftFloatDirective();
+ bool parseSetHardFloatDirective();
bool parseSetAssignment();
bool parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI,
StringRef Directive);
+ bool parseInternalDirectiveReallowModule();
+
MCSymbolRefExpr::VariantKind getVariantKind(StringRef Symbol);
bool eatComma(StringRef ErrorStr);
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);
// 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:
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");
CurrentFn = nullptr;
+
+ Triple TheTriple(sti.getTargetTriple());
+ if ((TheTriple.getArch() == Triple::mips) ||
+ (TheTriple.getArch() == Triple::mips64))
+ IsLittleEndian = false;
+ else
+ IsLittleEndian = true;
}
/// 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];
+ }
+
+ bool useSoftFloat() const {
+ return STI.getFeatureBits()[Mips::FeatureSoftFloat];
}
- // 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);
+ /// Warn if RegIndex is the same as the current AT.
+ void warnIfRegIndexIsAT(unsigned RegIndex, SMLoc Loc);
+
+ void warnIfNoMacro(SMLoc Loc);
+
+ bool isLittle() const { return IsLittleEndian; }
};
}
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_RegList, /// A physical register list
+ k_RegPair /// A pair of physical register
} Kind;
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);
}
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 {
/// 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
/// 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 "
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 {
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);
+ }
+
+ void addMicroMipsMemOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 2 && "Invalid number of operands!");
+
+ Inst.addOperand(MCOperand::createReg(getMemBase()->getGPRMM16Reg()));
const MCExpr *Expr = getMemOff();
addExpr(Inst, Expr);
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));
+ }
+
+ 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 {
bool isConstantImm() const {
return isImm() && dyn_cast<MCConstantExpr>(getImm());
}
+ template <unsigned Bits> bool isUImm() const {
+ return isImm() && isConstantImm() && isUInt<Bits>(getConstantImm());
+ }
bool isToken() const override {
// Note: It's not possible to pretend that other operand kinds are tokens.
// The matcher emitter checks tokens first.
template <unsigned Bits> bool isMemWithSimmOffset() const {
return isMem() && isConstantMemOff() && isInt<Bits>(getConstantMemOff());
}
+ 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);
+ }
+ bool isRegList16() const {
+ if (!isRegList())
+ return false;
+
+ int Size = RegList.List->size();
+ if (Size < 2 || Size > 5 || *RegList.List->begin() != Mips::S0 ||
+ RegList.List->back() != Mips::RA)
+ return false;
+
+ int PrevReg = *RegList.List->begin();
+ for (int i = 1; i < Size - 1; i++) {
+ int Reg = (*(RegList.List))[i];
+ if ( Reg != PrevReg + 1)
+ return false;
+ PrevReg = Reg;
+ }
+
+ return true;
+ }
bool isInvNum() const { return Kind == k_Immediate; }
bool isLSAImm() const {
if (!isConstantImm())
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!");
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
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);
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;
}
+ 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 isGPRAsmReg() const {
return isRegIdx() && RegIdx.Kind & RegKind_GPR && RegIdx.Index <= 31;
}
(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;
case k_PhysRegister:
case k_RegisterIndex:
case k_Token:
+ case k_RegPair:
break;
}
}
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:
OS << Reg << " ";
OS << ">";
break;
+ case k_RegPair:
+ OS << "RegPair<" << RegIdx.Index << "," << RegIdx.Index + 1 << ">";
+ break;
}
}
}; // class MipsOperand
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:
1LL << (inMicroMipsMode() ? 1 : 2)))
return Error(IDLoc, "branch to misaligned address");
break;
+ case Mips::BEQZ16_MM:
+ case Mips::BNEZ16_MM:
+ 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(8, Offset.getImm()))
+ return Error(IDLoc, "branch target out of range");
+ if (OffsetToAlignment(Offset.getImm(), 2LL))
+ return Error(IDLoc, "branch to misaligned address");
+ break;
}
}
"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()) {
} // 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;
Imm == 64 || Imm == 255 || Imm == 32768 || Imm == 65535))
return Error(IDLoc, "immediate operand value out of range");
break;
+ case Mips::LBU16_MM:
+ Opnd = Inst.getOperand(2);
+ if (!Opnd.isImm())
+ return Error(IDLoc, "expected immediate operand kind");
+ Imm = Opnd.getImm();
+ if (Imm < -1 || Imm > 14)
+ return Error(IDLoc, "immediate operand value out of range");
+ break;
+ case Mips::SB16_MM:
+ Opnd = Inst.getOperand(2);
+ if (!Opnd.isImm())
+ return Error(IDLoc, "expected immediate operand kind");
+ Imm = Opnd.getImm();
+ if (Imm < 0 || Imm > 15)
+ return Error(IDLoc, "immediate operand value out of range");
+ break;
+ case Mips::LHU16_MM:
+ case Mips::SH16_MM:
+ Opnd = Inst.getOperand(2);
+ if (!Opnd.isImm())
+ return Error(IDLoc, "expected immediate operand kind");
+ Imm = Opnd.getImm();
+ if (Imm < 0 || Imm > 30 || (Imm % 2 != 0))
+ return Error(IDLoc, "immediate operand value out of range");
+ break;
+ case Mips::LW16_MM:
+ case Mips::SW16_MM:
+ Opnd = Inst.getOperand(2);
+ if (!Opnd.isImm())
+ return Error(IDLoc, "expected immediate operand kind");
+ Imm = Opnd.getImm();
+ if (Imm < 0 || Imm > 60 || (Imm % 4 != 0))
+ return Error(IDLoc, "immediate operand value out of range");
+ break;
+ case Mips::CACHE:
+ case Mips::PREF:
+ Opnd = Inst.getOperand(2);
+ if (!Opnd.isImm())
+ return Error(IDLoc, "expected immediate operand kind");
+ Imm = Opnd.getImm();
+ 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:
+ case Mips::BneImm:
+ case Mips::BeqImm:
+ case Mips::BLT:
+ case Mips::BLE:
+ case Mips::BGE:
+ case Mips::BGT:
+ case Mips::BLTU:
+ case Mips::BLEU:
+ case Mips::BGEU:
+ case Mips::BGTU:
+ case Mips::Ulhu:
return true;
default:
return false;
bool MipsAsmParser::expandInstruction(MCInst &Inst, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions) {
switch (Inst.getOpcode()) {
- default:
- assert(0 && "unimplemented expansion");
- return true;
- 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);
+ default: llvm_unreachable("unimplemented expansion");
+ 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);
+ case Mips::BneImm:
+ case Mips::BeqImm:
+ return expandBranchImm(Inst, IDLoc, Instructions);
+ case Mips::BLT:
+ case Mips::BLE:
+ case Mips::BGE:
+ case Mips::BGT:
+ case Mips::BLTU:
+ case Mips::BLEU:
+ case Mips::BGEU:
+ case Mips::BGTU:
+ return expandCondBranches(Inst, IDLoc, Instructions);
+ case Mips::Ulhu:
+ return expandUlhu(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();
+ unsigned TmpReg = DstReg;
+ if (UseSrcReg && (DstReg == SrcReg)) {
+ // At this point we need AT to perform the expansions and we exit if it is
+ // not available.
+ unsigned ATReg = getATReg(IDLoc);
+ if (!ATReg)
+ return true;
+ TmpReg = ATReg;
+ }
+
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(TmpReg));
+ 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, TmpReg, IDLoc, Instructions);
+ } else {
+ tmpInst.setOpcode(Mips::LUi);
+ tmpInst.addOperand(MCOperand::createReg(TmpReg));
+ tmpInst.addOperand(MCOperand::createImm(Bits31To16));
+ Instructions.push_back(tmpInst);
+ }
+ createLShiftOri<0>(Bits15To0, TmpReg, IDLoc, Instructions);
+
+ if (UseSrcReg)
+ createAddu(DstReg, TmpReg, SrcReg, !Is32BitImm, 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(TmpReg));
+ 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, TmpReg, IDLoc, Instructions);
+ createLShiftOri<16>(Bits15To0, TmpReg, IDLoc, Instructions);
+
+ if (UseSrcReg)
+ createAddu(DstReg, TmpReg, SrcReg, !Is32BitImm, 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(TmpReg));
+ 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, TmpReg, 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, TmpReg, IDLoc, Instructions);
+ } else {
+ createLShiftOri<16>(Bits31To16, TmpReg, IDLoc, Instructions);
+ createLShiftOri<16>(Bits15To0, TmpReg, IDLoc, Instructions);
+ }
+
+ if (UseSrcReg)
+ createAddu(DstReg, TmpReg, SrcReg, !Is32BitImm, 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 &SrcRegOp = Inst.getOperand(1);
+ assert(SrcRegOp.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);
+ if (loadAndAddSymbolAddress(ImmOp.getExpr(), DstRegOp.getReg(),
+ SrcRegOp.getReg(), Is32BitImm, IDLoc,
+ Instructions))
+ return true;
+
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);
+ if (loadAndAddSymbolAddress(ImmOp.getExpr(), DstRegOp.getReg(),
+ Mips::NoRegister, Is32BitImm, IDLoc,
+ Instructions))
+ return true;
+
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.
+bool MipsAsmParser::loadAndAddSymbolAddress(
+ const MCExpr *SymExpr, unsigned DstReg, unsigned SrcReg, 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();
- const MCSymbolRefExpr *Symbol = cast<MCSymbolRefExpr>(SymOp.getExpr());
- const MCSymbolRefExpr *HiExpr =
- MCSymbolRefExpr::Create(Symbol->getSymbol().getName(),
- MCSymbolRefExpr::VK_Mips_ABS_HI, getContext());
- const MCSymbolRefExpr *LoExpr =
- MCSymbolRefExpr::Create(Symbol->getSymbol().getName(),
- MCSymbolRefExpr::VK_Mips_ABS_LO, getContext());
- if (isGP64bit()) {
+ const MCSymbolRefExpr *Symbol = cast<MCSymbolRefExpr>(SymExpr);
+ const MCSymbolRefExpr *HiExpr = MCSymbolRefExpr::create(
+ &Symbol->getSymbol(), MCSymbolRefExpr::VK_Mips_ABS_HI, getContext());
+ const MCSymbolRefExpr *LoExpr = MCSymbolRefExpr::create(
+ &Symbol->getSymbol(), MCSymbolRefExpr::VK_Mips_ABS_LO, getContext());
+
+ bool UseSrcReg = SrcReg != Mips::NoRegister;
+
+ unsigned TmpReg = DstReg;
+ if (UseSrcReg && (DstReg == SrcReg)) {
+ // At this point we need AT to perform the expansions and we exit if it is
+ // not available.
+ unsigned ATReg = getATReg(IDLoc);
+ if (!ATReg)
+ return true;
+ TmpReg = ATReg;
+ }
+
+ if (!Is32BitSym) {
// If it's a 64-bit architecture, expand to:
// la d,sym => lui d,highest(sym)
// ori d,d,higher(sym)
// ori d,d,hi16(sym)
// dsll d,d,16
// ori d,d,lo16(sym)
- const MCSymbolRefExpr *HighestExpr =
- MCSymbolRefExpr::Create(Symbol->getSymbol().getName(),
- MCSymbolRefExpr::VK_Mips_HIGHEST, getContext());
- const MCSymbolRefExpr *HigherExpr =
- MCSymbolRefExpr::Create(Symbol->getSymbol().getName(),
- MCSymbolRefExpr::VK_Mips_HIGHER, getContext());
+ const MCSymbolRefExpr *HighestExpr = MCSymbolRefExpr::create(
+ &Symbol->getSymbol(), MCSymbolRefExpr::VK_Mips_HIGHEST, getContext());
+ const MCSymbolRefExpr *HigherExpr = MCSymbolRefExpr::create(
+ &Symbol->getSymbol(), MCSymbolRefExpr::VK_Mips_HIGHER, getContext());
tmpInst.setOpcode(Mips::LUi);
- tmpInst.addOperand(MCOperand::CreateReg(RegNo));
- tmpInst.addOperand(MCOperand::CreateExpr(HighestExpr));
+ tmpInst.addOperand(MCOperand::createReg(TmpReg));
+ 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), TmpReg, SMLoc(),
+ Instructions);
+ createLShiftOri<16>(MCOperand::createExpr(HiExpr), TmpReg, SMLoc(),
Instructions);
- createShiftOr<true>(MCOperand::CreateExpr(LoExpr), RegNo, SMLoc(),
+ createLShiftOri<16>(MCOperand::createExpr(LoExpr), TmpReg, 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(TmpReg));
+ tmpInst.addOperand(MCOperand::createExpr(HiExpr));
Instructions.push_back(tmpInst);
- createShiftOr<false>(MCOperand::CreateExpr(LoExpr), RegNo, SMLoc(),
- Instructions);
+ createLShiftOri<0>(MCOperand::createExpr(LoExpr), TmpReg, SMLoc(),
+ Instructions);
+ }
+
+ if (UseSrcReg)
+ createAddu(DstReg, TmpReg, SrcReg, !Is32BitSym, Instructions);
+
+ return false;
+}
+
+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;
+}
+
+bool MipsAsmParser::expandBranchImm(MCInst &Inst, SMLoc IDLoc,
+ SmallVectorImpl<MCInst> &Instructions) {
+ const MCOperand &DstRegOp = Inst.getOperand(0);
+ assert(DstRegOp.isReg() && "expected register operand kind");
+
+ const MCOperand &ImmOp = Inst.getOperand(1);
+ assert(ImmOp.isImm() && "expected immediate operand kind");
+
+ const MCOperand &MemOffsetOp = Inst.getOperand(2);
+ assert(MemOffsetOp.isImm() && "expected immediate operand kind");
+
+ unsigned OpCode = 0;
+ switch(Inst.getOpcode()) {
+ case Mips::BneImm:
+ OpCode = Mips::BNE;
+ break;
+ case Mips::BeqImm:
+ OpCode = Mips::BEQ;
+ break;
+ default:
+ llvm_unreachable("Unknown immediate branch pseudo-instruction.");
+ break;
+ }
+
+ int64_t ImmValue = ImmOp.getImm();
+ if (ImmValue == 0) {
+ MCInst BranchInst;
+ BranchInst.setOpcode(OpCode);
+ BranchInst.addOperand(DstRegOp);
+ BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
+ BranchInst.addOperand(MemOffsetOp);
+ Instructions.push_back(BranchInst);
+ } else {
+ warnIfNoMacro(IDLoc);
+
+ unsigned ATReg = getATReg(IDLoc);
+ if (!ATReg)
+ return true;
+
+ if (loadImmediate(ImmValue, ATReg, Mips::NoRegister, !isGP64bit(), IDLoc,
+ Instructions))
+ return true;
+
+ MCInst BranchInst;
+ BranchInst.setOpcode(OpCode);
+ BranchInst.addOperand(DstRegOp);
+ BranchInst.addOperand(MCOperand::createReg(ATReg));
+ BranchInst.addOperand(MemOffsetOp);
+ Instructions.push_back(BranchInst);
}
+ return false;
}
void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions,
bool isLoad, bool isImmOpnd) {
- const MCSymbolRefExpr *SR;
MCInst TempInst;
unsigned ImmOffset, HiOffset, LoOffset;
const MCExpr *ExprOffset;
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(
- SR->getSymbol().getName(), MCSymbolRefExpr::VK_Mips_ABS_HI,
- getContext());
- TempInst.addOperand(MCOperand::CreateExpr(HiExpr));
- } else {
- const MCExpr *HiExpr = evaluateRelocExpr(ExprOffset, "hi");
- TempInst.addOperand(MCOperand::CreateExpr(HiExpr));
- }
+ const MCExpr *HiExpr = evaluateRelocExpr(ExprOffset, "hi");
+ TempInst.addOperand(MCOperand::createExpr(HiExpr));
}
// Add the instruction to the list.
Instructions.push_back(TempInst);
// 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(
- SR->getSymbol().getName(), MCSymbolRefExpr::VK_Mips_ABS_LO,
- getContext());
- TempInst.addOperand(MCOperand::CreateExpr(LoExpr));
- } else {
- const MCExpr *LoExpr = evaluateRelocExpr(ExprOffset, "lo");
- TempInst.addOperand(MCOperand::CreateExpr(LoExpr));
- }
+ const MCExpr *LoExpr = evaluateRelocExpr(ExprOffset, "lo");
+ 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;
+}
+
+bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc,
+ SmallVectorImpl<MCInst> &Instructions) {
+ unsigned PseudoOpcode = Inst.getOpcode();
+ unsigned SrcReg = Inst.getOperand(0).getReg();
+ unsigned TrgReg = Inst.getOperand(1).getReg();
+ const MCExpr *OffsetExpr = Inst.getOperand(2).getExpr();
+
+ unsigned ZeroSrcOpcode, ZeroTrgOpcode;
+ bool ReverseOrderSLT, IsUnsigned, AcceptsEquality;
+
+ switch (PseudoOpcode) {
+ case Mips::BLT:
+ case Mips::BLTU:
+ AcceptsEquality = false;
+ ReverseOrderSLT = false;
+ IsUnsigned = (PseudoOpcode == Mips::BLTU);
+ ZeroSrcOpcode = Mips::BGTZ;
+ ZeroTrgOpcode = Mips::BLTZ;
+ break;
+ case Mips::BLE:
+ case Mips::BLEU:
+ AcceptsEquality = true;
+ ReverseOrderSLT = true;
+ IsUnsigned = (PseudoOpcode == Mips::BLEU);
+ ZeroSrcOpcode = Mips::BGEZ;
+ ZeroTrgOpcode = Mips::BLEZ;
+ break;
+ case Mips::BGE:
+ case Mips::BGEU:
+ AcceptsEquality = true;
+ ReverseOrderSLT = false;
+ IsUnsigned = (PseudoOpcode == Mips::BGEU);
+ ZeroSrcOpcode = Mips::BLEZ;
+ ZeroTrgOpcode = Mips::BGEZ;
+ break;
+ case Mips::BGT:
+ case Mips::BGTU:
+ AcceptsEquality = false;
+ ReverseOrderSLT = true;
+ IsUnsigned = (PseudoOpcode == Mips::BGTU);
+ ZeroSrcOpcode = Mips::BLTZ;
+ ZeroTrgOpcode = Mips::BGTZ;
+ break;
+ default:
+ llvm_unreachable("unknown opcode for branch pseudo-instruction");
+ }
+
+ MCInst BranchInst;
+ bool IsTrgRegZero = (TrgReg == Mips::ZERO);
+ bool IsSrcRegZero = (SrcReg == Mips::ZERO);
+ if (IsSrcRegZero && IsTrgRegZero) {
+ // FIXME: All of these Opcode-specific if's are needed for compatibility
+ // with GAS' behaviour. However, they may not generate the most efficient
+ // code in some circumstances.
+ if (PseudoOpcode == Mips::BLT) {
+ BranchInst.setOpcode(Mips::BLTZ);
+ BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
+ BranchInst.addOperand(MCOperand::createExpr(OffsetExpr));
+ Instructions.push_back(BranchInst);
+ return false;
+ }
+ if (PseudoOpcode == Mips::BLE) {
+ BranchInst.setOpcode(Mips::BLEZ);
+ BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
+ BranchInst.addOperand(MCOperand::createExpr(OffsetExpr));
+ Instructions.push_back(BranchInst);
+ Warning(IDLoc, "branch is always taken");
+ return false;
+ }
+ if (PseudoOpcode == Mips::BGE) {
+ BranchInst.setOpcode(Mips::BGEZ);
+ BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
+ BranchInst.addOperand(MCOperand::createExpr(OffsetExpr));
+ Instructions.push_back(BranchInst);
+ Warning(IDLoc, "branch is always taken");
+ return false;
+ }
+ if (PseudoOpcode == Mips::BGT) {
+ BranchInst.setOpcode(Mips::BGTZ);
+ BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
+ BranchInst.addOperand(MCOperand::createExpr(OffsetExpr));
+ Instructions.push_back(BranchInst);
+ return false;
+ }
+ if (PseudoOpcode == Mips::BGTU) {
+ BranchInst.setOpcode(Mips::BNE);
+ BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
+ BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
+ BranchInst.addOperand(MCOperand::createExpr(OffsetExpr));
+ Instructions.push_back(BranchInst);
+ 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.
+ BranchInst.setOpcode(Mips::BEQ);
+ BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
+ BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
+ BranchInst.addOperand(MCOperand::createExpr(OffsetExpr));
+ Instructions.push_back(BranchInst);
+ Warning(IDLoc, "branch is always taken");
+ return false;
+ }
+ // If both registers are $0 and the pseudo-branch does not accept
+ // equality, it will never be taken, so we don't have to emit anything.
+ return false;
+ }
+ if (IsSrcRegZero || IsTrgRegZero) {
+ if ((IsSrcRegZero && PseudoOpcode == Mips::BGTU) ||
+ (IsTrgRegZero && PseudoOpcode == Mips::BLTU)) {
+ // If the $rs is $0 and the pseudo-branch is BGTU (0 > x) or
+ // if the $rt is $0 and the pseudo-branch is BLTU (x < 0),
+ // the pseudo-branch will never be taken, so we don't emit anything.
+ // This only applies to unsigned pseudo-branches.
+ return false;
+ }
+ if ((IsSrcRegZero && PseudoOpcode == Mips::BLEU) ||
+ (IsTrgRegZero && PseudoOpcode == Mips::BGEU)) {
+ // If the $rs is $0 and the pseudo-branch is BLEU (0 <= x) or
+ // if the $rt is $0 and the pseudo-branch is BGEU (x >= 0),
+ // the pseudo-branch will always be taken, so we emit an unconditional
+ // branch.
+ // This only applies to unsigned pseudo-branches.
+ BranchInst.setOpcode(Mips::BEQ);
+ BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
+ BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
+ BranchInst.addOperand(MCOperand::createExpr(OffsetExpr));
+ Instructions.push_back(BranchInst);
+ Warning(IDLoc, "branch is always taken");
+ return false;
+ }
+ if (IsUnsigned) {
+ // If the $rs is $0 and the pseudo-branch is BLTU (0 < x) or
+ // if the $rt is $0 and the pseudo-branch is BGTU (x > 0),
+ // the pseudo-branch will be taken only when the non-zero register is
+ // different from 0, so we emit a BNEZ.
+ //
+ // If the $rs is $0 and the pseudo-branch is BGEU (0 >= x) or
+ // if the $rt is $0 and the pseudo-branch is BLEU (x <= 0),
+ // the pseudo-branch will be taken only when the non-zero register is
+ // equal to 0, so we emit a BEQZ.
+ //
+ // Because only BLEU and BGEU branch on equality, we can use the
+ // AcceptsEquality variable to decide when to emit the BEQZ.
+ BranchInst.setOpcode(AcceptsEquality ? Mips::BEQ : Mips::BNE);
+ BranchInst.addOperand(
+ MCOperand::createReg(IsSrcRegZero ? TrgReg : SrcReg));
+ BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
+ BranchInst.addOperand(MCOperand::createExpr(OffsetExpr));
+ Instructions.push_back(BranchInst);
+ 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.
+ BranchInst.setOpcode(IsSrcRegZero ? ZeroSrcOpcode : ZeroTrgOpcode);
+ BranchInst.addOperand(MCOperand::createReg(IsSrcRegZero ? TrgReg : SrcReg));
+ BranchInst.addOperand(MCOperand::createExpr(OffsetExpr));
+ Instructions.push_back(BranchInst);
+ return false;
+ }
+
+ // If neither the SrcReg nor the TrgReg are $0, we need AT to perform the
+ // expansions. If it is not available, we return.
+ unsigned ATRegNum = getATReg(IDLoc);
+ if (!ATRegNum)
+ return true;
+
+ warnIfNoMacro(IDLoc);
+
+ // SLT fits well with 2 of our 4 pseudo-branches:
+ // BLT, where $rs < $rt, translates into "slt $at, $rs, $rt" and
+ // BGT, where $rs > $rt, translates into "slt $at, $rt, $rs".
+ // If the result of the SLT is 1, we branch, and if it's 0, we don't.
+ // 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.
+ // 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
+ // opposites.
+ //
+ // The same applies to the unsigned variants, except that SLTu is used
+ // instead of SLT.
+ MCInst SetInst;
+ SetInst.setOpcode(IsUnsigned ? Mips::SLTu : Mips::SLT);
+ SetInst.addOperand(MCOperand::createReg(ATRegNum));
+ SetInst.addOperand(MCOperand::createReg(ReverseOrderSLT ? TrgReg : SrcReg));
+ SetInst.addOperand(MCOperand::createReg(ReverseOrderSLT ? SrcReg : TrgReg));
+ Instructions.push_back(SetInst);
+
+ BranchInst.setOpcode(AcceptsEquality ? Mips::BEQ : Mips::BNE);
+ BranchInst.addOperand(MCOperand::createReg(ATRegNum));
+ BranchInst.addOperand(MCOperand::createReg(Mips::ZERO));
+ BranchInst.addOperand(MCOperand::createExpr(OffsetExpr));
+ Instructions.push_back(BranchInst);
+ return false;
+}
+
+bool MipsAsmParser::expandUlhu(MCInst &Inst, SMLoc IDLoc,
+ SmallVectorImpl<MCInst> &Instructions) {
+ if (hasMips32r6() || hasMips64r6()) {
+ Error(IDLoc, "instruction not supported on mips32r6 or mips64r6");
+ return false;
+ }
+
+ warnIfNoMacro(IDLoc);
+
+ 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");
+
+ 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.
+ 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(),
+ IDLoc, Instructions))
+ 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 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 SllReg = LoadedOffsetInAT ? DstReg : ATReg;
+
+ MCInst TmpInst;
+ TmpInst.setOpcode(Mips::LBu);
+ TmpInst.addOperand(MCOperand::createReg(FirstLbuDstReg));
+ TmpInst.addOperand(MCOperand::createReg(LbuSrcReg));
+ TmpInst.addOperand(MCOperand::createImm(FirstLbuOffset));
+ Instructions.push_back(TmpInst);
+
+ TmpInst.clear();
+ TmpInst.setOpcode(Mips::LBu);
+ TmpInst.addOperand(MCOperand::createReg(SecondLbuDstReg));
+ TmpInst.addOperand(MCOperand::createReg(LbuSrcReg));
+ TmpInst.addOperand(MCOperand::createImm(SecondLbuOffset));
+ Instructions.push_back(TmpInst);
+
+ TmpInst.clear();
+ TmpInst.setOpcode(Mips::SLL);
+ TmpInst.addOperand(MCOperand::createReg(SllReg));
+ TmpInst.addOperand(MCOperand::createReg(SllReg));
+ TmpInst.addOperand(MCOperand::createImm(8));
+ Instructions.push_back(TmpInst);
+
+ TmpInst.clear();
+ TmpInst.setOpcode(Mips::OR);
+ TmpInst.addOperand(MCOperand::createReg(DstReg));
+ TmpInst.addOperand(MCOperand::createReg(DstReg));
+ TmpInst.addOperand(MCOperand::createReg(ATReg));
+ Instructions.push_back(TmpInst);
+
+ 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, bool Is64Bit,
+ SmallVectorImpl<MCInst> &Instructions) {
+ MCInst AdduInst;
+ AdduInst.setOpcode(Is64Bit ? Mips::DADDu : 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.
MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
switch (MatchResult) {
- default:
- break;
case Match_Success: {
if (processInstruction(Inst, IDLoc, Instructions))
return true;
case Match_RequiresDifferentSrcAndDst:
return Error(IDLoc, "source and destination must be different");
}
- return true;
+
+ 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
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;
}
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;
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();
+ const MCSymbol *Symbol = &MSRE->getSymbol();
MCSymbolRefExpr::VariantKind VK = getVariantKind(RelocStr);
- Res = MCSymbolRefExpr::Create(Symbol, VK, getContext());
+ Res = MCSymbolRefExpr::create(Symbol, VK, getContext());
return Res;
}
// 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.
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.
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(
// 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());
}
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;
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;
}
return MatchOperand_ParseFail;
int64_t Val;
- if (!Expr->EvaluateAsAbsolute(Val)) {
+ if (!Expr->evaluateAsAbsolute(Val)) {
Error(S, "expected immediate value");
return MatchOperand_ParseFail;
}
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 =
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() {
return false;
}
AssemblerOptions.back()->setMacro();
+ getTargetStreamer().emitDirectiveSetMacro();
Parser.Lex(); // Consume the EndOfStatement.
return false;
}
return false;
}
AssemblerOptions.back()->setNoMacro();
+ getTargetStreamer().emitDirectiveSetNoMacro();
Parser.Lex(); // Consume the EndOfStatement.
return false;
}
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;
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;
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;
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();
.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.
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();
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();
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;
}
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") {
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();
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
return false;
}
- if (Lexer.is(AsmToken::Identifier)) {
- StringRef Option = Parser.getTok().getString();
- Parser.Lex();
-
- if (Option == "oddspreg") {
- getTargetStreamer().emitDirectiveModuleOddSPReg(true, isABI_O32());
- clearFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg");
+ StringRef Option;
+ if (Parser.parseIdentifier(Option)) {
+ reportParseError("expected .module option identifier");
+ return false;
+ }
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- reportParseError("unexpected token, expected end of statement");
- return false;
- }
+ if (Option == "oddspreg") {
+ getTargetStreamer().emitDirectiveModuleOddSPReg(true, isABI_O32());
+ clearFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg");
+ // 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;
- } else if (Option == "nooddspreg") {
- if (!isABI_O32()) {
- Error(L, "'.module nooddspreg' requires the O32 ABI");
- return false;
- }
+ }
- getTargetStreamer().emitDirectiveModuleOddSPReg(false, isABI_O32());
- setFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg");
+ return false; // parseDirectiveModule has finished successfully.
+ } else if (Option == "nooddspreg") {
+ if (!isABI_O32()) {
+ Error(L, "'.module nooddspreg' requires the O32 ABI");
+ return false;
+ }
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- reportParseError("unexpected token, expected end of statement");
- return false;
- }
+ getTargetStreamer().emitDirectiveModuleOddSPReg(false, isABI_O32());
+ setFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg");
+ // 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;
- } else if (Option == "fp") {
- return parseDirectiveModuleFP();
}
+ return false; // parseDirectiveModule has finished successfully.
+ } else if (Option == "fp") {
+ return parseDirectiveModuleFP();
+ } else {
return Error(L, "'" + Twine(Option) + "' is not a valid .module option.");
}
-
- return false;
}
/// parseDirectiveModuleFP
reportParseError("expected number after comma");
return false;
}
- if (!DummyNumber->EvaluateAsAbsolute(DummyNumberVal)) {
+ if (!DummyNumber->evaluateAsAbsolute(DummyNumberVal)) {
reportParseError("expected an absolute expression after comma");
return false;
}
return false;
}
- MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName);
+ MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName);
getTargetStreamer().emitDirectiveEnt(*Sym);
CurrentFn = Sym;
return false;
}
- if (!FrameSize->EvaluateAsAbsolute(FrameSizeVal)) {
+ if (!FrameSize->evaluateAsAbsolute(FrameSizeVal)) {
reportParseError("frame size not an absolute expression");
return false;
}
return false;
}
- if (!BitMask->EvaluateAsAbsolute(BitMaskVal)) {
+ if (!BitMask->evaluateAsAbsolute(BitMaskVal)) {
reportParseError("bitmask not an absolute expression");
return false;
}
return false;
}
- if (!FrameOffset->EvaluateAsAbsolute(FrameOffsetVal)) {
+ if (!FrameOffset->evaluateAsAbsolute(FrameOffsetVal)) {
reportParseError("frame offset not an absolute expression");
return false;
}
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);