#include "MCTargetDesc/ARMBaseInfo.h"
#include "MCTargetDesc/ARMAddressingModes.h"
#include "MCTargetDesc/ARMMCExpr.h"
#include "llvm/MC/MCParser/MCAsmLexer.h"
#include "llvm/MC/MCParser/MCAsmParser.h"
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCTargetAsmParser.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
using namespace llvm;
namespace {
class ARMOperand;
enum VectorLaneTy { NoLanes, AllLanes, IndexedLane };
class ARMAsmParser : public MCTargetAsmParser {
MCSubtargetInfo &STI;
MCAsmParser &Parser;
StringMap<unsigned> RegisterReqs;
struct {
ARMCC::CondCodes Cond; unsigned Mask:4;
bool FirstCond;
unsigned CurPosition; } ITState;
bool inITBlock() { return ITState.CurPosition != ~0U;}
void forwardITPosition() {
if (!inITBlock()) return;
unsigned TZ = CountTrailingZeros_32(ITState.Mask);
if (++ITState.CurPosition == 5 - TZ)
ITState.CurPosition = ~0U; }
MCAsmParser &getParser() const { return Parser; }
MCAsmLexer &getLexer() const { return Parser.getLexer(); }
void Warning(SMLoc L, const Twine &Msg) { Parser.Warning(L, Msg); }
bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); }
int tryParseRegister();
bool tryParseRegisterWithWriteBack(SmallVectorImpl<MCParsedAsmOperand*> &);
int tryParseShiftRegister(SmallVectorImpl<MCParsedAsmOperand*> &);
bool parseRegisterList(SmallVectorImpl<MCParsedAsmOperand*> &);
bool parseMemory(SmallVectorImpl<MCParsedAsmOperand*> &);
bool parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &, StringRef Mnemonic);
bool parsePrefix(ARMMCExpr::VariantKind &RefKind);
bool parseMemRegOffsetShift(ARM_AM::ShiftOpc &ShiftType,
unsigned &ShiftAmount);
bool parseDirectiveWord(unsigned Size, SMLoc L);
bool parseDirectiveThumb(SMLoc L);
bool parseDirectiveARM(SMLoc L);
bool parseDirectiveThumbFunc(SMLoc L);
bool parseDirectiveCode(SMLoc L);
bool parseDirectiveSyntax(SMLoc L);
bool parseDirectiveReq(StringRef Name, SMLoc L);
bool parseDirectiveUnreq(SMLoc L);
StringRef splitMnemonic(StringRef Mnemonic, unsigned &PredicationCode,
bool &CarrySetting, unsigned &ProcessorIMod,
StringRef &ITMask);
void getMnemonicAcceptInfo(StringRef Mnemonic, bool &CanAcceptCarrySet,
bool &CanAcceptPredicationCode);
bool isThumb() const {
return (STI.getFeatureBits() & ARM::ModeThumb) != 0;
}
bool isThumbOne() const {
return isThumb() && (STI.getFeatureBits() & ARM::FeatureThumb2) == 0;
}
bool isThumbTwo() const {
return isThumb() && (STI.getFeatureBits() & ARM::FeatureThumb2);
}
bool hasV6Ops() const {
return STI.getFeatureBits() & ARM::HasV6Ops;
}
bool hasV7Ops() const {
return STI.getFeatureBits() & ARM::HasV7Ops;
}
void SwitchMode() {
unsigned FB = ComputeAvailableFeatures(STI.ToggleFeature(ARM::ModeThumb));
setAvailableFeatures(FB);
}
bool isMClass() const {
return STI.getFeatureBits() & ARM::FeatureMClass;
}
#define GET_ASSEMBLER_HEADER
#include "ARMGenAsmMatcher.inc"
OperandMatchResultTy parseITCondCode(SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parseCoprocNumOperand(
SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parseCoprocRegOperand(
SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parseCoprocOptionOperand(
SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parseMemBarrierOptOperand(
SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parseProcIFlagsOperand(
SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parseMSRMaskOperand(
SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parsePKHImm(SmallVectorImpl<MCParsedAsmOperand*> &O,
StringRef Op, int Low, int High);
OperandMatchResultTy parsePKHLSLImm(SmallVectorImpl<MCParsedAsmOperand*> &O) {
return parsePKHImm(O, "lsl", 0, 31);
}
OperandMatchResultTy parsePKHASRImm(SmallVectorImpl<MCParsedAsmOperand*> &O) {
return parsePKHImm(O, "asr", 1, 32);
}
OperandMatchResultTy parseSetEndImm(SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parseShifterImm(SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parseRotImm(SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parseBitfield(SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parsePostIdxReg(SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parseAM3Offset(SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parseFPImm(SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parseVectorList(SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parseVectorLane(VectorLaneTy &LaneKind, unsigned &Index);
bool cvtT2LdrdPre(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtT2StrdPre(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtLdWriteBackRegT2AddrModeImm8(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtStWriteBackRegT2AddrModeImm8(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtLdWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtLdWriteBackRegAddrModeImm12(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtStWriteBackRegAddrModeImm12(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtStWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtStWriteBackRegAddrMode3(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtLdExtTWriteBackImm(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtLdExtTWriteBackReg(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtStExtTWriteBackImm(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtStExtTWriteBackReg(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtLdrdPre(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtStrdPre(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtLdWriteBackRegAddrMode3(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtThumbMultiply(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtVLDwbFixed(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtVLDwbRegister(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtVSTwbFixed(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtVSTwbRegister(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool validateInstruction(MCInst &Inst,
const SmallVectorImpl<MCParsedAsmOperand*> &Ops);
bool processInstruction(MCInst &Inst,
const SmallVectorImpl<MCParsedAsmOperand*> &Ops);
bool shouldOmitCCOutOperand(StringRef Mnemonic,
SmallVectorImpl<MCParsedAsmOperand*> &Operands);
public:
enum ARMMatchResultTy {
Match_RequiresITBlock = FIRST_TARGET_MATCH_RESULT_TY,
Match_RequiresNotITBlock,
Match_RequiresV6,
Match_RequiresThumb2
};
ARMAsmParser(MCSubtargetInfo &_STI, MCAsmParser &_Parser)
: MCTargetAsmParser(), STI(_STI), Parser(_Parser) {
MCAsmParserExtension::Initialize(_Parser);
setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
ITState.CurPosition = ~0U;
}
bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc);
bool ParseInstruction(StringRef Name, SMLoc NameLoc,
SmallVectorImpl<MCParsedAsmOperand*> &Operands);
bool ParseDirective(AsmToken DirectiveID);
unsigned checkTargetMatchPredicate(MCInst &Inst);
bool MatchAndEmitInstruction(SMLoc IDLoc,
SmallVectorImpl<MCParsedAsmOperand*> &Operands,
MCStreamer &Out);
};
}
namespace {
class ARMOperand : public MCParsedAsmOperand {
enum KindTy {
k_CondCode,
k_CCOut,
k_ITCondMask,
k_CoprocNum,
k_CoprocReg,
k_CoprocOption,
k_Immediate,
k_FPImmediate,
k_MemBarrierOpt,
k_Memory,
k_PostIndexRegister,
k_MSRMask,
k_ProcIFlags,
k_VectorIndex,
k_Register,
k_RegisterList,
k_DPRRegisterList,
k_SPRRegisterList,
k_VectorList,
k_VectorListAllLanes,
k_VectorListIndexed,
k_ShiftedRegister,
k_ShiftedImmediate,
k_ShifterImmediate,
k_RotateImmediate,
k_BitfieldDescriptor,
k_Token
} Kind;
SMLoc StartLoc, EndLoc;
SmallVector<unsigned, 8> Registers;
union {
struct {
ARMCC::CondCodes Val;
} CC;
struct {
unsigned Val;
} Cop;
struct {
unsigned Val;
} CoprocOption;
struct {
unsigned Mask:4;
} ITMask;
struct {
ARM_MB::MemBOpt Val;
} MBOpt;
struct {
ARM_PROC::IFlags Val;
} IFlags;
struct {
unsigned Val;
} MMask;
struct {
const char *Data;
unsigned Length;
} Tok;
struct {
unsigned RegNum;
} Reg;
struct {
unsigned RegNum;
unsigned Count;
unsigned LaneIndex;
} VectorList;
struct {
unsigned Val;
} VectorIndex;
struct {
const MCExpr *Val;
} Imm;
struct {
unsigned Val; } FPImm;
struct {
unsigned BaseRegNum;
const MCConstantExpr *OffsetImm; unsigned OffsetRegNum; ARM_AM::ShiftOpc ShiftType; unsigned ShiftImm; unsigned Alignment; unsigned isNegative : 1; } Memory;
struct {
unsigned RegNum;
bool isAdd;
ARM_AM::ShiftOpc ShiftTy;
unsigned ShiftImm;
} PostIdxReg;
struct {
bool isASR;
unsigned Imm;
} ShifterImm;
struct {
ARM_AM::ShiftOpc ShiftTy;
unsigned SrcReg;
unsigned ShiftReg;
unsigned ShiftImm;
} RegShiftedReg;
struct {
ARM_AM::ShiftOpc ShiftTy;
unsigned SrcReg;
unsigned ShiftImm;
} RegShiftedImm;
struct {
unsigned Imm;
} RotImm;
struct {
unsigned LSB;
unsigned Width;
} Bitfield;
};
ARMOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
public:
ARMOperand(const ARMOperand &o) : MCParsedAsmOperand() {
Kind = o.Kind;
StartLoc = o.StartLoc;
EndLoc = o.EndLoc;
switch (Kind) {
case k_CondCode:
CC = o.CC;
break;
case k_ITCondMask:
ITMask = o.ITMask;
break;
case k_Token:
Tok = o.Tok;
break;
case k_CCOut:
case k_Register:
Reg = o.Reg;
break;
case k_RegisterList:
case k_DPRRegisterList:
case k_SPRRegisterList:
Registers = o.Registers;
break;
case k_VectorList:
case k_VectorListAllLanes:
case k_VectorListIndexed:
VectorList = o.VectorList;
break;
case k_CoprocNum:
case k_CoprocReg:
Cop = o.Cop;
break;
case k_CoprocOption:
CoprocOption = o.CoprocOption;
break;
case k_Immediate:
Imm = o.Imm;
break;
case k_FPImmediate:
FPImm = o.FPImm;
break;
case k_MemBarrierOpt:
MBOpt = o.MBOpt;
break;
case k_Memory:
Memory = o.Memory;
break;
case k_PostIndexRegister:
PostIdxReg = o.PostIdxReg;
break;
case k_MSRMask:
MMask = o.MMask;
break;
case k_ProcIFlags:
IFlags = o.IFlags;
break;
case k_ShifterImmediate:
ShifterImm = o.ShifterImm;
break;
case k_ShiftedRegister:
RegShiftedReg = o.RegShiftedReg;
break;
case k_ShiftedImmediate:
RegShiftedImm = o.RegShiftedImm;
break;
case k_RotateImmediate:
RotImm = o.RotImm;
break;
case k_BitfieldDescriptor:
Bitfield = o.Bitfield;
break;
case k_VectorIndex:
VectorIndex = o.VectorIndex;
break;
}
}
SMLoc getStartLoc() const { return StartLoc; }
SMLoc getEndLoc() const { return EndLoc; }
ARMCC::CondCodes getCondCode() const {
assert(Kind == k_CondCode && "Invalid access!");
return CC.Val;
}
unsigned getCoproc() const {
assert((Kind == k_CoprocNum || Kind == k_CoprocReg) && "Invalid access!");
return Cop.Val;
}
StringRef getToken() const {
assert(Kind == k_Token && "Invalid access!");
return StringRef(Tok.Data, Tok.Length);
}
unsigned getReg() const {
assert((Kind == k_Register || Kind == k_CCOut) && "Invalid access!");
return Reg.RegNum;
}
const SmallVectorImpl<unsigned> &getRegList() const {
assert((Kind == k_RegisterList || Kind == k_DPRRegisterList ||
Kind == k_SPRRegisterList) && "Invalid access!");
return Registers;
}
const MCExpr *getImm() const {
assert(Kind == k_Immediate && "Invalid access!");
return Imm.Val;
}
unsigned getFPImm() const {
assert(Kind == k_FPImmediate && "Invalid access!");
return FPImm.Val;
}
unsigned getVectorIndex() const {
assert(Kind == k_VectorIndex && "Invalid access!");
return VectorIndex.Val;
}
ARM_MB::MemBOpt getMemBarrierOpt() const {
assert(Kind == k_MemBarrierOpt && "Invalid access!");
return MBOpt.Val;
}
ARM_PROC::IFlags getProcIFlags() const {
assert(Kind == k_ProcIFlags && "Invalid access!");
return IFlags.Val;
}
unsigned getMSRMask() const {
assert(Kind == k_MSRMask && "Invalid access!");
return MMask.Val;
}
bool isCoprocNum() const { return Kind == k_CoprocNum; }
bool isCoprocReg() const { return Kind == k_CoprocReg; }
bool isCoprocOption() const { return Kind == k_CoprocOption; }
bool isCondCode() const { return Kind == k_CondCode; }
bool isCCOut() const { return Kind == k_CCOut; }
bool isITMask() const { return Kind == k_ITCondMask; }
bool isITCondCode() const { return Kind == k_CondCode; }
bool isImm() const { return Kind == k_Immediate; }
bool isFPImm() const { return Kind == k_FPImmediate; }
bool isImm8s4() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return ((Value & 3) == 0) && Value >= -1020 && Value <= 1020;
}
bool isImm0_1020s4() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return ((Value & 3) == 0) && Value >= 0 && Value <= 1020;
}
bool isImm0_508s4() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return ((Value & 3) == 0) && Value >= 0 && Value <= 508;
}
bool isImm0_255() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value >= 0 && Value < 256;
}
bool isImm0_1() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value >= 0 && Value < 2;
}
bool isImm0_3() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value >= 0 && Value < 4;
}
bool isImm0_7() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value >= 0 && Value < 8;
}
bool isImm0_15() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value >= 0 && Value < 16;
}
bool isImm0_31() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value >= 0 && Value < 32;
}
bool isImm0_63() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value >= 0 && Value < 64;
}
bool isImm8() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value == 8;
}
bool isImm16() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value == 16;
}
bool isImm32() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value == 32;
}
bool isShrImm8() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value > 0 && Value <= 8;
}
bool isShrImm16() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value > 0 && Value <= 16;
}
bool isShrImm32() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value > 0 && Value <= 32;
}
bool isShrImm64() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value > 0 && Value <= 64;
}
bool isImm1_7() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value > 0 && Value < 8;
}
bool isImm1_15() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value > 0 && Value < 16;
}
bool isImm1_31() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value > 0 && Value < 32;
}
bool isImm1_16() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value > 0 && Value < 17;
}
bool isImm1_32() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value > 0 && Value < 33;
}
bool isImm0_32() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value >= 0 && Value < 33;
}
bool isImm0_65535() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value >= 0 && Value < 65536;
}
bool isImm0_65535Expr() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return true;
int64_t Value = CE->getValue();
return Value >= 0 && Value < 65536;
}
bool isImm24bit() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value >= 0 && Value <= 0xffffff;
}
bool isImmThumbSR() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value > 0 && Value < 33;
}
bool isPKHLSLImm() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value >= 0 && Value < 32;
}
bool isPKHASRImm() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value > 0 && Value <= 32;
}
bool isARMSOImm() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return ARM_AM::getSOImmVal(Value) != -1;
}
bool isARMSOImmNot() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return ARM_AM::getSOImmVal(~Value) != -1;
}
bool isARMSOImmNeg() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return ARM_AM::getSOImmVal(-Value) != -1;
}
bool isT2SOImm() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return ARM_AM::getT2SOImmVal(Value) != -1;
}
bool isT2SOImmNot() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return ARM_AM::getT2SOImmVal(~Value) != -1;
}
bool isT2SOImmNeg() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return ARM_AM::getT2SOImmVal(-Value) != -1;
}
bool isSetEndImm() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value == 1 || Value == 0;
}
bool isReg() const { return Kind == k_Register; }
bool isRegList() const { return Kind == k_RegisterList; }
bool isDPRRegList() const { return Kind == k_DPRRegisterList; }
bool isSPRRegList() const { return Kind == k_SPRRegisterList; }
bool isToken() const { return Kind == k_Token; }
bool isMemBarrierOpt() const { return Kind == k_MemBarrierOpt; }
bool isMemory() const { return Kind == k_Memory; }
bool isShifterImm() const { return Kind == k_ShifterImmediate; }
bool isRegShiftedReg() const { return Kind == k_ShiftedRegister; }
bool isRegShiftedImm() const { return Kind == k_ShiftedImmediate; }
bool isRotImm() const { return Kind == k_RotateImmediate; }
bool isBitfield() const { return Kind == k_BitfieldDescriptor; }
bool isPostIdxRegShifted() const { return Kind == k_PostIndexRegister; }
bool isPostIdxReg() const {
return Kind == k_PostIndexRegister && PostIdxReg.ShiftTy ==ARM_AM::no_shift;
}
bool isMemNoOffset(bool alignOK = false) const {
if (!isMemory())
return false;
return Memory.OffsetRegNum == 0 && Memory.OffsetImm == 0 &&
(alignOK || Memory.Alignment == 0);
}
bool isAlignedMemory() const {
return isMemNoOffset(true);
}
bool isAddrMode2() const {
if (!isMemory() || Memory.Alignment != 0) return false;
if (Memory.OffsetRegNum) return true;
if (!Memory.OffsetImm) return true;
int64_t Val = Memory.OffsetImm->getValue();
return Val > -4096 && Val < 4096;
}
bool isAM2OffsetImm() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Val = CE->getValue();
return Val > -4096 && Val < 4096;
}
bool isAddrMode3() const {
if (!isMemory() || Memory.Alignment != 0) return false;
if (Memory.ShiftType != ARM_AM::no_shift) return false;
if (Memory.OffsetRegNum) return true;
if (!Memory.OffsetImm) return true;
int64_t Val = Memory.OffsetImm->getValue();
return Val > -256 && Val < 256;
}
bool isAM3Offset() const {
if (Kind != k_Immediate && Kind != k_PostIndexRegister)
return false;
if (Kind == k_PostIndexRegister)
return PostIdxReg.ShiftTy == ARM_AM::no_shift;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Val = CE->getValue();
return (Val > -256 && Val < 256) || Val == INT32_MIN;
}
bool isAddrMode5() const {
if (Kind == k_Immediate && !isa<MCConstantExpr>(getImm()))
return true;
if (!isMemory() || Memory.Alignment != 0) return false;
if (Memory.OffsetRegNum) return false;
if (!Memory.OffsetImm) return true;
int64_t Val = Memory.OffsetImm->getValue();
return (Val >= -1020 && Val <= 1020 && ((Val & 3) == 0)) ||
Val == INT32_MIN;
}
bool isMemTBB() const {
if (!isMemory() || !Memory.OffsetRegNum || Memory.isNegative ||
Memory.ShiftType != ARM_AM::no_shift || Memory.Alignment != 0)
return false;
return true;
}
bool isMemTBH() const {
if (!isMemory() || !Memory.OffsetRegNum || Memory.isNegative ||
Memory.ShiftType != ARM_AM::lsl || Memory.ShiftImm != 1 ||
Memory.Alignment != 0 )
return false;
return true;
}
bool isMemRegOffset() const {
if (!isMemory() || !Memory.OffsetRegNum || Memory.Alignment != 0)
return false;
return true;
}
bool isT2MemRegOffset() const {
if (!isMemory() || !Memory.OffsetRegNum || Memory.isNegative ||
Memory.Alignment != 0)
return false;
if (Memory.ShiftType == ARM_AM::no_shift)
return true;
if (Memory.ShiftType != ARM_AM::lsl || Memory.ShiftImm > 3)
return false;
return true;
}
bool isMemThumbRR() const {
if (!isMemory() || !Memory.OffsetRegNum || Memory.isNegative ||
Memory.ShiftType != ARM_AM::no_shift || Memory.Alignment != 0)
return false;
return isARMLowRegister(Memory.BaseRegNum) &&
(!Memory.OffsetRegNum || isARMLowRegister(Memory.OffsetRegNum));
}
bool isMemThumbRIs4() const {
if (!isMemory() || Memory.OffsetRegNum != 0 ||
!isARMLowRegister(Memory.BaseRegNum) || Memory.Alignment != 0)
return false;
if (!Memory.OffsetImm) return true;
int64_t Val = Memory.OffsetImm->getValue();
return Val >= 0 && Val <= 124 && (Val % 4) == 0;
}
bool isMemThumbRIs2() const {
if (!isMemory() || Memory.OffsetRegNum != 0 ||
!isARMLowRegister(Memory.BaseRegNum) || Memory.Alignment != 0)
return false;
if (!Memory.OffsetImm) return true;
int64_t Val = Memory.OffsetImm->getValue();
return Val >= 0 && Val <= 62 && (Val % 2) == 0;
}
bool isMemThumbRIs1() const {
if (!isMemory() || Memory.OffsetRegNum != 0 ||
!isARMLowRegister(Memory.BaseRegNum) || Memory.Alignment != 0)
return false;
if (!Memory.OffsetImm) return true;
int64_t Val = Memory.OffsetImm->getValue();
return Val >= 0 && Val <= 31;
}
bool isMemThumbSPI() const {
if (!isMemory() || Memory.OffsetRegNum != 0 ||
Memory.BaseRegNum != ARM::SP || Memory.Alignment != 0)
return false;
if (!Memory.OffsetImm) return true;
int64_t Val = Memory.OffsetImm->getValue();
return Val >= 0 && Val <= 1020 && (Val % 4) == 0;
}
bool isMemImm8s4Offset() const {
if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0)
return false;
if (!Memory.OffsetImm) return true;
int64_t Val = Memory.OffsetImm->getValue();
return Val >= -1020 && Val <= 1020 && (Val & 3) == 0;
}
bool isMemImm0_1020s4Offset() const {
if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0)
return false;
if (!Memory.OffsetImm) return true;
int64_t Val = Memory.OffsetImm->getValue();
return Val >= 0 && Val <= 1020 && (Val & 3) == 0;
}
bool isMemImm8Offset() const {
if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0)
return false;
if (!Memory.OffsetImm) return true;
int64_t Val = Memory.OffsetImm->getValue();
return (Val == INT32_MIN) || (Val > -256 && Val < 256);
}
bool isMemPosImm8Offset() const {
if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0)
return false;
if (!Memory.OffsetImm) return true;
int64_t Val = Memory.OffsetImm->getValue();
return Val >= 0 && Val < 256;
}
bool isMemNegImm8Offset() const {
if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0)
return false;
if (!Memory.OffsetImm) return false;
int64_t Val = Memory.OffsetImm->getValue();
return (Val == INT32_MIN) || (Val > -256 && Val < 0);
}
bool isMemUImm12Offset() const {
if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0)
return false;
if (!Memory.OffsetImm) return true;
int64_t Val = Memory.OffsetImm->getValue();
return (Val >= 0 && Val < 4096);
}
bool isMemImm12Offset() const {
if (Kind == k_Immediate && !isa<MCConstantExpr>(getImm()))
return true;
if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0)
return false;
if (!Memory.OffsetImm) return true;
int64_t Val = Memory.OffsetImm->getValue();
return (Val > -4096 && Val < 4096) || (Val == INT32_MIN);
}
bool isPostIdxImm8() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Val = CE->getValue();
return (Val > -256 && Val < 256) || (Val == INT32_MIN);
}
bool isPostIdxImm8s4() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Val = CE->getValue();
return ((Val & 3) == 0 && Val >= -1020 && Val <= 1020) ||
(Val == INT32_MIN);
}
bool isMSRMask() const { return Kind == k_MSRMask; }
bool isProcIFlags() const { return Kind == k_ProcIFlags; }
bool isVecListOneD() const {
if (Kind != k_VectorList) return false;
return VectorList.Count == 1;
}
bool isVecListTwoD() const {
if (Kind != k_VectorList) return false;
return VectorList.Count == 2;
}
bool isVecListThreeD() const {
if (Kind != k_VectorList) return false;
return VectorList.Count == 3;
}
bool isVecListFourD() const {
if (Kind != k_VectorList) return false;
return VectorList.Count == 4;
}
bool isVecListTwoQ() const {
if (Kind != k_VectorList) return false;
return VectorList.Count == 2 && false;
}
bool isVecListOneDAllLanes() const {
if (Kind != k_VectorListAllLanes) return false;
return VectorList.Count == 1;
}
bool isVecListTwoDAllLanes() const {
if (Kind != k_VectorListAllLanes) return false;
return VectorList.Count == 2;
}
bool isVecListOneDByteIndexed() const {
if (Kind != k_VectorListIndexed) return false;
return VectorList.Count == 1 && VectorList.LaneIndex <= 7;
}
bool isVecListOneDHWordIndexed() const {
if (Kind != k_VectorListIndexed) return false;
return VectorList.Count == 1 && VectorList.LaneIndex <= 3;
}
bool isVecListOneDWordIndexed() const {
if (Kind != k_VectorListIndexed) return false;
return VectorList.Count == 1 && VectorList.LaneIndex <= 1;
}
bool isVecListTwoDByteIndexed() const {
if (Kind != k_VectorListIndexed) return false;
return VectorList.Count == 2 && VectorList.LaneIndex <= 7;
}
bool isVecListTwoDHWordIndexed() const {
if (Kind != k_VectorListIndexed) return false;
return VectorList.Count == 2 && VectorList.LaneIndex <= 3;
}
bool isVecListTwoDWordIndexed() const {
if (Kind != k_VectorListIndexed) return false;
return VectorList.Count == 2 && VectorList.LaneIndex <= 1;
}
bool isVectorIndex8() const {
if (Kind != k_VectorIndex) return false;
return VectorIndex.Val < 8;
}
bool isVectorIndex16() const {
if (Kind != k_VectorIndex) return false;
return VectorIndex.Val < 4;
}
bool isVectorIndex32() const {
if (Kind != k_VectorIndex) return false;
return VectorIndex.Val < 2;
}
bool isNEONi8splat() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value >= 0 && Value < 256;
}
bool isNEONi16splat() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return (Value >= 0 && Value < 256) || (Value >= 0x0100 && Value <= 0xff00);
}
bool isNEONi32splat() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return (Value >= 0 && Value < 256) ||
(Value >= 0x0100 && Value <= 0xff00) ||
(Value >= 0x010000 && Value <= 0xff0000) ||
(Value >= 0x01000000 && Value <= 0xff000000);
}
bool isNEONi32vmov() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return (Value >= 0 && Value < 256) ||
(Value >= 0x0100 && Value <= 0xff00) ||
(Value >= 0x010000 && Value <= 0xff0000) ||
(Value >= 0x01000000 && Value <= 0xff000000) ||
(Value >= 0x01ff && Value <= 0xffff && (Value & 0xff) == 0xff) ||
(Value >= 0x01ffff && Value <= 0xffffff && (Value & 0xffff) == 0xffff);
}
bool isNEONi64splat() const {
if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
uint64_t Value = CE->getValue();
for (unsigned i = 0; i < 8; ++i)
if ((Value & 0xff) != 0 && (Value & 0xff) != 0xff) return false;
return true;
}
void addExpr(MCInst &Inst, const MCExpr *Expr) const {
if (Expr == 0)
Inst.addOperand(MCOperand::CreateImm(0));
else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr))
Inst.addOperand(MCOperand::CreateImm(CE->getValue()));
else
Inst.addOperand(MCOperand::CreateExpr(Expr));
}
void addCondCodeOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateImm(unsigned(getCondCode())));
unsigned RegNum = getCondCode() == ARMCC::AL ? 0: ARM::CPSR;
Inst.addOperand(MCOperand::CreateReg(RegNum));
}
void addCoprocNumOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateImm(getCoproc()));
}
void addCoprocRegOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateImm(getCoproc()));
}
void addCoprocOptionOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateImm(CoprocOption.Val));
}
void addITMaskOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateImm(ITMask.Mask));
}
void addITCondCodeOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateImm(unsigned(getCondCode())));
}
void addCCOutOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateReg(getReg()));
}
void addRegOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateReg(getReg()));
}
void addRegShiftedRegOperands(MCInst &Inst, unsigned N) const {
assert(N == 3 && "Invalid number of operands!");
assert(isRegShiftedReg() &&
"addRegShiftedRegOperands() on non RegShiftedReg!");
Inst.addOperand(MCOperand::CreateReg(RegShiftedReg.SrcReg));
Inst.addOperand(MCOperand::CreateReg(RegShiftedReg.ShiftReg));
Inst.addOperand(MCOperand::CreateImm(
ARM_AM::getSORegOpc(RegShiftedReg.ShiftTy, RegShiftedReg.ShiftImm)));
}
void addRegShiftedImmOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
assert(isRegShiftedImm() &&
"addRegShiftedImmOperands() on non RegShiftedImm!");
Inst.addOperand(MCOperand::CreateReg(RegShiftedImm.SrcReg));
Inst.addOperand(MCOperand::CreateImm(
ARM_AM::getSORegOpc(RegShiftedImm.ShiftTy, RegShiftedImm.ShiftImm)));
}
void addShifterImmOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateImm((ShifterImm.isASR << 5) |
ShifterImm.Imm));
}
void addRegListOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const SmallVectorImpl<unsigned> &RegList = getRegList();
for (SmallVectorImpl<unsigned>::const_iterator
I = RegList.begin(), E = RegList.end(); I != E; ++I)
Inst.addOperand(MCOperand::CreateReg(*I));
}
void addDPRRegListOperands(MCInst &Inst, unsigned N) const {
addRegListOperands(Inst, N);
}
void addSPRRegListOperands(MCInst &Inst, unsigned N) const {
addRegListOperands(Inst, N);
}
void addRotImmOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateImm(RotImm.Imm >> 3));
}
void addBitfieldOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
unsigned lsb = Bitfield.LSB;
unsigned width = Bitfield.Width;
uint32_t Mask = ~(((uint32_t)0xffffffff >> lsb) << (32 - width) >>
(32 - (lsb + width)));
Inst.addOperand(MCOperand::CreateImm(Mask));
}
void addImmOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
addExpr(Inst, getImm());
}
void addFPImmOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateImm(getFPImm()));
}
void addImm8s4Operands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
Inst.addOperand(MCOperand::CreateImm(CE->getValue()));
}
void addImm0_1020s4Operands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
Inst.addOperand(MCOperand::CreateImm(CE->getValue() / 4));
}
void addImm0_508s4Operands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
Inst.addOperand(MCOperand::CreateImm(CE->getValue() / 4));
}
void addImm1_16Operands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
Inst.addOperand(MCOperand::CreateImm(CE->getValue() - 1));
}
void addImm1_32Operands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
Inst.addOperand(MCOperand::CreateImm(CE->getValue() - 1));
}
void addImmThumbSROperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
unsigned Imm = CE->getValue();
Inst.addOperand(MCOperand::CreateImm((Imm == 32 ? 0 : Imm)));
}
void addPKHASRImmOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
int Val = CE->getValue();
Inst.addOperand(MCOperand::CreateImm(Val == 32 ? 0 : Val));
}
void addT2SOImmNotOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
Inst.addOperand(MCOperand::CreateImm(~CE->getValue()));
}
void addT2SOImmNegOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
Inst.addOperand(MCOperand::CreateImm(-CE->getValue()));
}
void addARMSOImmNotOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
Inst.addOperand(MCOperand::CreateImm(~CE->getValue()));
}
void addARMSOImmNegOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
Inst.addOperand(MCOperand::CreateImm(-CE->getValue()));
}
void addMemBarrierOptOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateImm(unsigned(getMemBarrierOpt())));
}
void addMemNoOffsetOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum));
}
void addAlignedMemoryOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum));
Inst.addOperand(MCOperand::CreateImm(Memory.Alignment));
}
void addAddrMode2Operands(MCInst &Inst, unsigned N) const {
assert(N == 3 && "Invalid number of operands!");
int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0;
if (!Memory.OffsetRegNum) {
ARM_AM::AddrOpc AddSub = Val < 0 ? ARM_AM::sub : ARM_AM::add;
if (Val == INT32_MIN) Val = 0;
if (Val < 0) Val = -Val;
Val = ARM_AM::getAM2Opc(AddSub, Val, ARM_AM::no_shift);
} else {
Val = ARM_AM::getAM2Opc(Memory.isNegative ? ARM_AM::sub : ARM_AM::add,
Memory.ShiftImm, Memory.ShiftType);
}
Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum));
Inst.addOperand(MCOperand::CreateReg(Memory.OffsetRegNum));
Inst.addOperand(MCOperand::CreateImm(Val));
}
void addAM2OffsetImmOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
assert(CE && "non-constant AM2OffsetImm operand!");
int32_t Val = CE->getValue();
ARM_AM::AddrOpc AddSub = Val < 0 ? ARM_AM::sub : ARM_AM::add;
if (Val == INT32_MIN) Val = 0;
if (Val < 0) Val = -Val;
Val = ARM_AM::getAM2Opc(AddSub, Val, ARM_AM::no_shift);
Inst.addOperand(MCOperand::CreateReg(0));
Inst.addOperand(MCOperand::CreateImm(Val));
}
void addAddrMode3Operands(MCInst &Inst, unsigned N) const {
assert(N == 3 && "Invalid number of operands!");
int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0;
if (!Memory.OffsetRegNum) {
ARM_AM::AddrOpc AddSub = Val < 0 ? ARM_AM::sub : ARM_AM::add;
if (Val == INT32_MIN) Val = 0;
if (Val < 0) Val = -Val;
Val = ARM_AM::getAM3Opc(AddSub, Val);
} else {
Val = ARM_AM::getAM3Opc(Memory.isNegative ? ARM_AM::sub : ARM_AM::add, 0);
}
Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum));
Inst.addOperand(MCOperand::CreateReg(Memory.OffsetRegNum));
Inst.addOperand(MCOperand::CreateImm(Val));
}
void addAM3OffsetOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
if (Kind == k_PostIndexRegister) {
int32_t Val =
ARM_AM::getAM3Opc(PostIdxReg.isAdd ? ARM_AM::add : ARM_AM::sub, 0);
Inst.addOperand(MCOperand::CreateReg(PostIdxReg.RegNum));
Inst.addOperand(MCOperand::CreateImm(Val));
return;
}
const MCConstantExpr *CE = static_cast<const MCConstantExpr*>(getImm());
int32_t Val = CE->getValue();
ARM_AM::AddrOpc AddSub = Val < 0 ? ARM_AM::sub : ARM_AM::add;
if (Val == INT32_MIN) Val = 0;
if (Val < 0) Val = -Val;
Val = ARM_AM::getAM3Opc(AddSub, Val);
Inst.addOperand(MCOperand::CreateReg(0));
Inst.addOperand(MCOperand::CreateImm(Val));
}
void addAddrMode5Operands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
if (isImm()) {
Inst.addOperand(MCOperand::CreateExpr(getImm()));
Inst.addOperand(MCOperand::CreateImm(0));
return;
}
int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() / 4 : 0;
ARM_AM::AddrOpc AddSub = Val < 0 ? ARM_AM::sub : ARM_AM::add;
if (Val == INT32_MIN) Val = 0;
if (Val < 0) Val = -Val;
Val = ARM_AM::getAM5Opc(AddSub, Val);
Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum));
Inst.addOperand(MCOperand::CreateImm(Val));
}
void addMemImm8s4OffsetOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
int64_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0;
Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum));
Inst.addOperand(MCOperand::CreateImm(Val));
}
void addMemImm0_1020s4OffsetOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() / 4 : 0;
Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum));
Inst.addOperand(MCOperand::CreateImm(Val));
}
void addMemImm8OffsetOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
int64_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0;
Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum));
Inst.addOperand(MCOperand::CreateImm(Val));
}
void addMemPosImm8OffsetOperands(MCInst &Inst, unsigned N) const {
addMemImm8OffsetOperands(Inst, N);
}
void addMemNegImm8OffsetOperands(MCInst &Inst, unsigned N) const {
addMemImm8OffsetOperands(Inst, N);
}
void addMemUImm12OffsetOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
if (Kind == k_Immediate) {
addExpr(Inst, getImm());
Inst.addOperand(MCOperand::CreateImm(0));
return;
}
int64_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0;
Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum));
Inst.addOperand(MCOperand::CreateImm(Val));
}
void addMemImm12OffsetOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
if (Kind == k_Immediate) {
addExpr(Inst, getImm());
Inst.addOperand(MCOperand::CreateImm(0));
return;
}
int64_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0;
Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum));
Inst.addOperand(MCOperand::CreateImm(Val));
}
void addMemTBBOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum));
Inst.addOperand(MCOperand::CreateReg(Memory.OffsetRegNum));
}
void addMemTBHOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum));
Inst.addOperand(MCOperand::CreateReg(Memory.OffsetRegNum));
}
void addMemRegOffsetOperands(MCInst &Inst, unsigned N) const {
assert(N == 3 && "Invalid number of operands!");
unsigned Val =
ARM_AM::getAM2Opc(Memory.isNegative ? ARM_AM::sub : ARM_AM::add,
Memory.ShiftImm, Memory.ShiftType);
Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum));
Inst.addOperand(MCOperand::CreateReg(Memory.OffsetRegNum));
Inst.addOperand(MCOperand::CreateImm(Val));
}
void addT2MemRegOffsetOperands(MCInst &Inst, unsigned N) const {
assert(N == 3 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum));
Inst.addOperand(MCOperand::CreateReg(Memory.OffsetRegNum));
Inst.addOperand(MCOperand::CreateImm(Memory.ShiftImm));
}
void addMemThumbRROperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum));
Inst.addOperand(MCOperand::CreateReg(Memory.OffsetRegNum));
}
void addMemThumbRIs4Operands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
int64_t Val = Memory.OffsetImm ? (Memory.OffsetImm->getValue() / 4) : 0;
Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum));
Inst.addOperand(MCOperand::CreateImm(Val));
}
void addMemThumbRIs2Operands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
int64_t Val = Memory.OffsetImm ? (Memory.OffsetImm->getValue() / 2) : 0;
Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum));
Inst.addOperand(MCOperand::CreateImm(Val));
}
void addMemThumbRIs1Operands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
int64_t Val = Memory.OffsetImm ? (Memory.OffsetImm->getValue()) : 0;
Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum));
Inst.addOperand(MCOperand::CreateImm(Val));
}
void addMemThumbSPIOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
int64_t Val = Memory.OffsetImm ? (Memory.OffsetImm->getValue() / 4) : 0;
Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum));
Inst.addOperand(MCOperand::CreateImm(Val));
}
void addPostIdxImm8Operands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
assert(CE && "non-constant post-idx-imm8 operand!");
int Imm = CE->getValue();
bool isAdd = Imm >= 0;
if (Imm == INT32_MIN) Imm = 0;
Imm = (Imm < 0 ? -Imm : Imm) | (int)isAdd << 8;
Inst.addOperand(MCOperand::CreateImm(Imm));
}
void addPostIdxImm8s4Operands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
assert(CE && "non-constant post-idx-imm8s4 operand!");
int Imm = CE->getValue();
bool isAdd = Imm >= 0;
if (Imm == INT32_MIN) Imm = 0;
Imm = ((Imm < 0 ? -Imm : Imm) / 4) | (int)isAdd << 8;
Inst.addOperand(MCOperand::CreateImm(Imm));
}
void addPostIdxRegOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateReg(PostIdxReg.RegNum));
Inst.addOperand(MCOperand::CreateImm(PostIdxReg.isAdd));
}
void addPostIdxRegShiftedOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateReg(PostIdxReg.RegNum));
ARM_AM::AddrOpc opc = PostIdxReg.isAdd ? ARM_AM::add : ARM_AM::sub;
unsigned Imm = ARM_AM::getAM2Opc(opc, PostIdxReg.ShiftImm,
PostIdxReg.ShiftTy);
Inst.addOperand(MCOperand::CreateImm(Imm));
}
void addMSRMaskOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateImm(unsigned(getMSRMask())));
}
void addProcIFlagsOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateImm(unsigned(getProcIFlags())));
}
void addVecListOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateReg(VectorList.RegNum));
}
void addVecListIndexedOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateReg(VectorList.RegNum));
Inst.addOperand(MCOperand::CreateImm(VectorList.LaneIndex));
}
void addVectorIndex8Operands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateImm(getVectorIndex()));
}
void addVectorIndex16Operands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateImm(getVectorIndex()));
}
void addVectorIndex32Operands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateImm(getVectorIndex()));
}
void addNEONi8splatOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
Inst.addOperand(MCOperand::CreateImm(CE->getValue() | 0xe00));
}
void addNEONi16splatOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
unsigned Value = CE->getValue();
if (Value >= 256)
Value = (Value >> 8) | 0xa00;
else
Value |= 0x800;
Inst.addOperand(MCOperand::CreateImm(Value));
}
void addNEONi32splatOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
unsigned Value = CE->getValue();
if (Value >= 256 && Value <= 0xff00)
Value = (Value >> 8) | 0x200;
else if (Value > 0xffff && Value <= 0xff0000)
Value = (Value >> 16) | 0x400;
else if (Value > 0xffffff)
Value = (Value >> 24) | 0x600;
Inst.addOperand(MCOperand::CreateImm(Value));
}
void addNEONi32vmovOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
unsigned Value = CE->getValue();
if (Value >= 256 && Value <= 0xffff)
Value = (Value >> 8) | ((Value & 0xff) ? 0xc00 : 0x200);
else if (Value > 0xffff && Value <= 0xffffff)
Value = (Value >> 16) | ((Value & 0xff) ? 0xd00 : 0x400);
else if (Value > 0xffffff)
Value = (Value >> 24) | 0x600;
Inst.addOperand(MCOperand::CreateImm(Value));
}
void addNEONi64splatOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
uint64_t Value = CE->getValue();
unsigned Imm = 0;
for (unsigned i = 0; i < 8; ++i, Value >>= 8) {
Imm |= (Value & 1) << i;
}
Inst.addOperand(MCOperand::CreateImm(Imm | 0x1e00));
}
virtual void print(raw_ostream &OS) const;
static ARMOperand *CreateITMask(unsigned Mask, SMLoc S) {
ARMOperand *Op = new ARMOperand(k_ITCondMask);
Op->ITMask.Mask = Mask;
Op->StartLoc = S;
Op->EndLoc = S;
return Op;
}
static ARMOperand *CreateCondCode(ARMCC::CondCodes CC, SMLoc S) {
ARMOperand *Op = new ARMOperand(k_CondCode);
Op->CC.Val = CC;
Op->StartLoc = S;
Op->EndLoc = S;
return Op;
}
static ARMOperand *CreateCoprocNum(unsigned CopVal, SMLoc S) {
ARMOperand *Op = new ARMOperand(k_CoprocNum);
Op->Cop.Val = CopVal;
Op->StartLoc = S;
Op->EndLoc = S;
return Op;
}
static ARMOperand *CreateCoprocReg(unsigned CopVal, SMLoc S) {
ARMOperand *Op = new ARMOperand(k_CoprocReg);
Op->Cop.Val = CopVal;
Op->StartLoc = S;
Op->EndLoc = S;
return Op;
}
static ARMOperand *CreateCoprocOption(unsigned Val, SMLoc S, SMLoc E) {
ARMOperand *Op = new ARMOperand(k_CoprocOption);
Op->Cop.Val = Val;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static ARMOperand *CreateCCOut(unsigned RegNum, SMLoc S) {
ARMOperand *Op = new ARMOperand(k_CCOut);
Op->Reg.RegNum = RegNum;
Op->StartLoc = S;
Op->EndLoc = S;
return Op;
}
static ARMOperand *CreateToken(StringRef Str, SMLoc S) {
ARMOperand *Op = new ARMOperand(k_Token);
Op->Tok.Data = Str.data();
Op->Tok.Length = Str.size();
Op->StartLoc = S;
Op->EndLoc = S;
return Op;
}
static ARMOperand *CreateReg(unsigned RegNum, SMLoc S, SMLoc E) {
ARMOperand *Op = new ARMOperand(k_Register);
Op->Reg.RegNum = RegNum;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static ARMOperand *CreateShiftedRegister(ARM_AM::ShiftOpc ShTy,
unsigned SrcReg,
unsigned ShiftReg,
unsigned ShiftImm,
SMLoc S, SMLoc E) {
ARMOperand *Op = new ARMOperand(k_ShiftedRegister);
Op->RegShiftedReg.ShiftTy = ShTy;
Op->RegShiftedReg.SrcReg = SrcReg;
Op->RegShiftedReg.ShiftReg = ShiftReg;
Op->RegShiftedReg.ShiftImm = ShiftImm;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static ARMOperand *CreateShiftedImmediate(ARM_AM::ShiftOpc ShTy,
unsigned SrcReg,
unsigned ShiftImm,
SMLoc S, SMLoc E) {
ARMOperand *Op = new ARMOperand(k_ShiftedImmediate);
Op->RegShiftedImm.ShiftTy = ShTy;
Op->RegShiftedImm.SrcReg = SrcReg;
Op->RegShiftedImm.ShiftImm = ShiftImm;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static ARMOperand *CreateShifterImm(bool isASR, unsigned Imm,
SMLoc S, SMLoc E) {
ARMOperand *Op = new ARMOperand(k_ShifterImmediate);
Op->ShifterImm.isASR = isASR;
Op->ShifterImm.Imm = Imm;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static ARMOperand *CreateRotImm(unsigned Imm, SMLoc S, SMLoc E) {
ARMOperand *Op = new ARMOperand(k_RotateImmediate);
Op->RotImm.Imm = Imm;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static ARMOperand *CreateBitfield(unsigned LSB, unsigned Width,
SMLoc S, SMLoc E) {
ARMOperand *Op = new ARMOperand(k_BitfieldDescriptor);
Op->Bitfield.LSB = LSB;
Op->Bitfield.Width = Width;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static ARMOperand *
CreateRegList(const SmallVectorImpl<std::pair<unsigned, SMLoc> > &Regs,
SMLoc StartLoc, SMLoc EndLoc) {
KindTy Kind = k_RegisterList;
if (ARMMCRegisterClasses[ARM::DPRRegClassID].contains(Regs.front().first))
Kind = k_DPRRegisterList;
else if (ARMMCRegisterClasses[ARM::SPRRegClassID].
contains(Regs.front().first))
Kind = k_SPRRegisterList;
ARMOperand *Op = new ARMOperand(Kind);
for (SmallVectorImpl<std::pair<unsigned, SMLoc> >::const_iterator
I = Regs.begin(), E = Regs.end(); I != E; ++I)
Op->Registers.push_back(I->first);
array_pod_sort(Op->Registers.begin(), Op->Registers.end());
Op->StartLoc = StartLoc;
Op->EndLoc = EndLoc;
return Op;
}
static ARMOperand *CreateVectorList(unsigned RegNum, unsigned Count,
SMLoc S, SMLoc E) {
ARMOperand *Op = new ARMOperand(k_VectorList);
Op->VectorList.RegNum = RegNum;
Op->VectorList.Count = Count;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static ARMOperand *CreateVectorListAllLanes(unsigned RegNum, unsigned Count,
SMLoc S, SMLoc E) {
ARMOperand *Op = new ARMOperand(k_VectorListAllLanes);
Op->VectorList.RegNum = RegNum;
Op->VectorList.Count = Count;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static ARMOperand *CreateVectorListIndexed(unsigned RegNum, unsigned Count,
unsigned Index, SMLoc S, SMLoc E) {
ARMOperand *Op = new ARMOperand(k_VectorListIndexed);
Op->VectorList.RegNum = RegNum;
Op->VectorList.Count = Count;
Op->VectorList.LaneIndex = Index;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static ARMOperand *CreateVectorIndex(unsigned Idx, SMLoc S, SMLoc E,
MCContext &Ctx) {
ARMOperand *Op = new ARMOperand(k_VectorIndex);
Op->VectorIndex.Val = Idx;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static ARMOperand *CreateImm(const MCExpr *Val, SMLoc S, SMLoc E) {
ARMOperand *Op = new ARMOperand(k_Immediate);
Op->Imm.Val = Val;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static ARMOperand *CreateFPImm(unsigned Val, SMLoc S, MCContext &Ctx) {
ARMOperand *Op = new ARMOperand(k_FPImmediate);
Op->FPImm.Val = Val;
Op->StartLoc = S;
Op->EndLoc = S;
return Op;
}
static ARMOperand *CreateMem(unsigned BaseRegNum,
const MCConstantExpr *OffsetImm,
unsigned OffsetRegNum,
ARM_AM::ShiftOpc ShiftType,
unsigned ShiftImm,
unsigned Alignment,
bool isNegative,
SMLoc S, SMLoc E) {
ARMOperand *Op = new ARMOperand(k_Memory);
Op->Memory.BaseRegNum = BaseRegNum;
Op->Memory.OffsetImm = OffsetImm;
Op->Memory.OffsetRegNum = OffsetRegNum;
Op->Memory.ShiftType = ShiftType;
Op->Memory.ShiftImm = ShiftImm;
Op->Memory.Alignment = Alignment;
Op->Memory.isNegative = isNegative;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static ARMOperand *CreatePostIdxReg(unsigned RegNum, bool isAdd,
ARM_AM::ShiftOpc ShiftTy,
unsigned ShiftImm,
SMLoc S, SMLoc E) {
ARMOperand *Op = new ARMOperand(k_PostIndexRegister);
Op->PostIdxReg.RegNum = RegNum;
Op->PostIdxReg.isAdd = isAdd;
Op->PostIdxReg.ShiftTy = ShiftTy;
Op->PostIdxReg.ShiftImm = ShiftImm;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static ARMOperand *CreateMemBarrierOpt(ARM_MB::MemBOpt Opt, SMLoc S) {
ARMOperand *Op = new ARMOperand(k_MemBarrierOpt);
Op->MBOpt.Val = Opt;
Op->StartLoc = S;
Op->EndLoc = S;
return Op;
}
static ARMOperand *CreateProcIFlags(ARM_PROC::IFlags IFlags, SMLoc S) {
ARMOperand *Op = new ARMOperand(k_ProcIFlags);
Op->IFlags.Val = IFlags;
Op->StartLoc = S;
Op->EndLoc = S;
return Op;
}
static ARMOperand *CreateMSRMask(unsigned MMask, SMLoc S) {
ARMOperand *Op = new ARMOperand(k_MSRMask);
Op->MMask.Val = MMask;
Op->StartLoc = S;
Op->EndLoc = S;
return Op;
}
};
}
void ARMOperand::print(raw_ostream &OS) const {
switch (Kind) {
case k_FPImmediate:
OS << "<fpimm " << getFPImm() << "(" << ARM_AM::getFPImmFloat(getFPImm())
<< ") >";
break;
case k_CondCode:
OS << "<ARMCC::" << ARMCondCodeToString(getCondCode()) << ">";
break;
case k_CCOut:
OS << "<ccout " << getReg() << ">";
break;
case k_ITCondMask: {
static const char *MaskStr[] = {
"()", "(t)", "(e)", "(tt)", "(et)", "(te)", "(ee)", "(ttt)", "(ett)",
"(tet)", "(eet)", "(tte)", "(ete)", "(tee)", "(eee)"
};
assert((ITMask.Mask & 0xf) == ITMask.Mask);
OS << "<it-mask " << MaskStr[ITMask.Mask] << ">";
break;
}
case k_CoprocNum:
OS << "<coprocessor number: " << getCoproc() << ">";
break;
case k_CoprocReg:
OS << "<coprocessor register: " << getCoproc() << ">";
break;
case k_CoprocOption:
OS << "<coprocessor option: " << CoprocOption.Val << ">";
break;
case k_MSRMask:
OS << "<mask: " << getMSRMask() << ">";
break;
case k_Immediate:
getImm()->print(OS);
break;
case k_MemBarrierOpt:
OS << "<ARM_MB::" << MemBOptToString(getMemBarrierOpt()) << ">";
break;
case k_Memory:
OS << "<memory "
<< " base:" << Memory.BaseRegNum;
OS << ">";
break;
case k_PostIndexRegister:
OS << "post-idx register " << (PostIdxReg.isAdd ? "" : "-")
<< PostIdxReg.RegNum;
if (PostIdxReg.ShiftTy != ARM_AM::no_shift)
OS << ARM_AM::getShiftOpcStr(PostIdxReg.ShiftTy) << " "
<< PostIdxReg.ShiftImm;
OS << ">";
break;
case k_ProcIFlags: {
OS << "<ARM_PROC::";
unsigned IFlags = getProcIFlags();
for (int i=2; i >= 0; --i)
if (IFlags & (1 << i))
OS << ARM_PROC::IFlagsToString(1 << i);
OS << ">";
break;
}
case k_Register:
OS << "<register " << getReg() << ">";
break;
case k_ShifterImmediate:
OS << "<shift " << (ShifterImm.isASR ? "asr" : "lsl")
<< " #" << ShifterImm.Imm << ">";
break;
case k_ShiftedRegister:
OS << "<so_reg_reg "
<< RegShiftedReg.SrcReg << " "
<< ARM_AM::getShiftOpcStr(RegShiftedReg.ShiftTy)
<< " " << RegShiftedReg.ShiftReg << ">";
break;
case k_ShiftedImmediate:
OS << "<so_reg_imm "
<< RegShiftedImm.SrcReg << " "
<< ARM_AM::getShiftOpcStr(RegShiftedImm.ShiftTy)
<< " #" << RegShiftedImm.ShiftImm << ">";
break;
case k_RotateImmediate:
OS << "<ror " << " #" << (RotImm.Imm * 8) << ">";
break;
case k_BitfieldDescriptor:
OS << "<bitfield " << "lsb: " << Bitfield.LSB
<< ", width: " << Bitfield.Width << ">";
break;
case k_RegisterList:
case k_DPRRegisterList:
case k_SPRRegisterList: {
OS << "<register_list ";
const SmallVectorImpl<unsigned> &RegList = getRegList();
for (SmallVectorImpl<unsigned>::const_iterator
I = RegList.begin(), E = RegList.end(); I != E; ) {
OS << *I;
if (++I < E) OS << ", ";
}
OS << ">";
break;
}
case k_VectorList:
OS << "<vector_list " << VectorList.Count << " * "
<< VectorList.RegNum << ">";
break;
case k_VectorListAllLanes:
OS << "<vector_list(all lanes) " << VectorList.Count << " * "
<< VectorList.RegNum << ">";
break;
case k_VectorListIndexed:
OS << "<vector_list(lane " << VectorList.LaneIndex << ") "
<< VectorList.Count << " * " << VectorList.RegNum << ">";
break;
case k_Token:
OS << "'" << getToken() << "'";
break;
case k_VectorIndex:
OS << "<vectorindex " << getVectorIndex() << ">";
break;
}
}
static unsigned MatchRegisterName(StringRef Name);
bool ARMAsmParser::ParseRegister(unsigned &RegNo,
SMLoc &StartLoc, SMLoc &EndLoc) {
StartLoc = Parser.getTok().getLoc();
RegNo = tryParseRegister();
EndLoc = Parser.getTok().getLoc();
return (RegNo == (unsigned)-1);
}
int ARMAsmParser::tryParseRegister() {
const AsmToken &Tok = Parser.getTok();
if (Tok.isNot(AsmToken::Identifier)) return -1;
std::string lowerCase = Tok.getString().lower();
unsigned RegNum = MatchRegisterName(lowerCase);
if (!RegNum) {
RegNum = StringSwitch<unsigned>(lowerCase)
.Case("r13", ARM::SP)
.Case("r14", ARM::LR)
.Case("r15", ARM::PC)
.Case("ip", ARM::R12)
.Case("a1", ARM::R0)
.Case("a2", ARM::R1)
.Case("a3", ARM::R2)
.Case("a4", ARM::R3)
.Case("v1", ARM::R4)
.Case("v2", ARM::R5)
.Case("v3", ARM::R6)
.Case("v4", ARM::R7)
.Case("v5", ARM::R8)
.Case("v6", ARM::R9)
.Case("v7", ARM::R10)
.Case("v8", ARM::R11)
.Case("sb", ARM::R9)
.Case("sl", ARM::R10)
.Case("fp", ARM::R11)
.Default(0);
}
if (!RegNum) {
StringMap<unsigned>::const_iterator Entry =
RegisterReqs.find(Tok.getIdentifier());
if (Entry == RegisterReqs.end())
return -1;
Parser.Lex(); return Entry->getValue();
}
Parser.Lex();
return RegNum;
}
int ARMAsmParser::tryParseShiftRegister(
SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
SMLoc S = Parser.getTok().getLoc();
const AsmToken &Tok = Parser.getTok();
assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier");
std::string lowerCase = Tok.getString().lower();
ARM_AM::ShiftOpc ShiftTy = StringSwitch<ARM_AM::ShiftOpc>(lowerCase)
.Case("asl", ARM_AM::lsl)
.Case("lsl", ARM_AM::lsl)
.Case("lsr", ARM_AM::lsr)
.Case("asr", ARM_AM::asr)
.Case("ror", ARM_AM::ror)
.Case("rrx", ARM_AM::rrx)
.Default(ARM_AM::no_shift);
if (ShiftTy == ARM_AM::no_shift)
return 1;
Parser.Lex();
OwningPtr<ARMOperand> PrevOp((ARMOperand*)Operands.pop_back_val());
if (!PrevOp->isReg())
return Error(PrevOp->getStartLoc(), "shift must be of a register");
int SrcReg = PrevOp->getReg();
int64_t Imm = 0;
int ShiftReg = 0;
if (ShiftTy == ARM_AM::rrx) {
ShiftReg = SrcReg;
} else {
if (Parser.getTok().is(AsmToken::Hash) ||
Parser.getTok().is(AsmToken::Dollar)) {
Parser.Lex(); SMLoc ImmLoc = Parser.getTok().getLoc();
const MCExpr *ShiftExpr = 0;
if (getParser().ParseExpression(ShiftExpr)) {
Error(ImmLoc, "invalid immediate shift value");
return -1;
}
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(ShiftExpr);
if (!CE) {
Error(ImmLoc, "invalid immediate shift value");
return -1;
}
Imm = CE->getValue();
if (Imm < 0 ||
((ShiftTy == ARM_AM::lsl || ShiftTy == ARM_AM::ror) && Imm > 31) ||
((ShiftTy == ARM_AM::lsr || ShiftTy == ARM_AM::asr) && Imm > 32)) {
Error(ImmLoc, "immediate shift value out of range");
return -1;
}
} else if (Parser.getTok().is(AsmToken::Identifier)) {
ShiftReg = tryParseRegister();
SMLoc L = Parser.getTok().getLoc();
if (ShiftReg == -1) {
Error (L, "expected immediate or register in shift operand");
return -1;
}
} else {
Error (Parser.getTok().getLoc(),
"expected immediate or register in shift operand");
return -1;
}
}
if (ShiftReg && ShiftTy != ARM_AM::rrx)
Operands.push_back(ARMOperand::CreateShiftedRegister(ShiftTy, SrcReg,
ShiftReg, Imm,
S, Parser.getTok().getLoc()));
else
Operands.push_back(ARMOperand::CreateShiftedImmediate(ShiftTy, SrcReg, Imm,
S, Parser.getTok().getLoc()));
return 0;
}
bool ARMAsmParser::
tryParseRegisterWithWriteBack(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
SMLoc S = Parser.getTok().getLoc();
int RegNo = tryParseRegister();
if (RegNo == -1)
return true;
Operands.push_back(ARMOperand::CreateReg(RegNo, S, Parser.getTok().getLoc()));
const AsmToken &ExclaimTok = Parser.getTok();
if (ExclaimTok.is(AsmToken::Exclaim)) {
Operands.push_back(ARMOperand::CreateToken(ExclaimTok.getString(),
ExclaimTok.getLoc()));
Parser.Lex(); return false;
}
if (Parser.getTok().is(AsmToken::LBrac)) {
SMLoc SIdx = Parser.getTok().getLoc();
Parser.Lex();
const MCExpr *ImmVal;
if (getParser().ParseExpression(ImmVal))
return MatchOperand_ParseFail;
const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal);
if (!MCE) {
TokError("immediate value expected for vector index");
return MatchOperand_ParseFail;
}
SMLoc E = Parser.getTok().getLoc();
if (Parser.getTok().isNot(AsmToken::RBrac)) {
Error(E, "']' expected");
return MatchOperand_ParseFail;
}
Parser.Lex();
Operands.push_back(ARMOperand::CreateVectorIndex(MCE->getValue(),
SIdx, E,
getContext()));
}
return false;
}
static int MatchCoprocessorOperandName(StringRef Name, char CoprocOp) {
switch (Name.size()) {
default: break;
case 2:
if (Name[0] != CoprocOp)
return -1;
switch (Name[1]) {
default: return -1;
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
}
break;
case 3:
if (Name[0] != CoprocOp || Name[1] != '1')
return -1;
switch (Name[2]) {
default: return -1;
case '0': return 10;
case '1': return 11;
case '2': return 12;
case '3': return 13;
case '4': return 14;
case '5': return 15;
}
break;
}
return -1;
}
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
parseITCondCode(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
SMLoc S = Parser.getTok().getLoc();
const AsmToken &Tok = Parser.getTok();
if (!Tok.is(AsmToken::Identifier))
return MatchOperand_NoMatch;
unsigned CC = StringSwitch<unsigned>(Tok.getString())
.Case("eq", ARMCC::EQ)
.Case("ne", ARMCC::NE)
.Case("hs", ARMCC::HS)
.Case("cs", ARMCC::HS)
.Case("lo", ARMCC::LO)
.Case("cc", ARMCC::LO)
.Case("mi", ARMCC::MI)
.Case("pl", ARMCC::PL)
.Case("vs", ARMCC::VS)
.Case("vc", ARMCC::VC)
.Case("hi", ARMCC::HI)
.Case("ls", ARMCC::LS)
.Case("ge", ARMCC::GE)
.Case("lt", ARMCC::LT)
.Case("gt", ARMCC::GT)
.Case("le", ARMCC::LE)
.Case("al", ARMCC::AL)
.Default(~0U);
if (CC == ~0U)
return MatchOperand_NoMatch;
Parser.Lex();
Operands.push_back(ARMOperand::CreateCondCode(ARMCC::CondCodes(CC), S));
return MatchOperand_Success;
}
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
parseCoprocNumOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
SMLoc S = Parser.getTok().getLoc();
const AsmToken &Tok = Parser.getTok();
if (Tok.isNot(AsmToken::Identifier))
return MatchOperand_NoMatch;
int Num = MatchCoprocessorOperandName(Tok.getString(), 'p');
if (Num == -1)
return MatchOperand_NoMatch;
Parser.Lex(); Operands.push_back(ARMOperand::CreateCoprocNum(Num, S));
return MatchOperand_Success;
}
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
parseCoprocRegOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
SMLoc S = Parser.getTok().getLoc();
const AsmToken &Tok = Parser.getTok();
if (Tok.isNot(AsmToken::Identifier))
return MatchOperand_NoMatch;
int Reg = MatchCoprocessorOperandName(Tok.getString(), 'c');
if (Reg == -1)
return MatchOperand_NoMatch;
Parser.Lex(); Operands.push_back(ARMOperand::CreateCoprocReg(Reg, S));
return MatchOperand_Success;
}
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
parseCoprocOptionOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
SMLoc S = Parser.getTok().getLoc();
if (Parser.getTok().isNot(AsmToken::LCurly))
return MatchOperand_NoMatch;
Parser.Lex();
const MCExpr *Expr;
SMLoc Loc = Parser.getTok().getLoc();
if (getParser().ParseExpression(Expr)) {
Error(Loc, "illegal expression");
return MatchOperand_ParseFail;
}
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr);
if (!CE || CE->getValue() < 0 || CE->getValue() > 255) {
Error(Loc, "coprocessor option must be an immediate in range [0, 255]");
return MatchOperand_ParseFail;
}
int Val = CE->getValue();
if (Parser.getTok().isNot(AsmToken::RCurly))
return MatchOperand_ParseFail;
SMLoc E = Parser.getTok().getLoc();
Parser.Lex();
Operands.push_back(ARMOperand::CreateCoprocOption(Val, S, E));
return MatchOperand_Success;
}
static unsigned getNextRegister(unsigned Reg) {
if (!ARMMCRegisterClasses[ARM::GPRRegClassID].contains(Reg))
return Reg + 1;
switch(Reg) {
default: assert(0 && "Invalid GPR number!");
case ARM::R0: return ARM::R1; case ARM::R1: return ARM::R2;
case ARM::R2: return ARM::R3; case ARM::R3: return ARM::R4;
case ARM::R4: return ARM::R5; case ARM::R5: return ARM::R6;
case ARM::R6: return ARM::R7; case ARM::R7: return ARM::R8;
case ARM::R8: return ARM::R9; case ARM::R9: return ARM::R10;
case ARM::R10: return ARM::R11; case ARM::R11: return ARM::R12;
case ARM::R12: return ARM::SP; case ARM::SP: return ARM::LR;
case ARM::LR: return ARM::PC; case ARM::PC: return ARM::R0;
}
}
static unsigned getDRegFromQReg(unsigned QReg) {
switch (QReg) {
default: llvm_unreachable("expected a Q register!");
case ARM::Q0: return ARM::D0;
case ARM::Q1: return ARM::D2;
case ARM::Q2: return ARM::D4;
case ARM::Q3: return ARM::D6;
case ARM::Q4: return ARM::D8;
case ARM::Q5: return ARM::D10;
case ARM::Q6: return ARM::D12;
case ARM::Q7: return ARM::D14;
case ARM::Q8: return ARM::D16;
case ARM::Q9: return ARM::D18;
case ARM::Q10: return ARM::D20;
case ARM::Q11: return ARM::D22;
case ARM::Q12: return ARM::D24;
case ARM::Q13: return ARM::D26;
case ARM::Q14: return ARM::D28;
case ARM::Q15: return ARM::D30;
}
}
bool ARMAsmParser::
parseRegisterList(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
assert(Parser.getTok().is(AsmToken::LCurly) &&
"Token is not a Left Curly Brace");
SMLoc S = Parser.getTok().getLoc();
Parser.Lex(); SMLoc RegLoc = Parser.getTok().getLoc();
int Reg = tryParseRegister();
if (Reg == -1)
return Error(RegLoc, "register expected");
SmallVector<std::pair<unsigned, SMLoc>, 16> Registers;
if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(Reg)) {
Reg = getDRegFromQReg(Reg);
Registers.push_back(std::pair<unsigned, SMLoc>(Reg, RegLoc));
++Reg;
}
const MCRegisterClass *RC;
if (ARMMCRegisterClasses[ARM::GPRRegClassID].contains(Reg))
RC = &ARMMCRegisterClasses[ARM::GPRRegClassID];
else if (ARMMCRegisterClasses[ARM::DPRRegClassID].contains(Reg))
RC = &ARMMCRegisterClasses[ARM::DPRRegClassID];
else if (ARMMCRegisterClasses[ARM::SPRRegClassID].contains(Reg))
RC = &ARMMCRegisterClasses[ARM::SPRRegClassID];
else
return Error(RegLoc, "invalid register in register list");
Registers.push_back(std::pair<unsigned, SMLoc>(Reg, RegLoc));
while (Parser.getTok().is(AsmToken::Comma) ||
Parser.getTok().is(AsmToken::Minus)) {
if (Parser.getTok().is(AsmToken::Minus)) {
Parser.Lex(); SMLoc EndLoc = Parser.getTok().getLoc();
int EndReg = tryParseRegister();
if (EndReg == -1)
return Error(EndLoc, "register expected");
if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(EndReg))
EndReg = getDRegFromQReg(EndReg) + 1;
if (Reg == EndReg)
continue;
if (!RC->contains(EndReg))
return Error(EndLoc, "invalid register in register list");
if (getARMRegisterNumbering(Reg) > getARMRegisterNumbering(EndReg))
return Error(EndLoc, "bad range in register list");
while (Reg != EndReg) {
Reg = getNextRegister(Reg);
Registers.push_back(std::pair<unsigned, SMLoc>(Reg, RegLoc));
}
continue;
}
Parser.Lex(); RegLoc = Parser.getTok().getLoc();
int OldReg = Reg;
const AsmToken RegTok = Parser.getTok();
Reg = tryParseRegister();
if (Reg == -1)
return Error(RegLoc, "register expected");
bool isQReg = false;
if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(Reg)) {
Reg = getDRegFromQReg(Reg);
isQReg = true;
}
if (!RC->contains(Reg))
return Error(RegLoc, "invalid register in register list");
if (getARMRegisterNumbering(Reg) < getARMRegisterNumbering(OldReg))
return Error(RegLoc, "register list not in ascending order");
if (getARMRegisterNumbering(Reg) == getARMRegisterNumbering(OldReg)) {
Warning(RegLoc, "duplicated register (" + RegTok.getString() +
") in register list");
continue;
}
if (RC != &ARMMCRegisterClasses[ARM::GPRRegClassID] &&
Reg != OldReg + 1)
return Error(RegLoc, "non-contiguous register range");
Registers.push_back(std::pair<unsigned, SMLoc>(Reg, RegLoc));
if (isQReg)
Registers.push_back(std::pair<unsigned, SMLoc>(++Reg, RegLoc));
}
SMLoc E = Parser.getTok().getLoc();
if (Parser.getTok().isNot(AsmToken::RCurly))
return Error(E, "'}' expected");
Parser.Lex();
Operands.push_back(ARMOperand::CreateRegList(Registers, S, E));
if (Parser.getTok().is(AsmToken::Caret)) {
Operands.push_back(ARMOperand::CreateToken("^",Parser.getTok().getLoc()));
Parser.Lex(); }
return false;
}
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
parseVectorLane(VectorLaneTy &LaneKind, unsigned &Index) {
Index = 0; if (Parser.getTok().is(AsmToken::LBrac)) {
Parser.Lex(); if (Parser.getTok().is(AsmToken::RBrac)) {
LaneKind = AllLanes;
Parser.Lex(); return MatchOperand_Success;
}
if (Parser.getTok().is(AsmToken::Integer)) {
int64_t Val = Parser.getTok().getIntVal();
if (Val < 0 && Val > 7)
Error(Parser.getTok().getLoc(), "lane index out of range");
Index = Val;
LaneKind = IndexedLane;
Parser.Lex(); if (Parser.getTok().isNot(AsmToken::RBrac))
Error(Parser.getTok().getLoc(), "']' expected");
Parser.Lex(); return MatchOperand_Success;
}
Error(Parser.getTok().getLoc(), "lane index must be empty or an integer");
return MatchOperand_ParseFail;
}
LaneKind = NoLanes;
return MatchOperand_Success;
}
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
parseVectorList(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
VectorLaneTy LaneKind;
unsigned LaneIndex;
SMLoc S = Parser.getTok().getLoc();
if (Parser.getTok().is(AsmToken::Identifier)) {
int Reg = tryParseRegister();
if (Reg == -1)
return MatchOperand_NoMatch;
SMLoc E = Parser.getTok().getLoc();
if (ARMMCRegisterClasses[ARM::DPRRegClassID].contains(Reg)) {
OperandMatchResultTy Res = parseVectorLane(LaneKind, LaneIndex);
if (Res != MatchOperand_Success)
return Res;
switch (LaneKind) {
default:
assert(0 && "unexpected lane kind!");
case NoLanes:
E = Parser.getTok().getLoc();
Operands.push_back(ARMOperand::CreateVectorList(Reg, 1, S, E));
break;
case AllLanes:
E = Parser.getTok().getLoc();
Operands.push_back(ARMOperand::CreateVectorListAllLanes(Reg, 1, S, E));
break;
case IndexedLane:
Operands.push_back(ARMOperand::CreateVectorListIndexed(Reg, 1,
LaneIndex, S,E));
break;
}
return MatchOperand_Success;
}
if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(Reg)) {
Reg = getDRegFromQReg(Reg);
OperandMatchResultTy Res = parseVectorLane(LaneKind, LaneIndex);
if (Res != MatchOperand_Success)
return Res;
switch (LaneKind) {
default:
assert(0 && "unexpected lane kind!");
case NoLanes:
E = Parser.getTok().getLoc();
Operands.push_back(ARMOperand::CreateVectorList(Reg, 2, S, E));
break;
case AllLanes:
E = Parser.getTok().getLoc();
Operands.push_back(ARMOperand::CreateVectorListAllLanes(Reg, 2, S, E));
break;
case IndexedLane:
Operands.push_back(ARMOperand::CreateVectorListIndexed(Reg, 2,
LaneIndex, S,E));
break;
}
return MatchOperand_Success;
}
Error(S, "vector register expected");
return MatchOperand_ParseFail;
}
if (Parser.getTok().isNot(AsmToken::LCurly))
return MatchOperand_NoMatch;
Parser.Lex(); SMLoc RegLoc = Parser.getTok().getLoc();
int Reg = tryParseRegister();
if (Reg == -1) {
Error(RegLoc, "register expected");
return MatchOperand_ParseFail;
}
unsigned Count = 1;
unsigned FirstReg = Reg;
if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(Reg)) {
FirstReg = Reg = getDRegFromQReg(Reg);
++Reg;
++Count;
}
if (parseVectorLane(LaneKind, LaneIndex) != MatchOperand_Success)
return MatchOperand_ParseFail;
while (Parser.getTok().is(AsmToken::Comma) ||
Parser.getTok().is(AsmToken::Minus)) {
if (Parser.getTok().is(AsmToken::Minus)) {
Parser.Lex(); SMLoc EndLoc = Parser.getTok().getLoc();
int EndReg = tryParseRegister();
if (EndReg == -1) {
Error(EndLoc, "register expected");
return MatchOperand_ParseFail;
}
if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(EndReg))
EndReg = getDRegFromQReg(EndReg) + 1;
if (Reg == EndReg)
continue;
if (!ARMMCRegisterClasses[ARM::DPRRegClassID].contains(EndReg)) {
Error(EndLoc, "invalid register in register list");
return MatchOperand_ParseFail;
}
if (Reg > EndReg) {
Error(EndLoc, "bad range in register list");
return MatchOperand_ParseFail;
}
VectorLaneTy NextLaneKind;
unsigned NextLaneIndex;
if (parseVectorLane(NextLaneKind, NextLaneIndex) != MatchOperand_Success)
return MatchOperand_ParseFail;
if (NextLaneKind != LaneKind || LaneIndex != NextLaneIndex) {
Error(EndLoc, "mismatched lane index in register list");
return MatchOperand_ParseFail;
}
EndLoc = Parser.getTok().getLoc();
Count += EndReg - Reg;
Reg = EndReg;
continue;
}
Parser.Lex(); RegLoc = Parser.getTok().getLoc();
int OldReg = Reg;
Reg = tryParseRegister();
if (Reg == -1) {
Error(RegLoc, "register expected");
return MatchOperand_ParseFail;
}
if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(Reg)) {
Reg = getDRegFromQReg(Reg);
if (Reg != OldReg + 1) {
Error(RegLoc, "non-contiguous register range");
return MatchOperand_ParseFail;
}
++Reg;
Count += 2;
VectorLaneTy NextLaneKind;
unsigned NextLaneIndex;
SMLoc EndLoc = Parser.getTok().getLoc();
if (parseVectorLane(NextLaneKind, NextLaneIndex) != MatchOperand_Success)
return MatchOperand_ParseFail;
if (NextLaneKind != LaneKind || LaneIndex != NextLaneIndex) {
Error(EndLoc, "mismatched lane index in register list");
return MatchOperand_ParseFail;
}
continue;
}
if (Reg != OldReg + 1) {
Error(RegLoc, "non-contiguous register range");
return MatchOperand_ParseFail;
}
++Count;
VectorLaneTy NextLaneKind;
unsigned NextLaneIndex;
SMLoc EndLoc = Parser.getTok().getLoc();
if (parseVectorLane(NextLaneKind, NextLaneIndex) != MatchOperand_Success)
return MatchOperand_ParseFail;
if (NextLaneKind != LaneKind || LaneIndex != NextLaneIndex) {
Error(EndLoc, "mismatched lane index in register list");
return MatchOperand_ParseFail;
}
}
SMLoc E = Parser.getTok().getLoc();
if (Parser.getTok().isNot(AsmToken::RCurly)) {
Error(E, "'}' expected");
return MatchOperand_ParseFail;
}
Parser.Lex();
switch (LaneKind) {
default:
assert(0 && "unexpected lane kind in register list.");
case NoLanes:
Operands.push_back(ARMOperand::CreateVectorList(FirstReg, Count, S, E));
break;
case AllLanes:
Operands.push_back(ARMOperand::CreateVectorListAllLanes(FirstReg, Count,
S, E));
break;
case IndexedLane:
Operands.push_back(ARMOperand::CreateVectorListIndexed(FirstReg, Count,
LaneIndex, S, E));
break;
}
return MatchOperand_Success;
}
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
parseMemBarrierOptOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
SMLoc S = Parser.getTok().getLoc();
const AsmToken &Tok = Parser.getTok();
assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier");
StringRef OptStr = Tok.getString();
unsigned Opt = StringSwitch<unsigned>(OptStr.slice(0, OptStr.size()))
.Case("sy", ARM_MB::SY)
.Case("st", ARM_MB::ST)
.Case("sh", ARM_MB::ISH)
.Case("ish", ARM_MB::ISH)
.Case("shst", ARM_MB::ISHST)
.Case("ishst", ARM_MB::ISHST)
.Case("nsh", ARM_MB::NSH)
.Case("un", ARM_MB::NSH)
.Case("nshst", ARM_MB::NSHST)
.Case("unst", ARM_MB::NSHST)
.Case("osh", ARM_MB::OSH)
.Case("oshst", ARM_MB::OSHST)
.Default(~0U);
if (Opt == ~0U)
return MatchOperand_NoMatch;
Parser.Lex(); Operands.push_back(ARMOperand::CreateMemBarrierOpt((ARM_MB::MemBOpt)Opt, S));
return MatchOperand_Success;
}
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
parseProcIFlagsOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
SMLoc S = Parser.getTok().getLoc();
const AsmToken &Tok = Parser.getTok();
assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier");
StringRef IFlagsStr = Tok.getString();
unsigned IFlags = 0;
if (IFlagsStr != "none") {
for (int i = 0, e = IFlagsStr.size(); i != e; ++i) {
unsigned Flag = StringSwitch<unsigned>(IFlagsStr.substr(i, 1))
.Case("a", ARM_PROC::A)
.Case("i", ARM_PROC::I)
.Case("f", ARM_PROC::F)
.Default(~0U);
if (Flag == ~0U || (IFlags & Flag))
return MatchOperand_NoMatch;
IFlags |= Flag;
}
}
Parser.Lex(); Operands.push_back(ARMOperand::CreateProcIFlags((ARM_PROC::IFlags)IFlags, S));
return MatchOperand_Success;
}
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
parseMSRMaskOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
SMLoc S = Parser.getTok().getLoc();
const AsmToken &Tok = Parser.getTok();
assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier");
StringRef Mask = Tok.getString();
if (isMClass()) {
unsigned FlagsVal = StringSwitch<unsigned>(Mask)
.Case("apsr", 0)
.Case("iapsr", 1)
.Case("eapsr", 2)
.Case("xpsr", 3)
.Case("ipsr", 5)
.Case("epsr", 6)
.Case("iepsr", 7)
.Case("msp", 8)
.Case("psp", 9)
.Case("primask", 16)
.Case("basepri", 17)
.Case("basepri_max", 18)
.Case("faultmask", 19)
.Case("control", 20)
.Default(~0U);
if (FlagsVal == ~0U)
return MatchOperand_NoMatch;
if (!hasV7Ops() && FlagsVal >= 17 && FlagsVal <= 19)
return MatchOperand_NoMatch;
Parser.Lex(); Operands.push_back(ARMOperand::CreateMSRMask(FlagsVal, S));
return MatchOperand_Success;
}
size_t Start = 0, Next = Mask.find('_');
StringRef Flags = "";
std::string SpecReg = Mask.slice(Start, Next).lower();
if (Next != StringRef::npos)
Flags = Mask.slice(Next+1, Mask.size());
unsigned FlagsVal = 0;
if (SpecReg == "apsr") {
FlagsVal = StringSwitch<unsigned>(Flags)
.Case("nzcvq", 0x8) .Case("g", 0x4) .Case("nzcvqg", 0xc) .Default(~0U);
if (FlagsVal == ~0U) {
if (!Flags.empty())
return MatchOperand_NoMatch;
else
FlagsVal = 8; }
} else if (SpecReg == "cpsr" || SpecReg == "spsr") {
if (Flags == "all") Flags = "fc";
for (int i = 0, e = Flags.size(); i != e; ++i) {
unsigned Flag = StringSwitch<unsigned>(Flags.substr(i, 1))
.Case("c", 1)
.Case("x", 2)
.Case("s", 4)
.Case("f", 8)
.Default(~0U);
if (FlagsVal == ~0U || (FlagsVal & Flag))
return MatchOperand_NoMatch;
FlagsVal |= Flag;
}
} else return MatchOperand_NoMatch;
if (SpecReg == "spsr")
FlagsVal |= 16;
Parser.Lex(); Operands.push_back(ARMOperand::CreateMSRMask(FlagsVal, S));
return MatchOperand_Success;
}
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
parsePKHImm(SmallVectorImpl<MCParsedAsmOperand*> &Operands, StringRef Op,
int Low, int High) {
const AsmToken &Tok = Parser.getTok();
if (Tok.isNot(AsmToken::Identifier)) {
Error(Parser.getTok().getLoc(), Op + " operand expected.");
return MatchOperand_ParseFail;
}
StringRef ShiftName = Tok.getString();
std::string LowerOp = Op.lower();
std::string UpperOp = Op.upper();
if (ShiftName != LowerOp && ShiftName != UpperOp) {
Error(Parser.getTok().getLoc(), Op + " operand expected.");
return MatchOperand_ParseFail;
}
Parser.Lex();
if (Parser.getTok().isNot(AsmToken::Hash) &&
Parser.getTok().isNot(AsmToken::Dollar)) {
Error(Parser.getTok().getLoc(), "'#' expected");
return MatchOperand_ParseFail;
}
Parser.Lex();
const MCExpr *ShiftAmount;
SMLoc Loc = Parser.getTok().getLoc();
if (getParser().ParseExpression(ShiftAmount)) {
Error(Loc, "illegal expression");
return MatchOperand_ParseFail;
}
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(ShiftAmount);
if (!CE) {
Error(Loc, "constant expression expected");
return MatchOperand_ParseFail;
}
int Val = CE->getValue();
if (Val < Low || Val > High) {
Error(Loc, "immediate value out of range");
return MatchOperand_ParseFail;
}
Operands.push_back(ARMOperand::CreateImm(CE, Loc, Parser.getTok().getLoc()));
return MatchOperand_Success;
}
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
parseSetEndImm(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
const AsmToken &Tok = Parser.getTok();
SMLoc S = Tok.getLoc();
if (Tok.isNot(AsmToken::Identifier)) {
Error(Tok.getLoc(), "'be' or 'le' operand expected");
return MatchOperand_ParseFail;
}
int Val = StringSwitch<int>(Tok.getString())
.Case("be", 1)
.Case("le", 0)
.Default(-1);
Parser.Lex();
if (Val == -1) {
Error(Tok.getLoc(), "'be' or 'le' operand expected");
return MatchOperand_ParseFail;
}
Operands.push_back(ARMOperand::CreateImm(MCConstantExpr::Create(Val,
getContext()),
S, Parser.getTok().getLoc()));
return MatchOperand_Success;
}
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
parseShifterImm(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
const AsmToken &Tok = Parser.getTok();
SMLoc S = Tok.getLoc();
if (Tok.isNot(AsmToken::Identifier)) {
Error(S, "shift operator 'asr' or 'lsl' expected");
return MatchOperand_ParseFail;
}
StringRef ShiftName = Tok.getString();
bool isASR;
if (ShiftName == "lsl" || ShiftName == "LSL")
isASR = false;
else if (ShiftName == "asr" || ShiftName == "ASR")
isASR = true;
else {
Error(S, "shift operator 'asr' or 'lsl' expected");
return MatchOperand_ParseFail;
}
Parser.Lex();
if (Parser.getTok().isNot(AsmToken::Hash) &&
Parser.getTok().isNot(AsmToken::Dollar)) {
Error(Parser.getTok().getLoc(), "'#' expected");
return MatchOperand_ParseFail;
}
Parser.Lex();
const MCExpr *ShiftAmount;
SMLoc E = Parser.getTok().getLoc();
if (getParser().ParseExpression(ShiftAmount)) {
Error(E, "malformed shift expression");
return MatchOperand_ParseFail;
}
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(ShiftAmount);
if (!CE) {
Error(E, "shift amount must be an immediate");
return MatchOperand_ParseFail;
}
int64_t Val = CE->getValue();
if (isASR) {
if (Val < 1 || Val > 32) {
Error(E, "'asr' shift amount must be in range [1,32]");
return MatchOperand_ParseFail;
}
if (isThumb() && Val == 32) {
Error(E, "'asr #32' shift amount not allowed in Thumb mode");
return MatchOperand_ParseFail;
}
if (Val == 32) Val = 0;
} else {
if (Val < 0 || Val > 31) {
Error(E, "'lsr' shift amount must be in range [0,31]");
return MatchOperand_ParseFail;
}
}
E = Parser.getTok().getLoc();
Operands.push_back(ARMOperand::CreateShifterImm(isASR, Val, S, E));
return MatchOperand_Success;
}
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
parseRotImm(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
const AsmToken &Tok = Parser.getTok();
SMLoc S = Tok.getLoc();
if (Tok.isNot(AsmToken::Identifier))
return MatchOperand_NoMatch;
StringRef ShiftName = Tok.getString();
if (ShiftName != "ror" && ShiftName != "ROR")
return MatchOperand_NoMatch;
Parser.Lex();
if (Parser.getTok().isNot(AsmToken::Hash) &&
Parser.getTok().isNot(AsmToken::Dollar)) {
Error(Parser.getTok().getLoc(), "'#' expected");
return MatchOperand_ParseFail;
}
Parser.Lex();
const MCExpr *ShiftAmount;
SMLoc E = Parser.getTok().getLoc();
if (getParser().ParseExpression(ShiftAmount)) {
Error(E, "malformed rotate expression");
return MatchOperand_ParseFail;
}
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(ShiftAmount);
if (!CE) {
Error(E, "rotate amount must be an immediate");
return MatchOperand_ParseFail;
}
int64_t Val = CE->getValue();
if (Val != 8 && Val != 16 && Val != 24 && Val != 0) {
Error(E, "'ror' rotate amount must be 8, 16, or 24");
return MatchOperand_ParseFail;
}
E = Parser.getTok().getLoc();
Operands.push_back(ARMOperand::CreateRotImm(Val, S, E));
return MatchOperand_Success;
}
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
parseBitfield(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
SMLoc S = Parser.getTok().getLoc();
if (Parser.getTok().isNot(AsmToken::Hash) &&
Parser.getTok().isNot(AsmToken::Dollar)) {
Error(Parser.getTok().getLoc(), "'#' expected");
return MatchOperand_ParseFail;
}
Parser.Lex();
const MCExpr *LSBExpr;
SMLoc E = Parser.getTok().getLoc();
if (getParser().ParseExpression(LSBExpr)) {
Error(E, "malformed immediate expression");
return MatchOperand_ParseFail;
}
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(LSBExpr);
if (!CE) {
Error(E, "'lsb' operand must be an immediate");
return MatchOperand_ParseFail;
}
int64_t LSB = CE->getValue();
if (LSB < 0 || LSB > 31) {
Error(E, "'lsb' operand must be in the range [0,31]");
return MatchOperand_ParseFail;
}
E = Parser.getTok().getLoc();
if (Parser.getTok().isNot(AsmToken::Comma)) {
Error(Parser.getTok().getLoc(), "too few operands");
return MatchOperand_ParseFail;
}
Parser.Lex(); if (Parser.getTok().isNot(AsmToken::Hash) &&
Parser.getTok().isNot(AsmToken::Dollar)) {
Error(Parser.getTok().getLoc(), "'#' expected");
return MatchOperand_ParseFail;
}
Parser.Lex();
const MCExpr *WidthExpr;
if (getParser().ParseExpression(WidthExpr)) {
Error(E, "malformed immediate expression");
return MatchOperand_ParseFail;
}
CE = dyn_cast<MCConstantExpr>(WidthExpr);
if (!CE) {
Error(E, "'width' operand must be an immediate");
return MatchOperand_ParseFail;
}
int64_t Width = CE->getValue();
if (Width < 1 || Width > 32 - LSB) {
Error(E, "'width' operand must be in the range [1,32-lsb]");
return MatchOperand_ParseFail;
}
E = Parser.getTok().getLoc();
Operands.push_back(ARMOperand::CreateBitfield(LSB, Width, S, E));
return MatchOperand_Success;
}
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
parsePostIdxReg(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
AsmToken Tok = Parser.getTok();
SMLoc S = Tok.getLoc();
bool haveEaten = false;
bool isAdd = true;
int Reg = -1;
if (Tok.is(AsmToken::Plus)) {
Parser.Lex(); haveEaten = true;
} else if (Tok.is(AsmToken::Minus)) {
Parser.Lex(); isAdd = false;
haveEaten = true;
}
if (Parser.getTok().is(AsmToken::Identifier))
Reg = tryParseRegister();
if (Reg == -1) {
if (!haveEaten)
return MatchOperand_NoMatch;
Error(Parser.getTok().getLoc(), "register expected");
return MatchOperand_ParseFail;
}
SMLoc E = Parser.getTok().getLoc();
ARM_AM::ShiftOpc ShiftTy = ARM_AM::no_shift;
unsigned ShiftImm = 0;
if (Parser.getTok().is(AsmToken::Comma)) {
Parser.Lex(); if (parseMemRegOffsetShift(ShiftTy, ShiftImm))
return MatchOperand_ParseFail;
}
Operands.push_back(ARMOperand::CreatePostIdxReg(Reg, isAdd, ShiftTy,
ShiftImm, S, E));
return MatchOperand_Success;
}
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
parseAM3Offset(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
AsmToken Tok = Parser.getTok();
SMLoc S = Tok.getLoc();
if (Parser.getTok().is(AsmToken::Hash) ||
Parser.getTok().is(AsmToken::Dollar)) {
Parser.Lex(); bool isNegative = Parser.getTok().is(AsmToken::Minus);
const MCExpr *Offset;
if (getParser().ParseExpression(Offset))
return MatchOperand_ParseFail;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Offset);
if (!CE) {
Error(S, "constant expression expected");
return MatchOperand_ParseFail;
}
SMLoc E = Tok.getLoc();
int32_t Val = CE->getValue();
if (isNegative && Val == 0)
Val = INT32_MIN;
Operands.push_back(
ARMOperand::CreateImm(MCConstantExpr::Create(Val, getContext()), S, E));
return MatchOperand_Success;
}
bool haveEaten = false;
bool isAdd = true;
int Reg = -1;
if (Tok.is(AsmToken::Plus)) {
Parser.Lex(); haveEaten = true;
} else if (Tok.is(AsmToken::Minus)) {
Parser.Lex(); isAdd = false;
haveEaten = true;
}
if (Parser.getTok().is(AsmToken::Identifier))
Reg = tryParseRegister();
if (Reg == -1) {
if (!haveEaten)
return MatchOperand_NoMatch;
Error(Parser.getTok().getLoc(), "register expected");
return MatchOperand_ParseFail;
}
SMLoc E = Parser.getTok().getLoc();
Operands.push_back(ARMOperand::CreatePostIdxReg(Reg, isAdd, ARM_AM::no_shift,
0, S, E));
return MatchOperand_Success;
}
bool ARMAsmParser::
cvtT2LdrdPre(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
((ARMOperand*)Operands[3])->addRegOperands(Inst, 1);
Inst.addOperand(MCOperand::CreateReg(0));
((ARMOperand*)Operands[4])->addMemImm8s4OffsetOperands(Inst, 2);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
cvtT2StrdPre(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
Inst.addOperand(MCOperand::CreateReg(0));
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
((ARMOperand*)Operands[3])->addRegOperands(Inst, 1);
((ARMOperand*)Operands[4])->addMemImm8s4OffsetOperands(Inst, 2);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
cvtLdWriteBackRegT2AddrModeImm8(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
Inst.addOperand(MCOperand::CreateImm(0));
((ARMOperand*)Operands[3])->addMemImm8OffsetOperands(Inst, 2);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
cvtStWriteBackRegT2AddrModeImm8(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
Inst.addOperand(MCOperand::CreateImm(0));
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
((ARMOperand*)Operands[3])->addMemImm8OffsetOperands(Inst, 2);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
cvtLdWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
Inst.addOperand(MCOperand::CreateImm(0));
((ARMOperand*)Operands[3])->addAddrMode2Operands(Inst, 3);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
cvtLdWriteBackRegAddrModeImm12(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
Inst.addOperand(MCOperand::CreateImm(0));
((ARMOperand*)Operands[3])->addMemImm12OffsetOperands(Inst, 2);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
cvtStWriteBackRegAddrModeImm12(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
Inst.addOperand(MCOperand::CreateImm(0));
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
((ARMOperand*)Operands[3])->addMemImm12OffsetOperands(Inst, 2);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
cvtStWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
Inst.addOperand(MCOperand::CreateImm(0));
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
((ARMOperand*)Operands[3])->addAddrMode2Operands(Inst, 3);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
cvtStWriteBackRegAddrMode3(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
Inst.addOperand(MCOperand::CreateImm(0));
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
((ARMOperand*)Operands[3])->addAddrMode3Operands(Inst, 3);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
cvtLdExtTWriteBackImm(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
Inst.addOperand(MCOperand::CreateImm(0));
((ARMOperand*)Operands[3])->addMemNoOffsetOperands(Inst, 1);
((ARMOperand*)Operands[4])->addPostIdxImm8Operands(Inst, 1);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
cvtLdExtTWriteBackReg(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
Inst.addOperand(MCOperand::CreateImm(0));
((ARMOperand*)Operands[3])->addMemNoOffsetOperands(Inst, 1);
((ARMOperand*)Operands[4])->addPostIdxRegOperands(Inst, 2);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
cvtStExtTWriteBackImm(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
Inst.addOperand(MCOperand::CreateImm(0));
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
((ARMOperand*)Operands[3])->addMemNoOffsetOperands(Inst, 1);
((ARMOperand*)Operands[4])->addPostIdxImm8Operands(Inst, 1);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
cvtStExtTWriteBackReg(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
Inst.addOperand(MCOperand::CreateImm(0));
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
((ARMOperand*)Operands[3])->addMemNoOffsetOperands(Inst, 1);
((ARMOperand*)Operands[4])->addPostIdxRegOperands(Inst, 2);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
cvtLdrdPre(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
((ARMOperand*)Operands[3])->addRegOperands(Inst, 1);
Inst.addOperand(MCOperand::CreateImm(0));
((ARMOperand*)Operands[4])->addAddrMode3Operands(Inst, 3);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
cvtStrdPre(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
Inst.addOperand(MCOperand::CreateImm(0));
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
((ARMOperand*)Operands[3])->addRegOperands(Inst, 1);
((ARMOperand*)Operands[4])->addAddrMode3Operands(Inst, 3);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
cvtLdWriteBackRegAddrMode3(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
Inst.addOperand(MCOperand::CreateImm(0));
((ARMOperand*)Operands[3])->addAddrMode3Operands(Inst, 3);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
cvtThumbMultiply(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
if (Operands.size() == 6 &&
(((ARMOperand*)Operands[3])->getReg() !=
((ARMOperand*)Operands[5])->getReg()) &&
(((ARMOperand*)Operands[3])->getReg() !=
((ARMOperand*)Operands[4])->getReg())) {
Error(Operands[3]->getStartLoc(),
"destination register must match source register");
return false;
}
((ARMOperand*)Operands[3])->addRegOperands(Inst, 1);
((ARMOperand*)Operands[1])->addCCOutOperands(Inst, 1);
unsigned RegOp = 4;
if (Operands.size() == 6 &&
((ARMOperand*)Operands[4])->getReg() ==
((ARMOperand*)Operands[3])->getReg())
RegOp = 5;
((ARMOperand*)Operands[RegOp])->addRegOperands(Inst, 1);
Inst.addOperand(Inst.getOperand(0));
((ARMOperand*)Operands[2])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
cvtVLDwbFixed(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
((ARMOperand*)Operands[3])->addVecListOperands(Inst, 1);
Inst.addOperand(MCOperand::CreateImm(0));
((ARMOperand*)Operands[4])->addAlignedMemoryOperands(Inst, 2);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
cvtVLDwbRegister(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
((ARMOperand*)Operands[3])->addVecListOperands(Inst, 1);
Inst.addOperand(MCOperand::CreateImm(0));
((ARMOperand*)Operands[4])->addAlignedMemoryOperands(Inst, 2);
((ARMOperand*)Operands[5])->addRegOperands(Inst, 1);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
cvtVSTwbFixed(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
Inst.addOperand(MCOperand::CreateImm(0));
((ARMOperand*)Operands[4])->addAlignedMemoryOperands(Inst, 2);
((ARMOperand*)Operands[3])->addVecListOperands(Inst, 1);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
cvtVSTwbRegister(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
Inst.addOperand(MCOperand::CreateImm(0));
((ARMOperand*)Operands[4])->addAlignedMemoryOperands(Inst, 2);
((ARMOperand*)Operands[5])->addRegOperands(Inst, 1);
((ARMOperand*)Operands[3])->addVecListOperands(Inst, 1);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
bool ARMAsmParser::
parseMemory(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
SMLoc S, E;
assert(Parser.getTok().is(AsmToken::LBrac) &&
"Token is not a Left Bracket");
S = Parser.getTok().getLoc();
Parser.Lex();
const AsmToken &BaseRegTok = Parser.getTok();
int BaseRegNum = tryParseRegister();
if (BaseRegNum == -1)
return Error(BaseRegTok.getLoc(), "register expected");
const AsmToken &Tok = Parser.getTok();
if (!Tok.is(AsmToken::Comma) && !Tok.is(AsmToken::RBrac))
return Error(Tok.getLoc(), "malformed memory operand");
if (Tok.is(AsmToken::RBrac)) {
E = Tok.getLoc();
Parser.Lex();
Operands.push_back(ARMOperand::CreateMem(BaseRegNum, 0, 0, ARM_AM::no_shift,
0, 0, false, S, E));
if (Parser.getTok().is(AsmToken::Exclaim)) {
Operands.push_back(ARMOperand::CreateToken("!",Parser.getTok().getLoc()));
Parser.Lex(); }
return false;
}
assert(Tok.is(AsmToken::Comma) && "Lost comma in memory operand?!");
Parser.Lex();
if (Parser.getTok().is(AsmToken::Colon)) {
Parser.Lex(); E = Parser.getTok().getLoc();
const MCExpr *Expr;
if (getParser().ParseExpression(Expr))
return true;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr);
if (!CE)
return Error (E, "constant expression expected");
unsigned Align = 0;
switch (CE->getValue()) {
default:
return Error(E, "alignment specifier must be 64, 128, or 256 bits");
case 64: Align = 8; break;
case 128: Align = 16; break;
case 256: Align = 32; break;
}
E = Parser.getTok().getLoc();
if (Parser.getTok().isNot(AsmToken::RBrac))
return Error(E, "']' expected");
Parser.Lex();
Operands.push_back(ARMOperand::CreateMem(BaseRegNum, 0, 0,
ARM_AM::no_shift, 0, Align,
false, S, E));
if (Parser.getTok().is(AsmToken::Exclaim)) {
Operands.push_back(ARMOperand::CreateToken("!",Parser.getTok().getLoc()));
Parser.Lex(); }
return false;
}
if (Parser.getTok().is(AsmToken::Hash) ||
Parser.getTok().is(AsmToken::Dollar) ||
Parser.getTok().is(AsmToken::Integer)) {
if (Parser.getTok().isNot(AsmToken::Integer))
Parser.Lex(); E = Parser.getTok().getLoc();
bool isNegative = getParser().getTok().is(AsmToken::Minus);
const MCExpr *Offset;
if (getParser().ParseExpression(Offset))
return true;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Offset);
if (!CE)
return Error (E, "constant expression expected");
int32_t Val = CE->getValue();
if (isNegative && Val == 0)
CE = MCConstantExpr::Create(INT32_MIN, getContext());
E = Parser.getTok().getLoc();
if (Parser.getTok().isNot(AsmToken::RBrac))
return Error(E, "']' expected");
Parser.Lex();
Operands.push_back(ARMOperand::CreateMem(BaseRegNum, CE, 0,
ARM_AM::no_shift, 0, 0,
false, S, E));
if (Parser.getTok().is(AsmToken::Exclaim)) {
Operands.push_back(ARMOperand::CreateToken("!",Parser.getTok().getLoc()));
Parser.Lex(); }
return false;
}
bool isNegative = false;
if (Parser.getTok().is(AsmToken::Minus)) {
isNegative = true;
Parser.Lex(); } else if (Parser.getTok().is(AsmToken::Plus)) {
Parser.Lex(); }
E = Parser.getTok().getLoc();
int OffsetRegNum = tryParseRegister();
if (OffsetRegNum == -1)
return Error(E, "register expected");
ARM_AM::ShiftOpc ShiftType = ARM_AM::no_shift;
unsigned ShiftImm = 0;
if (Parser.getTok().is(AsmToken::Comma)) {
Parser.Lex(); if (parseMemRegOffsetShift(ShiftType, ShiftImm))
return true;
}
E = Parser.getTok().getLoc();
if (Parser.getTok().isNot(AsmToken::RBrac))
return Error(E, "']' expected");
Parser.Lex();
Operands.push_back(ARMOperand::CreateMem(BaseRegNum, 0, OffsetRegNum,
ShiftType, ShiftImm, 0, isNegative,
S, E));
if (Parser.getTok().is(AsmToken::Exclaim)) {
Operands.push_back(ARMOperand::CreateToken("!",Parser.getTok().getLoc()));
Parser.Lex(); }
return false;
}
bool ARMAsmParser::parseMemRegOffsetShift(ARM_AM::ShiftOpc &St,
unsigned &Amount) {
SMLoc Loc = Parser.getTok().getLoc();
const AsmToken &Tok = Parser.getTok();
if (Tok.isNot(AsmToken::Identifier))
return true;
StringRef ShiftName = Tok.getString();
if (ShiftName == "lsl" || ShiftName == "LSL" ||
ShiftName == "asl" || ShiftName == "ASL")
St = ARM_AM::lsl;
else if (ShiftName == "lsr" || ShiftName == "LSR")
St = ARM_AM::lsr;
else if (ShiftName == "asr" || ShiftName == "ASR")
St = ARM_AM::asr;
else if (ShiftName == "ror" || ShiftName == "ROR")
St = ARM_AM::ror;
else if (ShiftName == "rrx" || ShiftName == "RRX")
St = ARM_AM::rrx;
else
return Error(Loc, "illegal shift operator");
Parser.Lex();
Amount = 0;
if (St != ARM_AM::rrx) {
Loc = Parser.getTok().getLoc();
const AsmToken &HashTok = Parser.getTok();
if (HashTok.isNot(AsmToken::Hash) &&
HashTok.isNot(AsmToken::Dollar))
return Error(HashTok.getLoc(), "'#' expected");
Parser.Lex();
const MCExpr *Expr;
if (getParser().ParseExpression(Expr))
return true;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr);
if (!CE)
return Error(Loc, "shift amount must be an immediate");
int64_t Imm = CE->getValue();
if (Imm < 0 ||
((St == ARM_AM::lsl || St == ARM_AM::ror) && Imm > 31) ||
((St == ARM_AM::lsr || St == ARM_AM::asr) && Imm > 32))
return Error(Loc, "immediate shift value out of range");
Amount = Imm;
}
return false;
}
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
parseFPImm(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
SMLoc S = Parser.getTok().getLoc();
if (Parser.getTok().isNot(AsmToken::Hash) &&
Parser.getTok().isNot(AsmToken::Dollar))
return MatchOperand_NoMatch;
ARMOperand *TyOp = static_cast<ARMOperand*>(Operands[2]);
if (!TyOp->isToken() || (TyOp->getToken() != ".f32" &&
TyOp->getToken() != ".f64"))
return MatchOperand_NoMatch;
Parser.Lex();
bool isNegative = false;
if (Parser.getTok().is(AsmToken::Minus)) {
isNegative = true;
Parser.Lex();
}
const AsmToken &Tok = Parser.getTok();
if (Tok.is(AsmToken::Real)) {
APFloat RealVal(APFloat::IEEEdouble, Tok.getString());
uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue();
IntVal ^= (uint64_t)isNegative << 63;
int Val = ARM_AM::getFP64Imm(APInt(64, IntVal));
Parser.Lex(); if (Val == -1) {
TokError("floating point value out of range");
return MatchOperand_ParseFail;
}
Operands.push_back(ARMOperand::CreateFPImm(Val, S, getContext()));
return MatchOperand_Success;
}
if (Tok.is(AsmToken::Integer)) {
int64_t Val = Tok.getIntVal();
Parser.Lex(); if (Val > 255 || Val < 0) {
TokError("encoded floating point value out of range");
return MatchOperand_ParseFail;
}
Operands.push_back(ARMOperand::CreateFPImm(Val, S, getContext()));
return MatchOperand_Success;
}
TokError("invalid floating point immediate");
return MatchOperand_ParseFail;
}
bool ARMAsmParser::parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
StringRef Mnemonic) {
SMLoc S, E;
OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic);
if (ResTy == MatchOperand_Success)
return false;
if (ResTy == MatchOperand_ParseFail)
return true;
switch (getLexer().getKind()) {
default:
Error(Parser.getTok().getLoc(), "unexpected token in operand");
return true;
case AsmToken::Identifier: {
if (!tryParseRegisterWithWriteBack(Operands))
return false;
int Res = tryParseShiftRegister(Operands);
if (Res == 0) return false;
else if (Res == -1) return true;
if (Mnemonic == "vmrs" && Parser.getTok().getString() == "apsr_nzcv") {
S = Parser.getTok().getLoc();
Parser.Lex();
Operands.push_back(ARMOperand::CreateToken("apsr_nzcv", S));
return false;
}
}
case AsmToken::LParen: case AsmToken::Integer: case AsmToken::String: case AsmToken::Dot: { const MCExpr *IdVal;
S = Parser.getTok().getLoc();
if (getParser().ParseExpression(IdVal))
return true;
E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
Operands.push_back(ARMOperand::CreateImm(IdVal, S, E));
return false;
}
case AsmToken::LBrac:
return parseMemory(Operands);
case AsmToken::LCurly:
return parseRegisterList(Operands);
case AsmToken::Dollar:
case AsmToken::Hash: {
S = Parser.getTok().getLoc();
Parser.Lex();
bool isNegative = Parser.getTok().is(AsmToken::Minus);
const MCExpr *ImmVal;
if (getParser().ParseExpression(ImmVal))
return true;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(ImmVal);
if (CE) {
int32_t Val = CE->getValue();
if (isNegative && Val == 0)
ImmVal = MCConstantExpr::Create(INT32_MIN, getContext());
}
E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
Operands.push_back(ARMOperand::CreateImm(ImmVal, S, E));
return false;
}
case AsmToken::Colon: {
ARMMCExpr::VariantKind RefKind;
if (parsePrefix(RefKind))
return true;
const MCExpr *SubExprVal;
if (getParser().ParseExpression(SubExprVal))
return true;
const MCExpr *ExprVal = ARMMCExpr::Create(RefKind, SubExprVal,
getContext());
E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
Operands.push_back(ARMOperand::CreateImm(ExprVal, S, E));
return false;
}
}
}
bool ARMAsmParser::parsePrefix(ARMMCExpr::VariantKind &RefKind) {
RefKind = ARMMCExpr::VK_ARM_None;
assert(getLexer().is(AsmToken::Colon) && "expected a :");
Parser.Lex();
if (getLexer().isNot(AsmToken::Identifier)) {
Error(Parser.getTok().getLoc(), "expected prefix identifier in operand");
return true;
}
StringRef IDVal = Parser.getTok().getIdentifier();
if (IDVal == "lower16") {
RefKind = ARMMCExpr::VK_ARM_LO16;
} else if (IDVal == "upper16") {
RefKind = ARMMCExpr::VK_ARM_HI16;
} else {
Error(Parser.getTok().getLoc(), "unexpected prefix in operand");
return true;
}
Parser.Lex();
if (getLexer().isNot(AsmToken::Colon)) {
Error(Parser.getTok().getLoc(), "unexpected token after prefix");
return true;
}
Parser.Lex(); return false;
}
StringRef ARMAsmParser::splitMnemonic(StringRef Mnemonic,
unsigned &PredicationCode,
bool &CarrySetting,
unsigned &ProcessorIMod,
StringRef &ITMask) {
PredicationCode = ARMCC::AL;
CarrySetting = false;
ProcessorIMod = 0;
if ((Mnemonic == "movs" && isThumb()) ||
Mnemonic == "teq" || Mnemonic == "vceq" || Mnemonic == "svc" ||
Mnemonic == "mls" || Mnemonic == "smmls" || Mnemonic == "vcls" ||
Mnemonic == "vmls" || Mnemonic == "vnmls" || Mnemonic == "vacge" ||
Mnemonic == "vcge" || Mnemonic == "vclt" || Mnemonic == "vacgt" ||
Mnemonic == "vcgt" || Mnemonic == "vcle" || Mnemonic == "smlal" ||
Mnemonic == "umaal" || Mnemonic == "umlal" || Mnemonic == "vabal" ||
Mnemonic == "vmlal" || Mnemonic == "vpadal" || Mnemonic == "vqdmlal")
return Mnemonic;
if (Mnemonic != "adcs" && Mnemonic != "bics" && Mnemonic != "movs" &&
Mnemonic != "muls" && Mnemonic != "smlals" && Mnemonic != "smulls" &&
Mnemonic != "umlals" && Mnemonic != "umulls" && Mnemonic != "lsls" &&
Mnemonic != "sbcs" && Mnemonic != "rscs") {
unsigned CC = StringSwitch<unsigned>(Mnemonic.substr(Mnemonic.size()-2))
.Case("eq", ARMCC::EQ)
.Case("ne", ARMCC::NE)
.Case("hs", ARMCC::HS)
.Case("cs", ARMCC::HS)
.Case("lo", ARMCC::LO)
.Case("cc", ARMCC::LO)
.Case("mi", ARMCC::MI)
.Case("pl", ARMCC::PL)
.Case("vs", ARMCC::VS)
.Case("vc", ARMCC::VC)
.Case("hi", ARMCC::HI)
.Case("ls", ARMCC::LS)
.Case("ge", ARMCC::GE)
.Case("lt", ARMCC::LT)
.Case("gt", ARMCC::GT)
.Case("le", ARMCC::LE)
.Case("al", ARMCC::AL)
.Default(~0U);
if (CC != ~0U) {
Mnemonic = Mnemonic.slice(0, Mnemonic.size() - 2);
PredicationCode = CC;
}
}
if (Mnemonic.endswith("s") &&
!(Mnemonic == "cps" || Mnemonic == "mls" ||
Mnemonic == "mrs" || Mnemonic == "smmls" || Mnemonic == "vabs" ||
Mnemonic == "vcls" || Mnemonic == "vmls" || Mnemonic == "vmrs" ||
Mnemonic == "vnmls" || Mnemonic == "vqabs" || Mnemonic == "vrecps" ||
Mnemonic == "vrsqrts" || Mnemonic == "srs" || Mnemonic == "flds" ||
Mnemonic == "fmrs" || Mnemonic == "fsqrts" || Mnemonic == "fsubs" ||
Mnemonic == "fsts" ||
(Mnemonic == "movs" && isThumb()))) {
Mnemonic = Mnemonic.slice(0, Mnemonic.size() - 1);
CarrySetting = true;
}
if (Mnemonic.startswith("cps")) {
unsigned IMod =
StringSwitch<unsigned>(Mnemonic.substr(Mnemonic.size()-2, 2))
.Case("ie", ARM_PROC::IE)
.Case("id", ARM_PROC::ID)
.Default(~0U);
if (IMod != ~0U) {
Mnemonic = Mnemonic.slice(0, Mnemonic.size()-2);
ProcessorIMod = IMod;
}
}
if (Mnemonic.startswith("it")) {
ITMask = Mnemonic.slice(2, Mnemonic.size());
Mnemonic = Mnemonic.slice(0, 2);
}
return Mnemonic;
}
void ARMAsmParser::
getMnemonicAcceptInfo(StringRef Mnemonic, bool &CanAcceptCarrySet,
bool &CanAcceptPredicationCode) {
if (Mnemonic == "and" || Mnemonic == "lsl" || Mnemonic == "lsr" ||
Mnemonic == "rrx" || Mnemonic == "ror" || Mnemonic == "sub" ||
Mnemonic == "add" || Mnemonic == "adc" ||
Mnemonic == "mul" || Mnemonic == "bic" || Mnemonic == "asr" ||
Mnemonic == "orr" || Mnemonic == "mvn" ||
Mnemonic == "rsb" || Mnemonic == "rsc" || Mnemonic == "orn" ||
Mnemonic == "sbc" || Mnemonic == "eor" || Mnemonic == "neg" ||
(!isThumb() && (Mnemonic == "smull" || Mnemonic == "mov" ||
Mnemonic == "mla" || Mnemonic == "smlal" ||
Mnemonic == "umlal" || Mnemonic == "umull"))) {
CanAcceptCarrySet = true;
} else
CanAcceptCarrySet = false;
if (Mnemonic == "cbnz" || Mnemonic == "setend" || Mnemonic == "dmb" ||
Mnemonic == "cps" || Mnemonic == "mcr2" || Mnemonic == "it" ||
Mnemonic == "mcrr2" || Mnemonic == "cbz" || Mnemonic == "cdp2" ||
Mnemonic == "trap" || Mnemonic == "mrc2" || Mnemonic == "mrrc2" ||
Mnemonic == "dsb" || Mnemonic == "isb" || Mnemonic == "setend" ||
(Mnemonic == "clrex" && !isThumb()) ||
(Mnemonic == "nop" && isThumbOne()) ||
((Mnemonic == "pld" || Mnemonic == "pli" || Mnemonic == "pldw" ||
Mnemonic == "ldc2" || Mnemonic == "ldc2l" ||
Mnemonic == "stc2" || Mnemonic == "stc2l") && !isThumb()) ||
((Mnemonic.startswith("rfe") || Mnemonic.startswith("srs")) &&
!isThumb()) ||
Mnemonic.startswith("cps") || (Mnemonic == "movs" && isThumbOne())) {
CanAcceptPredicationCode = false;
} else
CanAcceptPredicationCode = true;
if (isThumb()) {
if (Mnemonic == "bkpt" || Mnemonic == "mcr" || Mnemonic == "mcrr" ||
Mnemonic == "mrc" || Mnemonic == "mrrc" || Mnemonic == "cdp")
CanAcceptPredicationCode = false;
}
}
bool ARMAsmParser::shouldOmitCCOutOperand(StringRef Mnemonic,
SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
if (Mnemonic == "mov" && Operands.size() > 4 && !isThumb() &&
!static_cast<ARMOperand*>(Operands[4])->isARMSOImm() &&
static_cast<ARMOperand*>(Operands[4])->isImm0_65535Expr() &&
static_cast<ARMOperand*>(Operands[1])->getReg() == 0)
return true;
if (isThumb() && Mnemonic == "add" && Operands.size() == 5 &&
static_cast<ARMOperand*>(Operands[3])->isReg() &&
static_cast<ARMOperand*>(Operands[4])->isReg() &&
static_cast<ARMOperand*>(Operands[1])->getReg() == 0)
return true;
if (((isThumb() && Mnemonic == "add") ||
(isThumbTwo() && Mnemonic == "sub")) &&
Operands.size() == 6 &&
static_cast<ARMOperand*>(Operands[3])->isReg() &&
static_cast<ARMOperand*>(Operands[4])->isReg() &&
static_cast<ARMOperand*>(Operands[4])->getReg() == ARM::SP &&
static_cast<ARMOperand*>(Operands[1])->getReg() == 0 &&
(static_cast<ARMOperand*>(Operands[5])->isReg() ||
static_cast<ARMOperand*>(Operands[5])->isImm0_1020s4()))
return true;
if (isThumbTwo() && (Mnemonic == "add" || Mnemonic == "sub") &&
Operands.size() == 6 &&
static_cast<ARMOperand*>(Operands[3])->isReg() &&
static_cast<ARMOperand*>(Operands[4])->isReg() &&
static_cast<ARMOperand*>(Operands[5])->isImm()) {
if ((!isARMLowRegister(static_cast<ARMOperand*>(Operands[3])->getReg()) ||
!isARMLowRegister(static_cast<ARMOperand*>(Operands[4])->getReg())) &&
static_cast<ARMOperand*>(Operands[5])->isT2SOImm())
return false;
if (inITBlock() &&
isARMLowRegister(static_cast<ARMOperand*>(Operands[3])->getReg()) &&
isARMLowRegister(static_cast<ARMOperand*>(Operands[4])->getReg()) &&
static_cast<ARMOperand*>(Operands[5])->isImm0_7())
return false;
return true;
}
if (isThumbTwo() && Mnemonic == "mul" && Operands.size() == 6 &&
static_cast<ARMOperand*>(Operands[1])->getReg() == 0 &&
static_cast<ARMOperand*>(Operands[3])->isReg() &&
static_cast<ARMOperand*>(Operands[4])->isReg() &&
static_cast<ARMOperand*>(Operands[5])->isReg() &&
(!isARMLowRegister(static_cast<ARMOperand*>(Operands[3])->getReg()) ||
!isARMLowRegister(static_cast<ARMOperand*>(Operands[4])->getReg()) ||
!isARMLowRegister(static_cast<ARMOperand*>(Operands[5])->getReg()) ||
!inITBlock() ||
(static_cast<ARMOperand*>(Operands[3])->getReg() !=
static_cast<ARMOperand*>(Operands[5])->getReg() &&
static_cast<ARMOperand*>(Operands[3])->getReg() !=
static_cast<ARMOperand*>(Operands[4])->getReg())))
return true;
if (isThumbTwo() && Mnemonic == "mul" && Operands.size() == 5 &&
static_cast<ARMOperand*>(Operands[1])->getReg() == 0 &&
static_cast<ARMOperand*>(Operands[3])->isReg() &&
static_cast<ARMOperand*>(Operands[4])->isReg() &&
(!isARMLowRegister(static_cast<ARMOperand*>(Operands[3])->getReg()) ||
!isARMLowRegister(static_cast<ARMOperand*>(Operands[4])->getReg()) ||
!inITBlock()))
return true;
if (isThumb() && (Mnemonic == "add" || Mnemonic == "sub") &&
(Operands.size() == 5 || Operands.size() == 6) &&
static_cast<ARMOperand*>(Operands[3])->isReg() &&
static_cast<ARMOperand*>(Operands[3])->getReg() == ARM::SP &&
static_cast<ARMOperand*>(Operands[1])->getReg() == 0)
return true;
return false;
}
static bool isDataTypeToken(StringRef Tok) {
return Tok == ".8" || Tok == ".16" || Tok == ".32" || Tok == ".64" ||
Tok == ".i8" || Tok == ".i16" || Tok == ".i32" || Tok == ".i64" ||
Tok == ".u8" || Tok == ".u16" || Tok == ".u32" || Tok == ".u64" ||
Tok == ".s8" || Tok == ".s16" || Tok == ".s32" || Tok == ".s64" ||
Tok == ".p8" || Tok == ".p16" || Tok == ".f32" || Tok == ".f64" ||
Tok == ".f" || Tok == ".d";
}
static bool doesIgnoreDataTypeSuffix(StringRef Mnemonic, StringRef DT) {
return Mnemonic.startswith("vldm") || Mnemonic.startswith("vstm");
}
static void applyMnemonicAliases(StringRef &Mnemonic, unsigned Features);
bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc,
SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
unsigned AvailableFeatures = getAvailableFeatures();
applyMnemonicAliases(Name, AvailableFeatures);
if (Parser.getTok().is(AsmToken::Identifier) &&
Parser.getTok().getIdentifier() == ".req") {
parseDirectiveReq(Name, NameLoc);
return true;
}
size_t Start = 0, Next = Name.find('.');
StringRef Mnemonic = Name.slice(Start, Next);
unsigned PredicationCode;
unsigned ProcessorIMod;
bool CarrySetting;
StringRef ITMask;
Mnemonic = splitMnemonic(Mnemonic, PredicationCode, CarrySetting,
ProcessorIMod, ITMask);
if (isThumbOne() && PredicationCode != ARMCC::AL && Mnemonic != "b") {
Parser.EatToEndOfStatement();
return Error(NameLoc, "conditional execution not supported in Thumb1");
}
Operands.push_back(ARMOperand::CreateToken(Mnemonic, NameLoc));
if (Mnemonic == "it") {
SMLoc Loc = SMLoc::getFromPointer(NameLoc.getPointer() + 2);
if (ITMask.size() > 3) {
Parser.EatToEndOfStatement();
return Error(Loc, "too many conditions on IT instruction");
}
unsigned Mask = 8;
for (unsigned i = ITMask.size(); i != 0; --i) {
char pos = ITMask[i - 1];
if (pos != 't' && pos != 'e') {
Parser.EatToEndOfStatement();
return Error(Loc, "illegal IT block condition mask '" + ITMask + "'");
}
Mask >>= 1;
if (ITMask[i - 1] == 't')
Mask |= 8;
}
Operands.push_back(ARMOperand::CreateITMask(Mask, Loc));
}
bool CanAcceptCarrySet, CanAcceptPredicationCode;
getMnemonicAcceptInfo(Mnemonic, CanAcceptCarrySet, CanAcceptPredicationCode);
if (!CanAcceptCarrySet && CarrySetting) {
Parser.EatToEndOfStatement();
return Error(NameLoc, "instruction '" + Mnemonic +
"' can not set flags, but 's' suffix specified");
}
if (!CanAcceptPredicationCode && PredicationCode != ARMCC::AL) {
Parser.EatToEndOfStatement();
return Error(NameLoc, "instruction '" + Mnemonic +
"' is not predicable, but condition code specified");
}
if (CanAcceptCarrySet) {
SMLoc Loc = SMLoc::getFromPointer(NameLoc.getPointer() + Mnemonic.size());
Operands.push_back(ARMOperand::CreateCCOut(CarrySetting ? ARM::CPSR : 0,
Loc));
}
if (CanAcceptPredicationCode) {
SMLoc Loc = SMLoc::getFromPointer(NameLoc.getPointer() + Mnemonic.size() +
CarrySetting);
Operands.push_back(ARMOperand::CreateCondCode(
ARMCC::CondCodes(PredicationCode), Loc));
}
if (ProcessorIMod) {
Operands.push_back(ARMOperand::CreateImm(
MCConstantExpr::Create(ProcessorIMod, getContext()),
NameLoc, NameLoc));
}
while (Next != StringRef::npos) {
Start = Next;
Next = Name.find('.', Start + 1);
StringRef ExtraToken = Name.slice(Start, Next);
if (isDataTypeToken(ExtraToken) &&
doesIgnoreDataTypeSuffix(Mnemonic, ExtraToken))
continue;
if (ExtraToken != ".n") {
SMLoc Loc = SMLoc::getFromPointer(NameLoc.getPointer() + Start);
Operands.push_back(ARMOperand::CreateToken(ExtraToken, Loc));
}
}
if (getLexer().isNot(AsmToken::EndOfStatement)) {
if (parseOperand(Operands, Mnemonic)) {
Parser.EatToEndOfStatement();
return true;
}
while (getLexer().is(AsmToken::Comma)) {
Parser.Lex();
if (parseOperand(Operands, Mnemonic)) {
Parser.EatToEndOfStatement();
return true;
}
}
}
if (getLexer().isNot(AsmToken::EndOfStatement)) {
SMLoc Loc = getLexer().getLoc();
Parser.EatToEndOfStatement();
return Error(Loc, "unexpected token in argument list");
}
Parser.Lex();
if (!CarrySetting && shouldOmitCCOutOperand(Mnemonic, Operands)) {
ARMOperand *Op = static_cast<ARMOperand*>(Operands[1]);
Operands.erase(Operands.begin() + 1);
delete Op;
}
if (!isThumb() && Mnemonic == "blx" && Operands.size() == 3 &&
static_cast<ARMOperand*>(Operands[2])->isImm()) {
ARMOperand *Op = static_cast<ARMOperand*>(Operands[1]);
Operands.erase(Operands.begin() + 1);
delete Op;
}
if ((Mnemonic == "vceq" || Mnemonic == "vcge" || Mnemonic == "vcgt" ||
Mnemonic == "vcle" || Mnemonic == "vclt") && Operands.size() == 6 &&
static_cast<ARMOperand*>(Operands[5])->isImm()) {
ARMOperand *Op = static_cast<ARMOperand*>(Operands[5]);
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Op->getImm());
if (CE && CE->getValue() == 0) {
Operands.erase(Operands.begin() + 5);
Operands.push_back(ARMOperand::CreateToken("#0", Op->getStartLoc()));
delete Op;
}
}
if ((Mnemonic == "vcmp" || Mnemonic == "vcmpe") && Operands.size() == 5 &&
static_cast<ARMOperand*>(Operands[4])->isImm()) {
ARMOperand *Op = static_cast<ARMOperand*>(Operands[4]);
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Op->getImm());
if (CE && CE->getValue() == 0) {
Operands.erase(Operands.begin() + 4);
Operands.push_back(ARMOperand::CreateToken("#0", Op->getStartLoc()));
delete Op;
}
}
if (Mnemonic == "rsb" && isThumb() && Operands.size() == 6 &&
static_cast<ARMOperand*>(Operands[3])->isReg() &&
static_cast<ARMOperand*>(Operands[4])->isReg() &&
static_cast<ARMOperand*>(Operands[5])->isImm()) {
ARMOperand *Op = static_cast<ARMOperand*>(Operands[5]);
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Op->getImm());
if (CE && CE->getValue() == 0 &&
(isThumbOne() ||
((inITBlock() != CarrySetting) &&
(isARMLowRegister(static_cast<ARMOperand*>(Operands[3])->getReg()) &&
isARMLowRegister(static_cast<ARMOperand*>(Operands[4])->getReg()))))){
Operands.erase(Operands.begin() + 5);
Operands.push_back(ARMOperand::CreateToken("#0", Op->getStartLoc()));
delete Op;
}
}
return false;
}
static bool checkLowRegisterList(MCInst Inst, unsigned OpNo, unsigned Reg,
unsigned HiReg, bool &containsReg) {
containsReg = false;
for (unsigned i = OpNo; i < Inst.getNumOperands(); ++i) {
unsigned OpReg = Inst.getOperand(i).getReg();
if (OpReg == Reg)
containsReg = true;
if (!isARMLowRegister(OpReg) && (!HiReg || OpReg != HiReg))
return true;
}
return false;
}
static bool listContainsReg(MCInst &Inst, unsigned OpNo, unsigned Reg) {
for (unsigned i = OpNo; i < Inst.getNumOperands(); ++i) {
unsigned OpReg = Inst.getOperand(i).getReg();
if (OpReg == Reg)
return true;
}
return false;
}
namespace llvm {
extern const MCInstrDesc ARMInsts[];
}
static const MCInstrDesc &getInstDesc(unsigned Opcode) {
return ARMInsts[Opcode];
}
bool ARMAsmParser::
validateInstruction(MCInst &Inst,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode());
SMLoc Loc = Operands[0]->getStartLoc();
if (inITBlock() && Inst.getOpcode() != ARM::tBKPT) {
unsigned bit = 1;
if (ITState.FirstCond)
ITState.FirstCond = false;
else
bit = (ITState.Mask >> (5 - ITState.CurPosition)) & 1;
if (!MCID.isPredicable())
return Error(Loc, "instructions in IT block must be predicable");
unsigned Cond = Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm();
unsigned ITCond = bit ? ITState.Cond :
ARMCC::getOppositeCondition(ITState.Cond);
if (Cond != ITCond) {
SMLoc CondLoc;
for (unsigned i = 1; i < Operands.size(); ++i)
if (static_cast<ARMOperand*>(Operands[i])->isCondCode())
CondLoc = Operands[i]->getStartLoc();
return Error(CondLoc, "incorrect condition in IT block; got '" +
StringRef(ARMCondCodeToString(ARMCC::CondCodes(Cond))) +
"', but expected '" +
ARMCondCodeToString(ARMCC::CondCodes(ITCond)) + "'");
}
} else if (isThumbTwo() && MCID.isPredicable() &&
Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm() !=
ARMCC::AL && Inst.getOpcode() != ARM::tB &&
Inst.getOpcode() != ARM::t2B)
return Error(Loc, "predicated instructions must be in IT block");
switch (Inst.getOpcode()) {
case ARM::LDRD:
case ARM::LDRD_PRE:
case ARM::LDRD_POST:
case ARM::LDREXD: {
unsigned Rt = getARMRegisterNumbering(Inst.getOperand(0).getReg());
unsigned Rt2 = getARMRegisterNumbering(Inst.getOperand(1).getReg());
if (Rt2 != Rt + 1)
return Error(Operands[3]->getStartLoc(),
"destination operands must be sequential");
return false;
}
case ARM::STRD: {
unsigned Rt = getARMRegisterNumbering(Inst.getOperand(0).getReg());
unsigned Rt2 = getARMRegisterNumbering(Inst.getOperand(1).getReg());
if (Rt2 != Rt + 1)
return Error(Operands[3]->getStartLoc(),
"source operands must be sequential");
return false;
}
case ARM::STRD_PRE:
case ARM::STRD_POST:
case ARM::STREXD: {
unsigned Rt = getARMRegisterNumbering(Inst.getOperand(1).getReg());
unsigned Rt2 = getARMRegisterNumbering(Inst.getOperand(2).getReg());
if (Rt2 != Rt + 1)
return Error(Operands[3]->getStartLoc(),
"source operands must be sequential");
return false;
}
case ARM::SBFX:
case ARM::UBFX: {
unsigned lsb = Inst.getOperand(2).getImm();
unsigned widthm1 = Inst.getOperand(3).getImm();
if (widthm1 >= 32 - lsb)
return Error(Operands[5]->getStartLoc(),
"bitfield width must be in range [1,32-lsb]");
return false;
}
case ARM::tLDMIA: {
unsigned Rn = Inst.getOperand(0).getReg();
bool hasWritebackToken =
(static_cast<ARMOperand*>(Operands[3])->isToken() &&
static_cast<ARMOperand*>(Operands[3])->getToken() == "!");
bool listContainsBase;
if (checkLowRegisterList(Inst, 3, Rn, 0, listContainsBase) && !isThumbTwo())
return Error(Operands[3 + hasWritebackToken]->getStartLoc(),
"registers must be in range r0-r7");
if (!listContainsBase && !hasWritebackToken && !isThumbTwo())
return Error(Operands[2]->getStartLoc(),
"writeback operator '!' expected");
if (listContainsBase && hasWritebackToken)
return Error(Operands[3]->getStartLoc(),
"writeback operator '!' not allowed when base register "
"in register list");
break;
}
case ARM::t2LDMIA_UPD: {
if (listContainsReg(Inst, 3, Inst.getOperand(0).getReg()))
return Error(Operands[4]->getStartLoc(),
"writeback operator '!' not allowed when base register "
"in register list");
break;
}
case ARM::tPOP: {
bool listContainsBase;
if (checkLowRegisterList(Inst, 2, 0, ARM::PC, listContainsBase) &&
!isThumbTwo())
return Error(Operands[2]->getStartLoc(),
"registers must be in range r0-r7 or pc");
break;
}
case ARM::tPUSH: {
bool listContainsBase;
if (checkLowRegisterList(Inst, 2, 0, ARM::LR, listContainsBase) &&
!isThumbTwo())
return Error(Operands[2]->getStartLoc(),
"registers must be in range r0-r7 or lr");
break;
}
case ARM::tSTMIA_UPD: {
bool listContainsBase;
if (checkLowRegisterList(Inst, 4, 0, 0, listContainsBase) && !isThumbTwo())
return Error(Operands[4]->getStartLoc(),
"registers must be in range r0-r7");
break;
}
}
return false;
}
static unsigned getRealVSTLNOpcode(unsigned Opc) {
switch(Opc) {
default: assert(0 && "unexpected opcode!");
case ARM::VST1LNdWB_fixed_Asm_8: case ARM::VST1LNdWB_fixed_Asm_P8:
case ARM::VST1LNdWB_fixed_Asm_I8: case ARM::VST1LNdWB_fixed_Asm_S8:
case ARM::VST1LNdWB_fixed_Asm_U8:
return ARM::VST1LNd8_UPD;
case ARM::VST1LNdWB_fixed_Asm_16: case ARM::VST1LNdWB_fixed_Asm_P16:
case ARM::VST1LNdWB_fixed_Asm_I16: case ARM::VST1LNdWB_fixed_Asm_S16:
case ARM::VST1LNdWB_fixed_Asm_U16:
return ARM::VST1LNd16_UPD;
case ARM::VST1LNdWB_fixed_Asm_32: case ARM::VST1LNdWB_fixed_Asm_F:
case ARM::VST1LNdWB_fixed_Asm_F32: case ARM::VST1LNdWB_fixed_Asm_I32:
case ARM::VST1LNdWB_fixed_Asm_S32: case ARM::VST1LNdWB_fixed_Asm_U32:
return ARM::VST1LNd32_UPD;
case ARM::VST1LNdWB_register_Asm_8: case ARM::VST1LNdWB_register_Asm_P8:
case ARM::VST1LNdWB_register_Asm_I8: case ARM::VST1LNdWB_register_Asm_S8:
case ARM::VST1LNdWB_register_Asm_U8:
return ARM::VST1LNd8_UPD;
case ARM::VST1LNdWB_register_Asm_16: case ARM::VST1LNdWB_register_Asm_P16:
case ARM::VST1LNdWB_register_Asm_I16: case ARM::VST1LNdWB_register_Asm_S16:
case ARM::VST1LNdWB_register_Asm_U16:
return ARM::VST1LNd16_UPD;
case ARM::VST1LNdWB_register_Asm_32: case ARM::VST1LNdWB_register_Asm_F:
case ARM::VST1LNdWB_register_Asm_F32: case ARM::VST1LNdWB_register_Asm_I32:
case ARM::VST1LNdWB_register_Asm_S32: case ARM::VST1LNdWB_register_Asm_U32:
return ARM::VST1LNd32_UPD;
case ARM::VST1LNdAsm_8: case ARM::VST1LNdAsm_P8:
case ARM::VST1LNdAsm_I8: case ARM::VST1LNdAsm_S8:
case ARM::VST1LNdAsm_U8:
return ARM::VST1LNd8;
case ARM::VST1LNdAsm_16: case ARM::VST1LNdAsm_P16:
case ARM::VST1LNdAsm_I16: case ARM::VST1LNdAsm_S16:
case ARM::VST1LNdAsm_U16:
return ARM::VST1LNd16;
case ARM::VST1LNdAsm_32: case ARM::VST1LNdAsm_F:
case ARM::VST1LNdAsm_F32: case ARM::VST1LNdAsm_I32:
case ARM::VST1LNdAsm_S32: case ARM::VST1LNdAsm_U32:
return ARM::VST1LNd32;
case ARM::VST2LNdWB_fixed_Asm_8: case ARM::VST2LNdWB_fixed_Asm_P8:
case ARM::VST2LNdWB_fixed_Asm_I8: case ARM::VST2LNdWB_fixed_Asm_S8:
case ARM::VST2LNdWB_fixed_Asm_U8:
return ARM::VST2LNd8_UPD;
case ARM::VST2LNdWB_fixed_Asm_16: case ARM::VST2LNdWB_fixed_Asm_P16:
case ARM::VST2LNdWB_fixed_Asm_I16: case ARM::VST2LNdWB_fixed_Asm_S16:
case ARM::VST2LNdWB_fixed_Asm_U16:
return ARM::VST2LNd16_UPD;
case ARM::VST2LNdWB_fixed_Asm_32: case ARM::VST2LNdWB_fixed_Asm_F:
case ARM::VST2LNdWB_fixed_Asm_F32: case ARM::VST2LNdWB_fixed_Asm_I32:
case ARM::VST2LNdWB_fixed_Asm_S32: case ARM::VST2LNdWB_fixed_Asm_U32:
return ARM::VST2LNd32_UPD;
case ARM::VST2LNdWB_register_Asm_8: case ARM::VST2LNdWB_register_Asm_P8:
case ARM::VST2LNdWB_register_Asm_I8: case ARM::VST2LNdWB_register_Asm_S8:
case ARM::VST2LNdWB_register_Asm_U8:
return ARM::VST2LNd8_UPD;
case ARM::VST2LNdWB_register_Asm_16: case ARM::VST2LNdWB_register_Asm_P16:
case ARM::VST2LNdWB_register_Asm_I16: case ARM::VST2LNdWB_register_Asm_S16:
case ARM::VST2LNdWB_register_Asm_U16:
return ARM::VST2LNd16_UPD;
case ARM::VST2LNdWB_register_Asm_32: case ARM::VST2LNdWB_register_Asm_F:
case ARM::VST2LNdWB_register_Asm_F32: case ARM::VST2LNdWB_register_Asm_I32:
case ARM::VST2LNdWB_register_Asm_S32: case ARM::VST2LNdWB_register_Asm_U32:
return ARM::VST2LNd32_UPD;
case ARM::VST2LNdAsm_8: case ARM::VST2LNdAsm_P8:
case ARM::VST2LNdAsm_I8: case ARM::VST2LNdAsm_S8:
case ARM::VST2LNdAsm_U8:
return ARM::VST2LNd8;
case ARM::VST2LNdAsm_16: case ARM::VST2LNdAsm_P16:
case ARM::VST2LNdAsm_I16: case ARM::VST2LNdAsm_S16:
case ARM::VST2LNdAsm_U16:
return ARM::VST2LNd16;
case ARM::VST2LNdAsm_32: case ARM::VST2LNdAsm_F:
case ARM::VST2LNdAsm_F32: case ARM::VST2LNdAsm_I32:
case ARM::VST2LNdAsm_S32: case ARM::VST2LNdAsm_U32:
return ARM::VST2LNd32;
}
}
static unsigned getRealVLDLNOpcode(unsigned Opc) {
switch(Opc) {
default: assert(0 && "unexpected opcode!");
case ARM::VLD1LNdWB_fixed_Asm_8: case ARM::VLD1LNdWB_fixed_Asm_P8:
case ARM::VLD1LNdWB_fixed_Asm_I8: case ARM::VLD1LNdWB_fixed_Asm_S8:
case ARM::VLD1LNdWB_fixed_Asm_U8:
return ARM::VLD1LNd8_UPD;
case ARM::VLD1LNdWB_fixed_Asm_16: case ARM::VLD1LNdWB_fixed_Asm_P16:
case ARM::VLD1LNdWB_fixed_Asm_I16: case ARM::VLD1LNdWB_fixed_Asm_S16:
case ARM::VLD1LNdWB_fixed_Asm_U16:
return ARM::VLD1LNd16_UPD;
case ARM::VLD1LNdWB_fixed_Asm_32: case ARM::VLD1LNdWB_fixed_Asm_F:
case ARM::VLD1LNdWB_fixed_Asm_F32: case ARM::VLD1LNdWB_fixed_Asm_I32:
case ARM::VLD1LNdWB_fixed_Asm_S32: case ARM::VLD1LNdWB_fixed_Asm_U32:
return ARM::VLD1LNd32_UPD;
case ARM::VLD1LNdWB_register_Asm_8: case ARM::VLD1LNdWB_register_Asm_P8:
case ARM::VLD1LNdWB_register_Asm_I8: case ARM::VLD1LNdWB_register_Asm_S8:
case ARM::VLD1LNdWB_register_Asm_U8:
return ARM::VLD1LNd8_UPD;
case ARM::VLD1LNdWB_register_Asm_16: case ARM::VLD1LNdWB_register_Asm_P16:
case ARM::VLD1LNdWB_register_Asm_I16: case ARM::VLD1LNdWB_register_Asm_S16:
case ARM::VLD1LNdWB_register_Asm_U16:
return ARM::VLD1LNd16_UPD;
case ARM::VLD1LNdWB_register_Asm_32: case ARM::VLD1LNdWB_register_Asm_F:
case ARM::VLD1LNdWB_register_Asm_F32: case ARM::VLD1LNdWB_register_Asm_I32:
case ARM::VLD1LNdWB_register_Asm_S32: case ARM::VLD1LNdWB_register_Asm_U32:
return ARM::VLD1LNd32_UPD;
case ARM::VLD1LNdAsm_8: case ARM::VLD1LNdAsm_P8:
case ARM::VLD1LNdAsm_I8: case ARM::VLD1LNdAsm_S8:
case ARM::VLD1LNdAsm_U8:
return ARM::VLD1LNd8;
case ARM::VLD1LNdAsm_16: case ARM::VLD1LNdAsm_P16:
case ARM::VLD1LNdAsm_I16: case ARM::VLD1LNdAsm_S16:
case ARM::VLD1LNdAsm_U16:
return ARM::VLD1LNd16;
case ARM::VLD1LNdAsm_32: case ARM::VLD1LNdAsm_F:
case ARM::VLD1LNdAsm_F32: case ARM::VLD1LNdAsm_I32:
case ARM::VLD1LNdAsm_S32: case ARM::VLD1LNdAsm_U32:
return ARM::VLD1LNd32;
case ARM::VLD2LNdWB_fixed_Asm_8: case ARM::VLD2LNdWB_fixed_Asm_P8:
case ARM::VLD2LNdWB_fixed_Asm_I8: case ARM::VLD2LNdWB_fixed_Asm_S8:
case ARM::VLD2LNdWB_fixed_Asm_U8:
return ARM::VLD2LNd8_UPD;
case ARM::VLD2LNdWB_fixed_Asm_16: case ARM::VLD2LNdWB_fixed_Asm_P16:
case ARM::VLD2LNdWB_fixed_Asm_I16: case ARM::VLD2LNdWB_fixed_Asm_S16:
case ARM::VLD2LNdWB_fixed_Asm_U16:
return ARM::VLD2LNd16_UPD;
case ARM::VLD2LNdWB_fixed_Asm_32: case ARM::VLD2LNdWB_fixed_Asm_F:
case ARM::VLD2LNdWB_fixed_Asm_F32: case ARM::VLD2LNdWB_fixed_Asm_I32:
case ARM::VLD2LNdWB_fixed_Asm_S32: case ARM::VLD2LNdWB_fixed_Asm_U32:
return ARM::VLD2LNd32_UPD;
case ARM::VLD2LNdWB_register_Asm_8: case ARM::VLD2LNdWB_register_Asm_P8:
case ARM::VLD2LNdWB_register_Asm_I8: case ARM::VLD2LNdWB_register_Asm_S8:
case ARM::VLD2LNdWB_register_Asm_U8:
return ARM::VLD2LNd8_UPD;
case ARM::VLD2LNdWB_register_Asm_16: case ARM::VLD2LNdWB_register_Asm_P16:
case ARM::VLD2LNdWB_register_Asm_I16: case ARM::VLD2LNdWB_register_Asm_S16:
case ARM::VLD2LNdWB_register_Asm_U16:
return ARM::VLD2LNd16_UPD;
case ARM::VLD2LNdWB_register_Asm_32: case ARM::VLD2LNdWB_register_Asm_F:
case ARM::VLD2LNdWB_register_Asm_F32: case ARM::VLD2LNdWB_register_Asm_I32:
case ARM::VLD2LNdWB_register_Asm_S32: case ARM::VLD2LNdWB_register_Asm_U32:
return ARM::VLD2LNd32_UPD;
case ARM::VLD2LNdAsm_8: case ARM::VLD2LNdAsm_P8:
case ARM::VLD2LNdAsm_I8: case ARM::VLD2LNdAsm_S8:
case ARM::VLD2LNdAsm_U8:
return ARM::VLD2LNd8;
case ARM::VLD2LNdAsm_16: case ARM::VLD2LNdAsm_P16:
case ARM::VLD2LNdAsm_I16: case ARM::VLD2LNdAsm_S16:
case ARM::VLD2LNdAsm_U16:
return ARM::VLD2LNd16;
case ARM::VLD2LNdAsm_32: case ARM::VLD2LNdAsm_F:
case ARM::VLD2LNdAsm_F32: case ARM::VLD2LNdAsm_I32:
case ARM::VLD2LNdAsm_S32: case ARM::VLD2LNdAsm_U32:
return ARM::VLD2LNd32;
}
}
bool ARMAsmParser::
processInstruction(MCInst &Inst,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
switch (Inst.getOpcode()) {
case ARM::VST1LNdWB_register_Asm_8: case ARM::VST1LNdWB_register_Asm_P8:
case ARM::VST1LNdWB_register_Asm_I8: case ARM::VST1LNdWB_register_Asm_S8:
case ARM::VST1LNdWB_register_Asm_U8: case ARM::VST1LNdWB_register_Asm_16:
case ARM::VST1LNdWB_register_Asm_P16: case ARM::VST1LNdWB_register_Asm_I16:
case ARM::VST1LNdWB_register_Asm_S16: case ARM::VST1LNdWB_register_Asm_U16:
case ARM::VST1LNdWB_register_Asm_32: case ARM::VST1LNdWB_register_Asm_F:
case ARM::VST1LNdWB_register_Asm_F32: case ARM::VST1LNdWB_register_Asm_I32:
case ARM::VST1LNdWB_register_Asm_S32: case ARM::VST1LNdWB_register_Asm_U32: {
MCInst TmpInst;
TmpInst.setOpcode(getRealVSTLNOpcode(Inst.getOpcode()));
TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(3)); TmpInst.addOperand(Inst.getOperand(4)); TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(Inst.getOperand(1)); TmpInst.addOperand(Inst.getOperand(5)); TmpInst.addOperand(Inst.getOperand(6));
Inst = TmpInst;
return true;
}
case ARM::VST2LNdWB_register_Asm_8: case ARM::VST2LNdWB_register_Asm_P8:
case ARM::VST2LNdWB_register_Asm_I8: case ARM::VST2LNdWB_register_Asm_S8:
case ARM::VST2LNdWB_register_Asm_U8: case ARM::VST2LNdWB_register_Asm_16:
case ARM::VST2LNdWB_register_Asm_P16: case ARM::VST2LNdWB_register_Asm_I16:
case ARM::VST2LNdWB_register_Asm_S16: case ARM::VST2LNdWB_register_Asm_U16:
case ARM::VST2LNdWB_register_Asm_32: case ARM::VST2LNdWB_register_Asm_F:
case ARM::VST2LNdWB_register_Asm_F32: case ARM::VST2LNdWB_register_Asm_I32:
case ARM::VST2LNdWB_register_Asm_S32: case ARM::VST2LNdWB_register_Asm_U32: {
MCInst TmpInst;
TmpInst.setOpcode(getRealVSTLNOpcode(Inst.getOpcode()));
TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(3)); TmpInst.addOperand(Inst.getOperand(4)); TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(MCOperand::CreateReg(Inst.getOperand(0).getReg()+1));
TmpInst.addOperand(Inst.getOperand(1)); TmpInst.addOperand(Inst.getOperand(5)); TmpInst.addOperand(Inst.getOperand(6));
Inst = TmpInst;
return true;
}
case ARM::VST1LNdWB_fixed_Asm_8: case ARM::VST1LNdWB_fixed_Asm_P8:
case ARM::VST1LNdWB_fixed_Asm_I8: case ARM::VST1LNdWB_fixed_Asm_S8:
case ARM::VST1LNdWB_fixed_Asm_U8: case ARM::VST1LNdWB_fixed_Asm_16:
case ARM::VST1LNdWB_fixed_Asm_P16: case ARM::VST1LNdWB_fixed_Asm_I16:
case ARM::VST1LNdWB_fixed_Asm_S16: case ARM::VST1LNdWB_fixed_Asm_U16:
case ARM::VST1LNdWB_fixed_Asm_32: case ARM::VST1LNdWB_fixed_Asm_F:
case ARM::VST1LNdWB_fixed_Asm_F32: case ARM::VST1LNdWB_fixed_Asm_I32:
case ARM::VST1LNdWB_fixed_Asm_S32: case ARM::VST1LNdWB_fixed_Asm_U32: {
MCInst TmpInst;
TmpInst.setOpcode(getRealVSTLNOpcode(Inst.getOpcode()));
TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(3)); TmpInst.addOperand(MCOperand::CreateReg(0)); TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(Inst.getOperand(1)); TmpInst.addOperand(Inst.getOperand(4)); TmpInst.addOperand(Inst.getOperand(5));
Inst = TmpInst;
return true;
}
case ARM::VST2LNdWB_fixed_Asm_8: case ARM::VST2LNdWB_fixed_Asm_P8:
case ARM::VST2LNdWB_fixed_Asm_I8: case ARM::VST2LNdWB_fixed_Asm_S8:
case ARM::VST2LNdWB_fixed_Asm_U8: case ARM::VST2LNdWB_fixed_Asm_16:
case ARM::VST2LNdWB_fixed_Asm_P16: case ARM::VST2LNdWB_fixed_Asm_I16:
case ARM::VST2LNdWB_fixed_Asm_S16: case ARM::VST2LNdWB_fixed_Asm_U16:
case ARM::VST2LNdWB_fixed_Asm_32: case ARM::VST2LNdWB_fixed_Asm_F:
case ARM::VST2LNdWB_fixed_Asm_F32: case ARM::VST2LNdWB_fixed_Asm_I32:
case ARM::VST2LNdWB_fixed_Asm_S32: case ARM::VST2LNdWB_fixed_Asm_U32: {
MCInst TmpInst;
TmpInst.setOpcode(getRealVSTLNOpcode(Inst.getOpcode()));
TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(3)); TmpInst.addOperand(MCOperand::CreateReg(0)); TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(MCOperand::CreateReg(Inst.getOperand(0).getReg()+1));
TmpInst.addOperand(Inst.getOperand(1)); TmpInst.addOperand(Inst.getOperand(4)); TmpInst.addOperand(Inst.getOperand(5));
Inst = TmpInst;
return true;
}
case ARM::VST1LNdAsm_8: case ARM::VST1LNdAsm_P8: case ARM::VST1LNdAsm_I8:
case ARM::VST1LNdAsm_S8: case ARM::VST1LNdAsm_U8: case ARM::VST1LNdAsm_16:
case ARM::VST1LNdAsm_P16: case ARM::VST1LNdAsm_I16: case ARM::VST1LNdAsm_S16:
case ARM::VST1LNdAsm_U16: case ARM::VST1LNdAsm_32: case ARM::VST1LNdAsm_F:
case ARM::VST1LNdAsm_F32: case ARM::VST1LNdAsm_I32: case ARM::VST1LNdAsm_S32:
case ARM::VST1LNdAsm_U32: {
MCInst TmpInst;
TmpInst.setOpcode(getRealVSTLNOpcode(Inst.getOpcode()));
TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(3)); TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(Inst.getOperand(1)); TmpInst.addOperand(Inst.getOperand(4)); TmpInst.addOperand(Inst.getOperand(5));
Inst = TmpInst;
return true;
}
case ARM::VST2LNdAsm_8: case ARM::VST2LNdAsm_P8: case ARM::VST2LNdAsm_I8:
case ARM::VST2LNdAsm_S8: case ARM::VST2LNdAsm_U8: case ARM::VST2LNdAsm_16:
case ARM::VST2LNdAsm_P16: case ARM::VST2LNdAsm_I16: case ARM::VST2LNdAsm_S16:
case ARM::VST2LNdAsm_U16: case ARM::VST2LNdAsm_32: case ARM::VST2LNdAsm_F:
case ARM::VST2LNdAsm_F32: case ARM::VST2LNdAsm_I32: case ARM::VST2LNdAsm_S32:
case ARM::VST2LNdAsm_U32: {
MCInst TmpInst;
TmpInst.setOpcode(getRealVSTLNOpcode(Inst.getOpcode()));
TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(3)); TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(MCOperand::CreateReg(Inst.getOperand(0).getReg()+1));
TmpInst.addOperand(Inst.getOperand(1)); TmpInst.addOperand(Inst.getOperand(4)); TmpInst.addOperand(Inst.getOperand(5));
Inst = TmpInst;
return true;
}
case ARM::VLD1LNdWB_register_Asm_8: case ARM::VLD1LNdWB_register_Asm_P8:
case ARM::VLD1LNdWB_register_Asm_I8: case ARM::VLD1LNdWB_register_Asm_S8:
case ARM::VLD1LNdWB_register_Asm_U8: case ARM::VLD1LNdWB_register_Asm_16:
case ARM::VLD1LNdWB_register_Asm_P16: case ARM::VLD1LNdWB_register_Asm_I16:
case ARM::VLD1LNdWB_register_Asm_S16: case ARM::VLD1LNdWB_register_Asm_U16:
case ARM::VLD1LNdWB_register_Asm_32: case ARM::VLD1LNdWB_register_Asm_F:
case ARM::VLD1LNdWB_register_Asm_F32: case ARM::VLD1LNdWB_register_Asm_I32:
case ARM::VLD1LNdWB_register_Asm_S32: case ARM::VLD1LNdWB_register_Asm_U32: {
MCInst TmpInst;
TmpInst.setOpcode(getRealVLDLNOpcode(Inst.getOpcode()));
TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(3)); TmpInst.addOperand(Inst.getOperand(4)); TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(Inst.getOperand(1)); TmpInst.addOperand(Inst.getOperand(5)); TmpInst.addOperand(Inst.getOperand(6));
Inst = TmpInst;
return true;
}
case ARM::VLD2LNdWB_register_Asm_8: case ARM::VLD2LNdWB_register_Asm_P8:
case ARM::VLD2LNdWB_register_Asm_I8: case ARM::VLD2LNdWB_register_Asm_S8:
case ARM::VLD2LNdWB_register_Asm_U8: case ARM::VLD2LNdWB_register_Asm_16:
case ARM::VLD2LNdWB_register_Asm_P16: case ARM::VLD2LNdWB_register_Asm_I16:
case ARM::VLD2LNdWB_register_Asm_S16: case ARM::VLD2LNdWB_register_Asm_U16:
case ARM::VLD2LNdWB_register_Asm_32: case ARM::VLD2LNdWB_register_Asm_F:
case ARM::VLD2LNdWB_register_Asm_F32: case ARM::VLD2LNdWB_register_Asm_I32:
case ARM::VLD2LNdWB_register_Asm_S32: case ARM::VLD2LNdWB_register_Asm_U32: {
MCInst TmpInst;
TmpInst.setOpcode(getRealVLDLNOpcode(Inst.getOpcode()));
TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(MCOperand::CreateReg(Inst.getOperand(0).getReg()+1));
TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(3)); TmpInst.addOperand(Inst.getOperand(4)); TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(MCOperand::CreateReg(Inst.getOperand(0).getReg()+1));
TmpInst.addOperand(Inst.getOperand(1)); TmpInst.addOperand(Inst.getOperand(5)); TmpInst.addOperand(Inst.getOperand(6));
Inst = TmpInst;
return true;
}
case ARM::VLD1LNdWB_fixed_Asm_8: case ARM::VLD1LNdWB_fixed_Asm_P8:
case ARM::VLD1LNdWB_fixed_Asm_I8: case ARM::VLD1LNdWB_fixed_Asm_S8:
case ARM::VLD1LNdWB_fixed_Asm_U8: case ARM::VLD1LNdWB_fixed_Asm_16:
case ARM::VLD1LNdWB_fixed_Asm_P16: case ARM::VLD1LNdWB_fixed_Asm_I16:
case ARM::VLD1LNdWB_fixed_Asm_S16: case ARM::VLD1LNdWB_fixed_Asm_U16:
case ARM::VLD1LNdWB_fixed_Asm_32: case ARM::VLD1LNdWB_fixed_Asm_F:
case ARM::VLD1LNdWB_fixed_Asm_F32: case ARM::VLD1LNdWB_fixed_Asm_I32:
case ARM::VLD1LNdWB_fixed_Asm_S32: case ARM::VLD1LNdWB_fixed_Asm_U32: {
MCInst TmpInst;
TmpInst.setOpcode(getRealVLDLNOpcode(Inst.getOpcode()));
TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(3)); TmpInst.addOperand(MCOperand::CreateReg(0)); TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(Inst.getOperand(1)); TmpInst.addOperand(Inst.getOperand(4)); TmpInst.addOperand(Inst.getOperand(5));
Inst = TmpInst;
return true;
}
case ARM::VLD2LNdWB_fixed_Asm_8: case ARM::VLD2LNdWB_fixed_Asm_P8:
case ARM::VLD2LNdWB_fixed_Asm_I8: case ARM::VLD2LNdWB_fixed_Asm_S8:
case ARM::VLD2LNdWB_fixed_Asm_U8: case ARM::VLD2LNdWB_fixed_Asm_16:
case ARM::VLD2LNdWB_fixed_Asm_P16: case ARM::VLD2LNdWB_fixed_Asm_I16:
case ARM::VLD2LNdWB_fixed_Asm_S16: case ARM::VLD2LNdWB_fixed_Asm_U16:
case ARM::VLD2LNdWB_fixed_Asm_32: case ARM::VLD2LNdWB_fixed_Asm_F:
case ARM::VLD2LNdWB_fixed_Asm_F32: case ARM::VLD2LNdWB_fixed_Asm_I32:
case ARM::VLD2LNdWB_fixed_Asm_S32: case ARM::VLD2LNdWB_fixed_Asm_U32: {
MCInst TmpInst;
TmpInst.setOpcode(getRealVLDLNOpcode(Inst.getOpcode()));
TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(MCOperand::CreateReg(Inst.getOperand(0).getReg()+1));
TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(3)); TmpInst.addOperand(MCOperand::CreateReg(0)); TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(MCOperand::CreateReg(Inst.getOperand(0).getReg()+1));
TmpInst.addOperand(Inst.getOperand(1)); TmpInst.addOperand(Inst.getOperand(4)); TmpInst.addOperand(Inst.getOperand(5));
Inst = TmpInst;
return true;
}
case ARM::VLD1LNdAsm_8: case ARM::VLD1LNdAsm_P8: case ARM::VLD1LNdAsm_I8:
case ARM::VLD1LNdAsm_S8: case ARM::VLD1LNdAsm_U8: case ARM::VLD1LNdAsm_16:
case ARM::VLD1LNdAsm_P16: case ARM::VLD1LNdAsm_I16: case ARM::VLD1LNdAsm_S16:
case ARM::VLD1LNdAsm_U16: case ARM::VLD1LNdAsm_32: case ARM::VLD1LNdAsm_F:
case ARM::VLD1LNdAsm_F32: case ARM::VLD1LNdAsm_I32: case ARM::VLD1LNdAsm_S32:
case ARM::VLD1LNdAsm_U32: {
MCInst TmpInst;
TmpInst.setOpcode(getRealVLDLNOpcode(Inst.getOpcode()));
TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(3)); TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(Inst.getOperand(1)); TmpInst.addOperand(Inst.getOperand(4)); TmpInst.addOperand(Inst.getOperand(5));
Inst = TmpInst;
return true;
}
case ARM::VLD2LNdAsm_8: case ARM::VLD2LNdAsm_P8: case ARM::VLD2LNdAsm_I8:
case ARM::VLD2LNdAsm_S8: case ARM::VLD2LNdAsm_U8: case ARM::VLD2LNdAsm_16:
case ARM::VLD2LNdAsm_P16: case ARM::VLD2LNdAsm_I16: case ARM::VLD2LNdAsm_S16:
case ARM::VLD2LNdAsm_U16: case ARM::VLD2LNdAsm_32: case ARM::VLD2LNdAsm_F:
case ARM::VLD2LNdAsm_F32: case ARM::VLD2LNdAsm_I32: case ARM::VLD2LNdAsm_S32:
case ARM::VLD2LNdAsm_U32: {
MCInst TmpInst;
TmpInst.setOpcode(getRealVLDLNOpcode(Inst.getOpcode()));
TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(MCOperand::CreateReg(Inst.getOperand(0).getReg()+1));
TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(3)); TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(MCOperand::CreateReg(Inst.getOperand(0).getReg()+1));
TmpInst.addOperand(Inst.getOperand(1)); TmpInst.addOperand(Inst.getOperand(4)); TmpInst.addOperand(Inst.getOperand(5));
Inst = TmpInst;
return true;
}
case ARM::t2MOVsi:
case ARM::t2MOVSsi: {
bool isNarrow = false;
if (isARMLowRegister(Inst.getOperand(0).getReg()) &&
isARMLowRegister(Inst.getOperand(1).getReg()) &&
inITBlock() == (Inst.getOpcode() == ARM::t2MOVsi))
isNarrow = true;
MCInst TmpInst;
unsigned newOpc;
switch(ARM_AM::getSORegShOp(Inst.getOperand(2).getImm())) {
default: llvm_unreachable("unexpected opcode!");
case ARM_AM::asr: newOpc = isNarrow ? ARM::tASRri : ARM::t2ASRri; break;
case ARM_AM::lsr: newOpc = isNarrow ? ARM::tLSRri : ARM::t2LSRri; break;
case ARM_AM::lsl: newOpc = isNarrow ? ARM::tLSLri : ARM::t2LSLri; break;
case ARM_AM::ror: newOpc = ARM::t2RORri; isNarrow = false; break;
}
unsigned Ammount = ARM_AM::getSORegOffset(Inst.getOperand(2).getImm());
if (Ammount == 32) Ammount = 0;
TmpInst.setOpcode(newOpc);
TmpInst.addOperand(Inst.getOperand(0)); if (isNarrow)
TmpInst.addOperand(MCOperand::CreateReg(
Inst.getOpcode() == ARM::t2MOVSsi ? ARM::CPSR : 0));
TmpInst.addOperand(Inst.getOperand(1)); TmpInst.addOperand(MCOperand::CreateImm(Ammount));
TmpInst.addOperand(Inst.getOperand(3)); TmpInst.addOperand(Inst.getOperand(4));
if (!isNarrow)
TmpInst.addOperand(MCOperand::CreateReg(
Inst.getOpcode() == ARM::t2MOVSsi ? ARM::CPSR : 0));
Inst = TmpInst;
return true;
}
case ARM::ASRr:
case ARM::LSRr:
case ARM::LSLr:
case ARM::RORr: {
ARM_AM::ShiftOpc ShiftTy;
switch(Inst.getOpcode()) {
default: llvm_unreachable("unexpected opcode!");
case ARM::ASRr: ShiftTy = ARM_AM::asr; break;
case ARM::LSRr: ShiftTy = ARM_AM::lsr; break;
case ARM::LSLr: ShiftTy = ARM_AM::lsl; break;
case ARM::RORr: ShiftTy = ARM_AM::ror; break;
}
unsigned Shifter = ARM_AM::getSORegOpc(ShiftTy, 0);
MCInst TmpInst;
TmpInst.setOpcode(ARM::MOVsr);
TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(Inst.getOperand(1)); TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(MCOperand::CreateImm(Shifter)); TmpInst.addOperand(Inst.getOperand(3)); TmpInst.addOperand(Inst.getOperand(4));
TmpInst.addOperand(Inst.getOperand(5)); Inst = TmpInst;
return true;
}
case ARM::ASRi:
case ARM::LSRi:
case ARM::LSLi:
case ARM::RORi: {
ARM_AM::ShiftOpc ShiftTy;
switch(Inst.getOpcode()) {
default: llvm_unreachable("unexpected opcode!");
case ARM::ASRi: ShiftTy = ARM_AM::asr; break;
case ARM::LSRi: ShiftTy = ARM_AM::lsr; break;
case ARM::LSLi: ShiftTy = ARM_AM::lsl; break;
case ARM::RORi: ShiftTy = ARM_AM::ror; break;
}
unsigned Amt = Inst.getOperand(2).getImm();
unsigned Opc = Amt == 0 ? ARM::MOVr : ARM::MOVsi;
unsigned Shifter = ARM_AM::getSORegOpc(ShiftTy, Amt);
MCInst TmpInst;
TmpInst.setOpcode(Opc);
TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(Inst.getOperand(1)); if (Opc == ARM::MOVsi)
TmpInst.addOperand(MCOperand::CreateImm(Shifter)); TmpInst.addOperand(Inst.getOperand(3)); TmpInst.addOperand(Inst.getOperand(4));
TmpInst.addOperand(Inst.getOperand(5)); Inst = TmpInst;
return true;
}
case ARM::RRXi: {
unsigned Shifter = ARM_AM::getSORegOpc(ARM_AM::rrx, 0);
MCInst TmpInst;
TmpInst.setOpcode(ARM::MOVsi);
TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(Inst.getOperand(1)); TmpInst.addOperand(MCOperand::CreateImm(Shifter)); TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(3));
TmpInst.addOperand(Inst.getOperand(4)); Inst = TmpInst;
return true;
}
case ARM::t2LDMIA_UPD: {
if (Inst.getNumOperands() != 5)
return false;
MCInst TmpInst;
TmpInst.setOpcode(ARM::t2LDR_POST);
TmpInst.addOperand(Inst.getOperand(4)); TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(Inst.getOperand(1)); TmpInst.addOperand(MCOperand::CreateImm(4));
TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(3));
Inst = TmpInst;
return true;
}
case ARM::t2STMDB_UPD: {
if (Inst.getNumOperands() != 5)
return false;
MCInst TmpInst;
TmpInst.setOpcode(ARM::t2STR_PRE);
TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(Inst.getOperand(4)); TmpInst.addOperand(Inst.getOperand(1)); TmpInst.addOperand(MCOperand::CreateImm(-4));
TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(3));
Inst = TmpInst;
return true;
}
case ARM::LDMIA_UPD:
if (static_cast<ARMOperand*>(Operands[0])->getToken() == "pop" &&
Inst.getNumOperands() == 5) {
MCInst TmpInst;
TmpInst.setOpcode(ARM::LDR_POST_IMM);
TmpInst.addOperand(Inst.getOperand(4)); TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(Inst.getOperand(1)); TmpInst.addOperand(MCOperand::CreateReg(0)); TmpInst.addOperand(MCOperand::CreateImm(4));
TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(3));
Inst = TmpInst;
return true;
}
break;
case ARM::STMDB_UPD:
if (static_cast<ARMOperand*>(Operands[0])->getToken() == "push" &&
Inst.getNumOperands() == 5) {
MCInst TmpInst;
TmpInst.setOpcode(ARM::STR_PRE_IMM);
TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(Inst.getOperand(4)); TmpInst.addOperand(Inst.getOperand(1)); TmpInst.addOperand(MCOperand::CreateImm(-4));
TmpInst.addOperand(Inst.getOperand(2)); TmpInst.addOperand(Inst.getOperand(3));
Inst = TmpInst;
}
break;
case ARM::t2ADDri12:
if (static_cast<ARMOperand*>(Operands[0])->getToken() != "add" ||
ARM_AM::getT2SOImmVal(Inst.getOperand(2).getImm()) == -1)
break;
Inst.setOpcode(ARM::t2ADDri);
Inst.addOperand(MCOperand::CreateReg(0)); break;
case ARM::t2SUBri12:
if (static_cast<ARMOperand*>(Operands[0])->getToken() != "sub" ||
ARM_AM::getT2SOImmVal(Inst.getOperand(2).getImm()) == -1)
break;
Inst.setOpcode(ARM::t2SUBri);
Inst.addOperand(MCOperand::CreateReg(0)); break;
case ARM::tADDi8:
if (Inst.getOperand(3).getImm() < 8 && Operands.size() == 6) {
Inst.setOpcode(ARM::tADDi3);
return true;
}
break;
case ARM::tSUBi8:
if (Inst.getOperand(3).getImm() < 8 && Operands.size() == 6) {
Inst.setOpcode(ARM::tSUBi3);
return true;
}
break;
case ARM::t2ADDrr: {
if (Inst.getOperand(0).getReg() != Inst.getOperand(1).getReg() ||
Inst.getOperand(5).getReg() != 0 ||
(static_cast<ARMOperand*>(Operands[3])->isToken() &&
static_cast<ARMOperand*>(Operands[3])->getToken() == ".w"))
break;
MCInst TmpInst;
TmpInst.setOpcode(ARM::tADDhirr);
TmpInst.addOperand(Inst.getOperand(0));
TmpInst.addOperand(Inst.getOperand(0));
TmpInst.addOperand(Inst.getOperand(2));
TmpInst.addOperand(Inst.getOperand(3));
TmpInst.addOperand(Inst.getOperand(4));
Inst = TmpInst;
return true;
}
case ARM::tB:
if (Inst.getOperand(1).getImm() != ARMCC::AL && !inITBlock()) {
Inst.setOpcode(ARM::tBcc);
return true;
}
break;
case ARM::t2B:
if (Inst.getOperand(1).getImm() != ARMCC::AL && !inITBlock()){
Inst.setOpcode(ARM::t2Bcc);
return true;
}
break;
case ARM::t2Bcc:
if (Inst.getOperand(1).getImm() == ARMCC::AL || inITBlock()) {
Inst.setOpcode(ARM::t2B);
return true;
}
break;
case ARM::tBcc:
if (Inst.getOperand(1).getImm() == ARMCC::AL) {
Inst.setOpcode(ARM::tB);
return true;
}
break;
case ARM::tLDMIA: {
unsigned Rn = Inst.getOperand(0).getReg();
bool hasWritebackToken =
(static_cast<ARMOperand*>(Operands[3])->isToken() &&
static_cast<ARMOperand*>(Operands[3])->getToken() == "!");
bool listContainsBase;
if (checkLowRegisterList(Inst, 3, Rn, 0, listContainsBase) ||
(!listContainsBase && !hasWritebackToken) ||
(listContainsBase && hasWritebackToken)) {
assert (isThumbTwo());
Inst.setOpcode(hasWritebackToken ? ARM::t2LDMIA_UPD : ARM::t2LDMIA);
if (hasWritebackToken)
Inst.insert(Inst.begin(),
MCOperand::CreateReg(Inst.getOperand(0).getReg()));
return true;
}
break;
}
case ARM::tSTMIA_UPD: {
unsigned Rn = Inst.getOperand(0).getReg();
bool listContainsBase;
if (checkLowRegisterList(Inst, 4, Rn, 0, listContainsBase)) {
assert (isThumbTwo());
Inst.setOpcode(ARM::t2STMIA_UPD);
return true;
}
break;
}
case ARM::tPOP: {
bool listContainsBase;
if (!checkLowRegisterList(Inst, 2, 0, ARM::PC, listContainsBase))
return false;
assert (isThumbTwo());
Inst.setOpcode(ARM::t2LDMIA_UPD);
Inst.insert(Inst.begin(), MCOperand::CreateReg(ARM::SP));
Inst.insert(Inst.begin(), MCOperand::CreateReg(ARM::SP));
return true;
}
case ARM::tPUSH: {
bool listContainsBase;
if (!checkLowRegisterList(Inst, 2, 0, ARM::LR, listContainsBase))
return false;
assert (isThumbTwo());
Inst.setOpcode(ARM::t2STMDB_UPD);
Inst.insert(Inst.begin(), MCOperand::CreateReg(ARM::SP));
Inst.insert(Inst.begin(), MCOperand::CreateReg(ARM::SP));
return true;
}
case ARM::t2MOVi: {
if (isARMLowRegister(Inst.getOperand(0).getReg()) &&
Inst.getOperand(1).getImm() <= 255 &&
((!inITBlock() && Inst.getOperand(2).getImm() == ARMCC::AL &&
Inst.getOperand(4).getReg() == ARM::CPSR) ||
(inITBlock() && Inst.getOperand(4).getReg() == 0)) &&
(!static_cast<ARMOperand*>(Operands[2])->isToken() ||
static_cast<ARMOperand*>(Operands[2])->getToken() != ".w")) {
MCInst TmpInst;
TmpInst.setOpcode(ARM::tMOVi8);
TmpInst.addOperand(Inst.getOperand(0));
TmpInst.addOperand(Inst.getOperand(4));
TmpInst.addOperand(Inst.getOperand(1));
TmpInst.addOperand(Inst.getOperand(2));
TmpInst.addOperand(Inst.getOperand(3));
Inst = TmpInst;
return true;
}
break;
}
case ARM::t2MOVr: {
if (isARMLowRegister(Inst.getOperand(0).getReg()) &&
isARMLowRegister(Inst.getOperand(1).getReg()) &&
Inst.getOperand(2).getImm() == ARMCC::AL &&
Inst.getOperand(4).getReg() == ARM::CPSR &&
(!static_cast<ARMOperand*>(Operands[2])->isToken() ||
static_cast<ARMOperand*>(Operands[2])->getToken() != ".w")) {
MCInst TmpInst;
TmpInst.setOpcode(Inst.getOperand(4).getReg() ? ARM::tMOVSr : ARM::tMOVr);
TmpInst.addOperand(Inst.getOperand(0));
TmpInst.addOperand(Inst.getOperand(1));
TmpInst.addOperand(Inst.getOperand(2));
TmpInst.addOperand(Inst.getOperand(3));
Inst = TmpInst;
return true;
}
break;
}
case ARM::t2SXTH:
case ARM::t2SXTB:
case ARM::t2UXTH:
case ARM::t2UXTB: {
if (isARMLowRegister(Inst.getOperand(0).getReg()) &&
isARMLowRegister(Inst.getOperand(1).getReg()) &&
Inst.getOperand(2).getImm() == 0 &&
(!static_cast<ARMOperand*>(Operands[2])->isToken() ||
static_cast<ARMOperand*>(Operands[2])->getToken() != ".w")) {
unsigned NewOpc;
switch (Inst.getOpcode()) {
default: llvm_unreachable("Illegal opcode!");
case ARM::t2SXTH: NewOpc = ARM::tSXTH; break;
case ARM::t2SXTB: NewOpc = ARM::tSXTB; break;
case ARM::t2UXTH: NewOpc = ARM::tUXTH; break;
case ARM::t2UXTB: NewOpc = ARM::tUXTB; break;
}
MCInst TmpInst;
TmpInst.setOpcode(NewOpc);
TmpInst.addOperand(Inst.getOperand(0));
TmpInst.addOperand(Inst.getOperand(1));
TmpInst.addOperand(Inst.getOperand(3));
TmpInst.addOperand(Inst.getOperand(4));
Inst = TmpInst;
return true;
}
break;
}
case ARM::t2IT: {
MCOperand &MO = Inst.getOperand(1);
unsigned Mask = MO.getImm();
unsigned OrigMask = Mask;
unsigned TZ = CountTrailingZeros_32(Mask);
if ((Inst.getOperand(0).getImm() & 1) == 0) {
assert(Mask && TZ <= 3 && "illegal IT mask value!");
for (unsigned i = 3; i != TZ; --i)
Mask ^= 1 << i;
} else
Mask |= 0x10;
MO.setImm(Mask);
assert(!inITBlock() && "nested IT blocks?!");
ITState.Cond = ARMCC::CondCodes(Inst.getOperand(0).getImm());
ITState.Mask = OrigMask; ITState.CurPosition = 0;
ITState.FirstCond = true;
break;
}
}
return false;
}
unsigned ARMAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
unsigned Opc = Inst.getOpcode();
const MCInstrDesc &MCID = getInstDesc(Opc);
if (MCID.TSFlags & ARMII::ThumbArithFlagSetting) {
assert(MCID.hasOptionalDef() &&
"optionally flag setting instruction missing optional def operand");
assert(MCID.NumOperands == Inst.getNumOperands() &&
"operand count mismatch!");
unsigned OpNo;
for (OpNo = 0;
!MCID.OpInfo[OpNo].isOptionalDef() && OpNo < MCID.NumOperands;
++OpNo)
;
if (isThumbOne() && Inst.getOperand(OpNo).getReg() != ARM::CPSR)
return Match_MnemonicFail;
if (isThumbTwo() && Inst.getOperand(OpNo).getReg() != ARM::CPSR &&
!inITBlock())
return Match_RequiresITBlock;
if (isThumbTwo() && Inst.getOperand(OpNo).getReg() == ARM::CPSR &&
inITBlock())
return Match_RequiresNotITBlock;
}
else if (Opc == ARM::tADDhirr && isThumbOne() &&
isARMLowRegister(Inst.getOperand(1).getReg()) &&
isARMLowRegister(Inst.getOperand(2).getReg()))
return Match_RequiresThumb2;
else if (Opc == ARM::tMOVr && isThumbOne() && !hasV6Ops() &&
isARMLowRegister(Inst.getOperand(0).getReg()) &&
isARMLowRegister(Inst.getOperand(1).getReg()))
return Match_RequiresV6;
return Match_Success;
}
bool ARMAsmParser::
MatchAndEmitInstruction(SMLoc IDLoc,
SmallVectorImpl<MCParsedAsmOperand*> &Operands,
MCStreamer &Out) {
MCInst Inst;
unsigned ErrorInfo;
unsigned MatchResult;
MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo);
switch (MatchResult) {
default: break;
case Match_Success:
if (validateInstruction(Inst, Operands)) {
forwardITPosition();
return true;
}
while (processInstruction(Inst, Operands))
;
forwardITPosition();
Out.EmitInstruction(Inst);
return false;
case Match_MissingFeature:
Error(IDLoc, "instruction requires a CPU feature not currently enabled");
return true;
case Match_InvalidOperand: {
SMLoc ErrorLoc = IDLoc;
if (ErrorInfo != ~0U) {
if (ErrorInfo >= Operands.size())
return Error(IDLoc, "too few operands for instruction");
ErrorLoc = ((ARMOperand*)Operands[ErrorInfo])->getStartLoc();
if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc;
}
return Error(ErrorLoc, "invalid operand for instruction");
}
case Match_MnemonicFail:
return Error(IDLoc, "invalid instruction");
case Match_ConversionFail:
return true;
case Match_RequiresNotITBlock:
return Error(IDLoc, "flag setting instruction only valid outside IT block");
case Match_RequiresITBlock:
return Error(IDLoc, "instruction only valid inside IT block");
case Match_RequiresV6:
return Error(IDLoc, "instruction variant requires ARMv6 or later");
case Match_RequiresThumb2:
return Error(IDLoc, "instruction variant requires Thumb2");
}
llvm_unreachable("Implement any new match types added!");
return true;
}
bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) {
StringRef IDVal = DirectiveID.getIdentifier();
if (IDVal == ".word")
return parseDirectiveWord(4, DirectiveID.getLoc());
else if (IDVal == ".thumb")
return parseDirectiveThumb(DirectiveID.getLoc());
else if (IDVal == ".arm")
return parseDirectiveARM(DirectiveID.getLoc());
else if (IDVal == ".thumb_func")
return parseDirectiveThumbFunc(DirectiveID.getLoc());
else if (IDVal == ".code")
return parseDirectiveCode(DirectiveID.getLoc());
else if (IDVal == ".syntax")
return parseDirectiveSyntax(DirectiveID.getLoc());
else if (IDVal == ".unreq")
return parseDirectiveUnreq(DirectiveID.getLoc());
return true;
}
bool ARMAsmParser::parseDirectiveWord(unsigned Size, SMLoc L) {
if (getLexer().isNot(AsmToken::EndOfStatement)) {
for (;;) {
const MCExpr *Value;
if (getParser().ParseExpression(Value))
return true;
getParser().getStreamer().EmitValue(Value, Size, 0);
if (getLexer().is(AsmToken::EndOfStatement))
break;
if (getLexer().isNot(AsmToken::Comma))
return Error(L, "unexpected token in directive");
Parser.Lex();
}
}
Parser.Lex();
return false;
}
bool ARMAsmParser::parseDirectiveThumb(SMLoc L) {
if (getLexer().isNot(AsmToken::EndOfStatement))
return Error(L, "unexpected token in directive");
Parser.Lex();
if (!isThumb())
SwitchMode();
getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16);
return false;
}
bool ARMAsmParser::parseDirectiveARM(SMLoc L) {
if (getLexer().isNot(AsmToken::EndOfStatement))
return Error(L, "unexpected token in directive");
Parser.Lex();
if (isThumb())
SwitchMode();
getParser().getStreamer().EmitAssemblerFlag(MCAF_Code32);
return false;
}
bool ARMAsmParser::parseDirectiveThumbFunc(SMLoc L) {
const MCAsmInfo &MAI = getParser().getStreamer().getContext().getAsmInfo();
bool isMachO = MAI.hasSubsectionsViaSymbols();
StringRef Name;
if (isMachO) {
const AsmToken &Tok = Parser.getTok();
if (Tok.isNot(AsmToken::Identifier) && Tok.isNot(AsmToken::String))
return Error(L, "unexpected token in .thumb_func directive");
Name = Tok.getIdentifier();
Parser.Lex(); }
if (getLexer().isNot(AsmToken::EndOfStatement))
return Error(L, "unexpected token in directive");
Parser.Lex();
if (!isMachO) {
Name = Parser.getTok().getIdentifier();
}
MCSymbol *Func = getParser().getContext().GetOrCreateSymbol(Name);
getParser().getStreamer().EmitThumbFunc(Func);
return false;
}
bool ARMAsmParser::parseDirectiveSyntax(SMLoc L) {
const AsmToken &Tok = Parser.getTok();
if (Tok.isNot(AsmToken::Identifier))
return Error(L, "unexpected token in .syntax directive");
StringRef Mode = Tok.getString();
if (Mode == "unified" || Mode == "UNIFIED")
Parser.Lex();
else if (Mode == "divided" || Mode == "DIVIDED")
return Error(L, "'.syntax divided' arm asssembly not supported");
else
return Error(L, "unrecognized syntax mode in .syntax directive");
if (getLexer().isNot(AsmToken::EndOfStatement))
return Error(Parser.getTok().getLoc(), "unexpected token in directive");
Parser.Lex();
return false;
}
bool ARMAsmParser::parseDirectiveCode(SMLoc L) {
const AsmToken &Tok = Parser.getTok();
if (Tok.isNot(AsmToken::Integer))
return Error(L, "unexpected token in .code directive");
int64_t Val = Parser.getTok().getIntVal();
if (Val == 16)
Parser.Lex();
else if (Val == 32)
Parser.Lex();
else
return Error(L, "invalid operand to .code directive");
if (getLexer().isNot(AsmToken::EndOfStatement))
return Error(Parser.getTok().getLoc(), "unexpected token in directive");
Parser.Lex();
if (Val == 16) {
if (!isThumb())
SwitchMode();
getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16);
} else {
if (isThumb())
SwitchMode();
getParser().getStreamer().EmitAssemblerFlag(MCAF_Code32);
}
return false;
}
bool ARMAsmParser::parseDirectiveReq(StringRef Name, SMLoc L) {
Parser.Lex(); unsigned Reg;
SMLoc SRegLoc, ERegLoc;
if (ParseRegister(Reg, SRegLoc, ERegLoc)) {
Parser.EatToEndOfStatement();
return Error(SRegLoc, "register name expected");
}
if (Parser.getTok().isNot(AsmToken::EndOfStatement)) {
Parser.EatToEndOfStatement();
return Error(Parser.getTok().getLoc(),
"unexpected input in .req directive.");
}
Parser.Lex();
if (RegisterReqs.GetOrCreateValue(Name, Reg).getValue() != Reg)
return Error(SRegLoc, "redefinition of '" + Name +
"' does not match original.");
return false;
}
bool ARMAsmParser::parseDirectiveUnreq(SMLoc L) {
if (Parser.getTok().isNot(AsmToken::Identifier)) {
Parser.EatToEndOfStatement();
return Error(L, "unexpected input in .unreq directive.");
}
RegisterReqs.erase(Parser.getTok().getIdentifier());
Parser.Lex(); return false;
}
extern "C" void LLVMInitializeARMAsmLexer();
extern "C" void LLVMInitializeARMAsmParser() {
RegisterMCAsmParser<ARMAsmParser> X(TheARMTarget);
RegisterMCAsmParser<ARMAsmParser> Y(TheThumbTarget);
LLVMInitializeARMAsmLexer();
}
#define GET_REGISTER_MATCHER
#define GET_MATCHER_IMPLEMENTATION
#include "ARMGenAsmMatcher.inc"