Index: lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -561,6 +561,8 @@ 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 { @@ -6302,6 +6304,65 @@ 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) { @@ -6349,50 +6410,27 @@ const unsigned Opcode = Inst.getOpcode(); switch (Opcode) { 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 @@ -6401,35 +6439,39 @@ "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()); @@ -6441,18 +6483,28 @@ } 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()); @@ -6463,7 +6515,9 @@ 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(); Index: test/MC/ARM/arm-memory-instructions.s =================================================================== --- test/MC/ARM/arm-memory-instructions.s +++ test/MC/ARM/arm-memory-instructions.s @@ -404,21 +404,21 @@ @------------------------------------------------------------------------------ @ 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] @------------------------------------------------------------------------------ @@ -429,14 +429,14 @@ @ 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] @------------------------------------------------------------------------------ Index: test/MC/ARM/diagnostics.s =================================================================== --- test/MC/ARM/diagnostics.s +++ test/MC/ARM/diagnostics.s @@ -399,10 +399,13 @@ @ 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: ^ @@ -412,6 +415,53 @@ @ 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. Index: test/MC/ARM/thumb-diagnostics.s =================================================================== --- test/MC/ARM/thumb-diagnostics.s +++ test/MC/ARM/thumb-diagnostics.s @@ -360,3 +360,54 @@ 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: ^ Index: test/MC/ARM/v8_IT_manual.s =================================================================== --- test/MC/ARM/v8_IT_manual.s +++ test/MC/ARM/v8_IT_manual.s @@ -695,9 +695,6 @@ 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 @@ -743,9 +740,6 @@ 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 @@ -839,9 +833,6 @@ 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 @@ -887,9 +878,6 @@ 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 @@ -935,9 +923,6 @@ 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