+
+
+ bool isMemMode5() const {
+ if (!isMemory() || Mem.OffsetIsReg || Mem.OffsetRegShifted ||
+ Mem.Writeback || Mem.Negative)
+ return false;
+ // If there is an offset expression, make sure it's valid.
+ if (!Mem.Offset)
+ return true;
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Mem.Offset);
+ if (!CE)
+ return false;
+ // The offset must be a multiple of 4 in the range 0-1020.
+ int64_t Value = CE->getValue();
+ return ((Value & 0x3) == 0 && Value <= 1020 && Value >= -1020);
+ }
+
+ void addMemMode5Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 2 && isMemMode5() && "Invalid number of operands!");
+
+ Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum));
+ assert(!Mem.OffsetIsReg && "invalid mode 5 operand");
+
+ // FIXME: #-0 is encoded differently than #0. Does the parser preserve
+ // the difference?
+ if (Mem.Offset) {
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Mem.Offset);
+ assert(CE && "Non-constant mode 5 offset operand!");
+
+ // The MCInst offset operand doesn't include the low two bits (like
+ // the instruction encoding).
+ int64_t Offset = CE->getValue() / 4;
+ if (Offset >= 0)
+ Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(ARM_AM::add,
+ Offset)));
+ else
+ Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(ARM_AM::sub,
+ -Offset)));
+ } else {
+ Inst.addOperand(MCOperand::CreateImm(0));
+ }
+ }
+
+ virtual void dump(raw_ostream &OS) const;
+
+ static ARMOperand *CreateCondCode(ARMCC::CondCodes CC, SMLoc S) {
+ ARMOperand *Op = new ARMOperand(CondCode);
+ Op->CC.Val = CC;
+ Op->StartLoc = S;
+ Op->EndLoc = S;
+ return Op;
+ }
+
+ static ARMOperand *CreateToken(StringRef Str, SMLoc S) {
+ ARMOperand *Op = new ARMOperand(Token);
+ Op->Tok.Data = Str.data();
+ Op->Tok.Length = Str.size();
+ Op->StartLoc = S;
+ Op->EndLoc = S;
+ return Op;
+ }
+
+ static ARMOperand *CreateReg(unsigned RegNum, bool Writeback, SMLoc S,
+ SMLoc E) {
+ ARMOperand *Op = new ARMOperand(Register);
+ Op->Reg.RegNum = RegNum;
+ Op->Reg.Writeback = Writeback;
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ return Op;
+ }
+
+ static ARMOperand *CreateImm(const MCExpr *Val, SMLoc S, SMLoc E) {
+ ARMOperand *Op = new ARMOperand(Immediate);
+ Op->Imm.Val = Val;
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ return Op;
+ }
+
+ static ARMOperand *CreateMem(unsigned BaseRegNum, bool OffsetIsReg,
+ const MCExpr *Offset, unsigned OffsetRegNum,
+ bool OffsetRegShifted, enum ShiftType ShiftType,
+ const MCExpr *ShiftAmount, bool Preindexed,
+ bool Postindexed, bool Negative, bool Writeback,
+ SMLoc S, SMLoc E) {
+ ARMOperand *Op = new ARMOperand(Memory);
+ Op->Mem.BaseRegNum = BaseRegNum;
+ Op->Mem.OffsetIsReg = OffsetIsReg;
+ Op->Mem.Offset = Offset;
+ Op->Mem.OffsetRegNum = OffsetRegNum;
+ Op->Mem.OffsetRegShifted = OffsetRegShifted;
+ Op->Mem.ShiftType = ShiftType;
+ Op->Mem.ShiftAmount = ShiftAmount;
+ Op->Mem.Preindexed = Preindexed;
+ Op->Mem.Postindexed = Postindexed;
+ Op->Mem.Negative = Negative;
+ Op->Mem.Writeback = Writeback;
+
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ return Op;
+ }
+
+private:
+ ARMOperand(KindTy K) : Kind(K) {}