[ARM] Add missing Thumb2 assembler diagnostics.
authorEli Friedman <efriedma@codeaurora.org>
Thu, 28 Jun 2018 19:53:12 +0000 (19:53 +0000)
committerEli Friedman <efriedma@codeaurora.org>
Thu, 28 Jun 2018 19:53:12 +0000 (19:53 +0000)
Mostly just adding checks for Thumb2 instructions which correspond to
ARM instructions which already had diagnostics. While I'm here, also fix
ARM-mode strd to check the input registers correctly.

Differential Revision: https://reviews.llvm.org/D48610

llvm-svn: 335909

llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
llvm/test/MC/ARM/arm-memory-instructions.s
llvm/test/MC/ARM/diagnostics.s
llvm/test/MC/ARM/thumb-diagnostics.s
llvm/test/MC/ARM/v8_IT_manual.s

index 8a72587..df2e7ff 100644 (file)
@@ -561,6 +561,8 @@ class ARMAsmParser : public MCTargetAsmParser {
   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 @@ bool ARMAsmParser::validatetSTMRegList(const MCInst &Inst,
   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) {
@@ -6364,50 +6425,27 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
     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
@@ -6416,35 +6454,39 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
                    "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());
@@ -6456,18 +6498,28 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
   }
   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());
@@ -6478,7 +6530,9 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
     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 f41c779..416069a 100644 (file)
@@ -404,21 +404,21 @@ Lbaz: .quad 0
 @------------------------------------------------------------------------------
 @ 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 @@ Lbaz: .quad 0
 @ 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 899c811..d9ca8a5 100644 (file)
 @ 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.
index 51658ce..304e996 100644 (file)
         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 797c2b9..f4c5bcb 100644 (file)
@@ -695,9 +695,6 @@ it ge
 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 @@ 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
@@ -839,9 +833,6 @@ 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
@@ -887,9 +878,6 @@ 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
@@ -935,9 +923,6 @@ 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