diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 8f81bd236ab..3f683d85bb2 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -665,11 +665,17 @@ def addrmode2 : Operand, let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$offsimm); } +def PostIdxRegShiftedAsmOperand : AsmOperandClass { + let Name = "PostIdxRegShifted"; + let ParserMethod = "parsePostIdxReg"; +} def am2offset_reg : Operand, ComplexPattern { let EncoderMethod = "getAddrMode2OffsetOpValue"; let PrintMethod = "printAddrMode2OffsetOperand"; + // When using this for assembly, it's always as a post-index offset. + let ParserMatchClass = PostIdxRegShiftedAsmOperand; let MIOperandInfo = (ops GPR, i32imm); } diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 6837d3622c3..5425c91e9d5 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -232,7 +232,9 @@ class ARMOperand : public MCParsedAsmOperand { struct { unsigned RegNum; - unsigned Imm; + bool isAdd; + ARM_AM::ShiftOpc ShiftTy; + unsigned ShiftImm; } PostIdxReg; struct { @@ -498,12 +500,15 @@ public: bool isToken() const { return Kind == Token; } bool isMemBarrierOpt() const { return Kind == MemBarrierOpt; } bool isMemory() const { return Kind == Memory; } - bool isPostIdxReg() const { return Kind == PostIndexRegister; } bool isShifterImm() const { return Kind == ShifterImmediate; } bool isRegShiftedReg() const { return Kind == ShiftedRegister; } bool isRegShiftedImm() const { return Kind == ShiftedImmediate; } bool isRotImm() const { return Kind == RotateImmediate; } bool isBitfield() const { return Kind == BitfieldDescriptor; } + bool isPostIdxRegShifted() const { return Kind == PostIndexRegister; } + bool isPostIdxReg() const { + return Kind == PostIndexRegister && PostIdxReg.ShiftTy == ARM_AM::no_shift; + } bool isMemNoOffset() const { if (Kind != Memory) return false; @@ -858,7 +863,18 @@ public: 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.Imm)); + 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)); + // The sign, shift type, and shift amount are encoded in a single operand + // using the AM2 encoding helpers. + 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 { @@ -1027,11 +1043,15 @@ public: return Op; } - static ARMOperand *CreatePostIdxReg(unsigned RegNum, unsigned Imm, + static ARMOperand *CreatePostIdxReg(unsigned RegNum, bool isAdd, + ARM_AM::ShiftOpc ShiftTy, + unsigned ShiftImm, SMLoc S, SMLoc E) { ARMOperand *Op = new ARMOperand(PostIndexRegister); Op->PostIdxReg.RegNum = RegNum; - Op->PostIdxReg.Imm = Imm; + Op->PostIdxReg.isAdd = isAdd; + Op->PostIdxReg.ShiftTy = ShiftTy; + Op->PostIdxReg.ShiftImm = ShiftImm; Op->StartLoc = S; Op->EndLoc = E; return Op; @@ -1093,9 +1113,12 @@ void ARMOperand::print(raw_ostream &OS) const { OS << ">"; break; case PostIndexRegister: - OS << "post-idx register " << (PostIdxReg.Imm ? "" : "-") - << PostIdxReg.RegNum - << ">"; + 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 ProcIFlags: { OS << " &Operands) { ARMAsmParser::OperandMatchResultTy ARMAsmParser:: parsePostIdxReg(SmallVectorImpl &Operands) { // Check for a post-index addressing register operand. Specifically: - // postidx_reg := '+' register - // | '-' register - // | register + // postidx_reg := '+' register {, shift} + // | '-' register {, shift} + // | register {, shift} // This method must return MatchOperand_NoMatch without consuming any tokens // in the case where there is no match, as other alternatives take other @@ -1891,7 +1914,11 @@ parsePostIdxReg(SmallVectorImpl &Operands) { } SMLoc E = Parser.getTok().getLoc(); - Operands.push_back(ARMOperand::CreatePostIdxReg(Reg, isAdd, S, E)); + ARM_AM::ShiftOpc ShiftTy = ARM_AM::no_shift; + unsigned ShiftImm = 0; + + Operands.push_back(ARMOperand::CreatePostIdxReg(Reg, isAdd, ShiftTy, + ShiftImm, S, E)); return MatchOperand_Success; } @@ -2107,7 +2134,12 @@ parseMemory(SmallVectorImpl &Operands) { ShiftType, ShiftValue, isNegative, S, E)); - + // If there's a pre-indexing writeback marker, '!', just add it as a token + // operand. + if (Parser.getTok().is(AsmToken::Exclaim)) { + Operands.push_back(ARMOperand::CreateToken("!",Parser.getTok().getLoc())); + Parser.Lex(); // Eat the '!'. + } return false; } diff --git a/test/MC/ARM/arm-memory-instructions.s b/test/MC/ARM/arm-memory-instructions.s index f715e850599..765a96e8aa8 100644 --- a/test/MC/ARM/arm-memory-instructions.s +++ b/test/MC/ARM/arm-memory-instructions.s @@ -24,3 +24,19 @@ _func: @ CHECK: ldr r3, [r1], #-30 @ encoding: [0x1e,0x30,0x11,0xe4] +@------------------------------------------------------------------------------ +@ LDR (register) +@------------------------------------------------------------------------------ + ldr r3, [r8, r1] + ldr r2, [r5, -r3] + ldr r1, [r5, r9]! + ldr r6, [r7, -r8]! + ldr r5, [r9], r2 + ldr r4, [r3], -r6 + +@ CHECK: ldr r3, [r8, r1] @ encoding: [0x01,0x30,0x98,0xe7] +@ CHECK: ldr r2, [r5, -r3] @ encoding: [0x03,0x20,0x15,0xe7] +@ CHECK: ldr r1, [r5, r9]! @ encoding: [0x09,0x10,0xb5,0xe7] +@ CHECK: ldr r6, [r7, -r8]! @ encoding: [0x08,0x60,0x37,0xe7] +@ CHECK: ldr r5, [r9], r2 @ encoding: [0x02,0x50,0x99,0xe6] +@ CHECK: ldr r4, [r3], -r6 @ encoding: [0x06,0x40,0x13,0xe6]