bool shouldOmitPredicateOperand(StringRef Mnemonic, OperandVector &Operands);
bool isITBlockTerminator(MCInst &Inst) const;
void fixupGNULDRDAlias(StringRef Mnemonic, OperandVector &Operands);
+ bool validateLDRDSTRD(MCInst &Inst, const OperandVector &Operands,
+ bool Load, bool ARMMode, bool Writeback);
public:
enum ARMMatchResultTy {
return false;
}
+bool ARMAsmParser::validateLDRDSTRD(MCInst &Inst,
+ const OperandVector &Operands,
+ bool Load, bool ARMMode, bool Writeback) {
+ unsigned RtIndex = Load || !Writeback ? 0 : 1;
+ unsigned Rt = MRI->getEncodingValue(Inst.getOperand(RtIndex).getReg());
+ unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(RtIndex + 1).getReg());
+
+ if (ARMMode) {
+ // Rt can't be R14.
+ if (Rt == 14)
+ return Error(Operands[3]->getStartLoc(),
+ "Rt can't be R14");
+
+ // Rt must be even-numbered.
+ if ((Rt & 1) == 1)
+ return Error(Operands[3]->getStartLoc(),
+ "Rt must be even-numbered");
+
+ // Rt2 must be Rt + 1.
+ if (Rt2 != Rt + 1) {
+ if (Load)
+ return Error(Operands[3]->getStartLoc(),
+ "destination operands must be sequential");
+ else
+ return Error(Operands[3]->getStartLoc(),
+ "source operands must be sequential");
+ }
+
+ // FIXME: Diagnose m == 15
+ // FIXME: Diagnose ldrd with m == t || m == t2.
+ }
+
+ if (!ARMMode && Load) {
+ if (Rt2 == Rt)
+ return Error(Operands[3]->getStartLoc(),
+ "destination operands can't be identical");
+ }
+
+ if (Writeback) {
+ unsigned Rn = MRI->getEncodingValue(Inst.getOperand(3).getReg());
+
+ if (Rn == Rt || Rn == Rt2) {
+ if (Load)
+ return Error(Operands[3]->getStartLoc(),
+ "base register needs to be different from destination "
+ "registers");
+ else
+ return Error(Operands[3]->getStartLoc(),
+ "source register and base register can't be identical");
+ }
+
+ // FIXME: Diagnose ldrd/strd with writeback and n == 15.
+ // (Except the immediate form of ldrd?)
+ }
+
+ return false;
+}
+
+
// FIXME: We would really like to be able to tablegen'erate this.
bool ARMAsmParser::validateInstruction(MCInst &Inst,
const OperandVector &Operands) {
break;
}
case ARM::LDRD:
+ if (validateLDRDSTRD(Inst, Operands, /*Load*/true, /*ARMMode*/true,
+ /*Writeback*/false))
+ return true;
+ break;
case ARM::LDRD_PRE:
- case ARM::LDRD_POST: {
- const unsigned RtReg = Inst.getOperand(0).getReg();
-
- // Rt can't be R14.
- if (RtReg == ARM::LR)
- return Error(Operands[3]->getStartLoc(),
- "Rt can't be R14");
-
- const unsigned Rt = MRI->getEncodingValue(RtReg);
- // Rt must be even-numbered.
- if ((Rt & 1) == 1)
- return Error(Operands[3]->getStartLoc(),
- "Rt must be even-numbered");
-
- // Rt2 must be Rt + 1.
- const unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(1).getReg());
- if (Rt2 != Rt + 1)
- return Error(Operands[3]->getStartLoc(),
- "destination operands must be sequential");
-
- if (Opcode == ARM::LDRD_PRE || Opcode == ARM::LDRD_POST) {
- const unsigned Rn = MRI->getEncodingValue(Inst.getOperand(3).getReg());
- // For addressing modes with writeback, the base register needs to be
- // different from the destination registers.
- if (Rn == Rt || Rn == Rt2)
- return Error(Operands[3]->getStartLoc(),
- "base register needs to be different from destination "
- "registers");
- }
-
- return false;
- }
+ case ARM::LDRD_POST:
+ if (validateLDRDSTRD(Inst, Operands, /*Load*/true, /*ARMMode*/true,
+ /*Writeback*/true))
+ return true;
+ break;
case ARM::t2LDRDi8:
+ if (validateLDRDSTRD(Inst, Operands, /*Load*/true, /*ARMMode*/false,
+ /*Writeback*/false))
+ return true;
+ break;
case ARM::t2LDRD_PRE:
- case ARM::t2LDRD_POST: {
- // Rt2 must be different from Rt.
- unsigned Rt = MRI->getEncodingValue(Inst.getOperand(0).getReg());
- unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(1).getReg());
- if (Rt2 == Rt)
- return Error(Operands[3]->getStartLoc(),
- "destination operands can't be identical");
- return false;
- }
+ case ARM::t2LDRD_POST:
+ if (validateLDRDSTRD(Inst, Operands, /*Load*/true, /*ARMMode*/false,
+ /*Writeback*/true))
+ return true;
+ break;
case ARM::t2BXJ: {
const unsigned RmReg = Inst.getOperand(0).getReg();
// Rm = SP is no longer unpredictable in v8-A
"r13 (SP) is an unpredictable operand to BXJ");
return false;
}
- case ARM::STRD: {
- // Rt2 must be Rt + 1.
- unsigned Rt = MRI->getEncodingValue(Inst.getOperand(0).getReg());
- unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(1).getReg());
- if (Rt2 != Rt + 1)
- return Error(Operands[3]->getStartLoc(),
- "source operands must be sequential");
- return false;
- }
+ case ARM::STRD:
+ if (validateLDRDSTRD(Inst, Operands, /*Load*/false, /*ARMMode*/true,
+ /*Writeback*/false))
+ return true;
+ break;
case ARM::STRD_PRE:
- case ARM::STRD_POST: {
- // Rt2 must be Rt + 1.
- unsigned Rt = MRI->getEncodingValue(Inst.getOperand(1).getReg());
- unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(2).getReg());
- if (Rt2 != Rt + 1)
- return Error(Operands[3]->getStartLoc(),
- "source operands must be sequential");
- return false;
- }
+ case ARM::STRD_POST:
+ if (validateLDRDSTRD(Inst, Operands, /*Load*/false, /*ARMMode*/true,
+ /*Writeback*/true))
+ return true;
+ break;
+ case ARM::t2STRD_PRE:
+ case ARM::t2STRD_POST:
+ if (validateLDRDSTRD(Inst, Operands, /*Load*/false, /*ARMMode*/false,
+ /*Writeback*/true))
+ return true;
+ break;
case ARM::STR_PRE_IMM:
case ARM::STR_PRE_REG:
+ case ARM::t2STR_PRE:
case ARM::STR_POST_IMM:
case ARM::STR_POST_REG:
+ case ARM::t2STR_POST:
case ARM::STRH_PRE:
+ case ARM::t2STRH_PRE:
case ARM::STRH_POST:
+ case ARM::t2STRH_POST:
case ARM::STRB_PRE_IMM:
case ARM::STRB_PRE_REG:
+ case ARM::t2STRB_PRE:
case ARM::STRB_POST_IMM:
- case ARM::STRB_POST_REG: {
+ case ARM::STRB_POST_REG:
+ case ARM::t2STRB_POST: {
// Rt must be different from Rn.
const unsigned Rt = MRI->getEncodingValue(Inst.getOperand(1).getReg());
const unsigned Rn = MRI->getEncodingValue(Inst.getOperand(2).getReg());
}
case ARM::LDR_PRE_IMM:
case ARM::LDR_PRE_REG:
+ case ARM::t2LDR_PRE:
case ARM::LDR_POST_IMM:
case ARM::LDR_POST_REG:
+ case ARM::t2LDR_POST:
case ARM::LDRH_PRE:
+ case ARM::t2LDRH_PRE:
case ARM::LDRH_POST:
+ case ARM::t2LDRH_POST:
case ARM::LDRSH_PRE:
+ case ARM::t2LDRSH_PRE:
case ARM::LDRSH_POST:
+ case ARM::t2LDRSH_POST:
case ARM::LDRB_PRE_IMM:
case ARM::LDRB_PRE_REG:
+ case ARM::t2LDRB_PRE:
case ARM::LDRB_POST_IMM:
case ARM::LDRB_POST_REG:
+ case ARM::t2LDRB_POST:
case ARM::LDRSB_PRE:
- case ARM::LDRSB_POST: {
+ case ARM::t2LDRSB_PRE:
+ case ARM::LDRSB_POST:
+ case ARM::t2LDRSB_POST: {
// Rt must be different from Rn.
const unsigned Rt = MRI->getEncodingValue(Inst.getOperand(0).getReg());
const unsigned Rn = MRI->getEncodingValue(Inst.getOperand(2).getReg());
return false;
}
case ARM::SBFX:
- case ARM::UBFX: {
+ case ARM::t2SBFX:
+ case ARM::UBFX:
+ case ARM::t2UBFX: {
// Width must be in range [1, 32-lsb].
unsigned LSB = Inst.getOperand(2).getImm();
unsigned Widthm1 = Inst.getOperand(3).getImm();
@------------------------------------------------------------------------------
@ STRD (immediate)
@------------------------------------------------------------------------------
- strd r1, r2, [r4]
+ strd r2, r3, [r4]
strd r2, r3, [r6, #1]
- strd r3, r4, [r7, #22]!
+ strd r0, r1, [r7, #22]!
strd r4, r5, [r8], #7
- strd r5, r6, [sp], #0
+ strd r4, r5, [sp], #0
strd r6, r7, [lr], #+0
- strd r7, r8, [r9], #-0
+ strd r10, r11, [r9], #-0
-@ CHECK: strd r1, r2, [r4] @ encoding: [0xf0,0x10,0xc4,0xe1]
+@ CHECK: strd r2, r3, [r4] @ encoding: [0xf0,0x20,0xc4,0xe1]
@ CHECK: strd r2, r3, [r6, #1] @ encoding: [0xf1,0x20,0xc6,0xe1]
-@ CHECK: strd r3, r4, [r7, #22]! @ encoding: [0xf6,0x31,0xe7,0xe1]
+@ CHECK: strd r0, r1, [r7, #22]! @ encoding: [0xf6,0x01,0xe7,0xe1]
@ CHECK: strd r4, r5, [r8], #7 @ encoding: [0xf7,0x40,0xc8,0xe0]
-@ CHECK: strd r5, r6, [sp], #0 @ encoding: [0xf0,0x50,0xcd,0xe0]
+@ CHECK: strd r4, r5, [sp], #0 @ encoding: [0xf0,0x40,0xcd,0xe0]
@ CHECK: strd r6, r7, [lr], #0 @ encoding: [0xf0,0x60,0xce,0xe0]
-@ CHECK: strd r7, r8, [r9], #-0 @ encoding: [0xf0,0x70,0x49,0xe0]
+@ CHECK: strd r10, r11, [r9], #-0 @ encoding: [0xf0,0xa0,0x49,0xe0]
@------------------------------------------------------------------------------
@ STRD (register)
@------------------------------------------------------------------------------
strd r8, r9, [r4, r1]
- strd r7, r8, [r3, r9]!
+ strd r6, r7, [r3, r9]!
strd r6, r7, [r5], r8
- strd r5, r6, [r12], -r10
+ strd r4, r5, [r12], -r10
@ CHECK: strd r8, r9, [r4, r1] @ encoding: [0xf1,0x80,0x84,0xe1]
-@ CHECK: strd r7, r8, [r3, r9]! @ encoding: [0xf9,0x70,0xa3,0xe1]
+@ CHECK: strd r6, r7, [r3, r9]! @ encoding: [0xf9,0x60,0xa3,0xe1]
@ CHECK: strd r6, r7, [r5], r8 @ encoding: [0xf8,0x60,0x85,0xe0]
-@ CHECK: strd r5, r6, [r12], -r10 @ encoding: [0xfa,0x50,0x0c,0xe0]
+@ CHECK: strd r4, r5, [r12], -r10 @ encoding: [0xfa,0x40,0x0c,0xe0]
@------------------------------------------------------------------------------
@ CHECK-ERRORS: ubfx r14, pc, #1, #2
@ CHECK-ERRORS: ^
- @ Out of order Rt/Rt2 operands for ldrd
+ @ Out of order Rt/Rt2 operands for ldrd/strd
ldrd r4, r3, [r8]
ldrd r4, r3, [r8, #8]!
ldrd r4, r3, [r8], #8
+ strd r4, r3, [r8]
+ strd r4, r3, [r8, #8]!
+ strd r4, r3, [r8], #8
@ CHECK-ERRORS: error: destination operands must be sequential
@ CHECK-ERRORS: ldrd r4, r3, [r8]
@ CHECK-ERRORS: ^
@ CHECK-ERRORS: error: destination operands must be sequential
@ CHECK-ERRORS: ldrd r4, r3, [r8], #8
@ CHECK-ERRORS: ^
+@ CHECK-ERRORS: error: source operands must be sequential
+@ CHECK-ERRORS: strd r4, r3, [r8]
+@ CHECK-ERRORS: ^
+@ CHECK-ERRORS: error: source operands must be sequential
+@ CHECK-ERRORS: strd r4, r3, [r8, #8]!
+@ CHECK-ERRORS: ^
+@ CHECK-ERRORS: error: source operands must be sequential
+@ CHECK-ERRORS: strd r4, r3, [r8], #8
+@ CHECK-ERRORS: ^
+
+ @ Odd first register for ldrd/strd
+ ldrd r5, r6, [r8]
+ strd r5, r6, [r8]
+@ CHECK-ERRORS: error: Rt must be even-numbered
+@ CHECK-ERRORS: ldrd r5, r6, [r8]
+@ CHECK-ERRORS: ^
+@ CHECK-ERRORS: error: Rt must be even-numbered
+@ CHECK-ERRORS: strd r5, r6, [r8]
+@ CHECK-ERRORS: ^
+
+ @ Post-increment with base equal to source
+ ldrd r6, r7, [r6]!
+ ldrd r6, r7, [r7]!
+ strd r6, r7, [r6]!
+ strd r6, r7, [r7]!
+@ CHECK-ERRORS: error: base register needs to be different from destination registers
+@ CHECK-ERRORS: ldrd r6, r7, [r6]!
+@ CHECK-ERRORS: ^
+@ CHECK-ERRORS: error: base register needs to be different from destination registers
+@ CHECK-ERRORS: ldrd r6, r7, [r7]!
+@ CHECK-ERRORS: ^
+@ CHECK-ERRORS: error: source register and base register can't be identical
+@ CHECK-ERRORS: strd r6, r7, [r6]!
+@ CHECK-ERRORS: ^
+@ CHECK-ERRORS: error: source register and base register can't be identical
+@ CHECK-ERRORS: strd r6, r7, [r7]!
+@ CHECK-ERRORS: ^
+
+ @ Paired load/store of pc
+ ldrd lr, pc, [r6]!
+ strd lr, pc, [r6]!
+@ CHECK-ERRORS: error: Rt can't be R14
+@ CHECK-ERRORS: ldrd lr, pc, [r6]!
+@ CHECK-ERRORS: ^
+@ CHECK-ERRORS: error: Rt can't be R14
+@ CHECK-ERRORS: strd lr, pc, [r6]!
+@ CHECK-ERRORS: ^
@ Bad register lists for VFP.
adds r0
@ CHECK-ERRORS: error: too few operands for instruction
@ CHECK-ERRORS: error: too few operands for instruction
+
+@------------------------------------------------------------------------------
+@ Out of range width for SBFX/UBFX
+@------------------------------------------------------------------------------
+
+ sbfx r4, r5, #31, #2
+ ubfx r4, r5, #16, #17
+
+@ CHECK-ERRORS-V8: error: bitfield width must be in range [1,32-lsb]
+@ CHECK-ERRORS-V8: sbfx r4, r5, #31, #2
+@ CHECK-ERRORS-V8: ^
+@ CHECK-ERRORS-V8: error: bitfield width must be in range [1,32-lsb]
+@ CHECK-ERRORS-V8: ubfx r4, r5, #16, #17
+@ CHECK-ERRORS-V8: ^
+
+@------------------------------------------------------------------------------
+@ Writeback store writing to same register as value
+@------------------------------------------------------------------------------
+
+ str r0, [r0, #4]!
+ str r0, [r0], #4
+ strh r0, [r0, #2]!
+ strh r0, [r0], #2
+ strb r0, [r0, #1]!
+ strb r0, [r0], #1
+ strd r0, r1, [r0], #1
+ strd r1, r0, [r0], #1
+@ CHECK-ERRORS-V8: error: source register and base register can't be identical
+@ CHECK-ERRORS-V8: str r0, [r0, #4]!
+@ CHECK-ERRORS-V8: ^
+@ CHECK-ERRORS-V8: error: source register and base register can't be identical
+@ CHECK-ERRORS-V8: str r0, [r0], #4
+@ CHECK-ERRORS-V8: ^
+@ CHECK-ERRORS-V8: error: source register and base register can't be identical
+@ CHECK-ERRORS-V8: strh r0, [r0, #2]!
+@ CHECK-ERRORS-V8: ^
+@ CHECK-ERRORS-V8: error: source register and base register can't be identical
+@ CHECK-ERRORS-V8: strh r0, [r0], #2
+@ CHECK-ERRORS-V8: ^
+@ CHECK-ERRORS-V8: error: source register and base register can't be identical
+@ CHECK-ERRORS-V8: strb r0, [r0, #1]!
+@ CHECK-ERRORS-V8: ^
+@ CHECK-ERRORS-V8: error: source register and base register can't be identical
+@ CHECK-ERRORS-V8: strb r0, [r0], #1
+@ CHECK-ERRORS-V8: ^
+@ CHECK-ERRORS-V8: error: source register and base register can't be identical
+@ CHECK-ERRORS-V8: strd r0, r1, [r0], #1
+@ CHECK-ERRORS-V8: ^
+@ CHECK-ERRORS-V8: error: source register and base register can't be identical
+@ CHECK-ERRORS-V8: strd r1, r0, [r0], #1
+@ CHECK-ERRORS-V8: ^
strexge r0, r0, [pc]
@ CHECK: [[@LINE+2]]:1: warning: deprecated instruction in IT block
it ge
-strdge r0, r0, [r0], #-0
-@ CHECK: :[[@LINE+2]]:1: warning: deprecated instruction in IT block
-it ge
strdge r0, r0, [r1], #-0
@ CHECK: :[[@LINE+2]]:1: warning: deprecated instruction in IT block
it ge
strdge r0, r0, [pc], #-0
@ CHECK: :[[@LINE+2]]:1: warning: deprecated instruction in IT block
it ge
-strdge r0, r0, [r0], #0
-@ CHECK: :[[@LINE+2]]:1: warning: deprecated instruction in IT block
-it ge
strdge r0, r0, [r1], #0
@ CHECK: :[[@LINE+2]]:1: warning: deprecated instruction in IT block
it ge
strdge r0, r0, [pc, #-0]
@ CHECK: :[[@LINE+2]]:1: warning: deprecated instruction in IT block
it ge
-strdge r0, r0, [r0, #-0]!
-@ CHECK: :[[@LINE+2]]:1: warning: deprecated instruction in IT block
-it ge
strdge r0, r0, [r1, #-0]!
@ CHECK: :[[@LINE+2]]:1: warning: deprecated instruction in IT block
it ge
strdge r0, r0, [pc, #-0]!
@ CHECK: :[[@LINE+2]]:1: warning: deprecated instruction in IT block
it ge
-strdge r0, r0, [r0]
-@ CHECK: :[[@LINE+2]]:1: warning: deprecated instruction in IT block
-it ge
strdge r0, r0, [r1]
@ CHECK: :[[@LINE+2]]:1: warning: deprecated instruction in IT block
it ge
strdge r0, r0, [pc]
@ CHECK: :[[@LINE+2]]:1: warning: deprecated instruction in IT block
it ge
-strdge r0, r0, [r0, #0]!
-@ CHECK: :[[@LINE+2]]:1: warning: deprecated instruction in IT block
-it ge
strdge r0, r0, [r1, #0]!
@ CHECK: :[[@LINE+2]]:1: warning: deprecated instruction in IT block
it ge