Add aliases for VAND imm to VBIC ~imm
authorRenato Golin <renato.golin@linaro.org>
Thu, 25 Sep 2014 11:31:24 +0000 (11:31 +0000)
committerRenato Golin <renato.golin@linaro.org>
Thu, 25 Sep 2014 11:31:24 +0000 (11:31 +0000)
On ARM NEON, VAND with immediate (16/32 bits) is an alias to VBIC ~imm with
the same type size. Adding that logic to the parser, and generating VBIC
instructions from VAND asm files.

This patch also fixes the validation routines for NEON splat immediates which
were wrong.

Fixes PR20702.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@218450 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/ARMInstrNEON.td
lib/Target/ARM/AsmParser/ARMAsmParser.cpp
lib/Target/ARM/MCTargetDesc/ARMAddressingModes.h
test/MC/ARM/neon-bitwise-encoding.s
test/MC/ARM/vorr-vbic-illegal-cases.s

index a276b92b2977f83cc5eb29bca2cf74c67ab1fa3d..9f11c5bfffbc5411f786dbda71ca7703c02788ca 100644 (file)
@@ -34,6 +34,14 @@ def nImmSplatI32 : Operand<i32> {
   let PrintMethod = "printNEONModImmOperand";
   let ParserMatchClass = nImmSplatI32AsmOperand;
 }
+def nImmSplatNotI16AsmOperand : AsmOperandClass { let Name = "NEONi16splatNot"; }
+def nImmSplatNotI16 : Operand<i32> {
+  let ParserMatchClass = nImmSplatNotI16AsmOperand;
+}
+def nImmSplatNotI32AsmOperand : AsmOperandClass { let Name = "NEONi32splatNot"; }
+def nImmSplatNotI32 : Operand<i32> {
+  let ParserMatchClass = nImmSplatNotI32AsmOperand;
+}
 def nImmVMOVI32AsmOperand : AsmOperandClass { let Name = "NEONi32vmov"; }
 def nImmVMOVI32 : Operand<i32> {
   let PrintMethod = "printNEONModImmOperand";
@@ -6638,6 +6646,16 @@ defm : NEONDTAnyInstAlias<"vorr${p}", "$Vdn, $Vm",
                          (VORRd DPR:$Vdn, DPR:$Vdn, DPR:$Vm, pred:$p)>;
 defm : NEONDTAnyInstAlias<"vorr${p}", "$Vdn, $Vm",
                          (VORRq QPR:$Vdn, QPR:$Vdn, QPR:$Vm, pred:$p)>;
+// ... immediates
+def : NEONInstAlias<"vand${p}.i16 $Vd, $imm",
+                    (VBICiv4i16 DPR:$Vd, nImmSplatNotI16:$imm, pred:$p)>;
+def : NEONInstAlias<"vand${p}.i32 $Vd, $imm",
+                    (VBICiv2i32 DPR:$Vd, nImmSplatNotI32:$imm, pred:$p)>;
+def : NEONInstAlias<"vand${p}.i16 $Vd, $imm",
+                    (VBICiv8i16 QPR:$Vd, nImmSplatNotI16:$imm, pred:$p)>;
+def : NEONInstAlias<"vand${p}.i32 $Vd, $imm",
+                    (VBICiv4i32 QPR:$Vd, nImmSplatNotI32:$imm, pred:$p)>;
+
 
 // VLD1 single-lane pseudo-instructions. These need special handling for
 // the lane index that an InstAlias can't handle, so we use these instead.
index 211157c7203c61068ebd697aa0f6e21dbe08ce1a..833b01352b286c65bca8776897a1aa345f5851b4 100644 (file)
@@ -1622,9 +1622,18 @@ public:
     const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
     // Must be a constant.
     if (!CE) return false;
-    int64_t Value = CE->getValue();
-    // i16 value in the range [0,255] or [0x0100, 0xff00]
-    return (Value >= 0 && Value < 256) || (Value >= 0x0100 && Value <= 0xff00);
+    unsigned Value = CE->getValue();
+    return ARM_AM::isNEONi16splat(Value);
+  }
+
+  bool isNEONi16splatNot() const {
+    if (!isImm())
+      return false;
+    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+    // Must be a constant.
+    if (!CE) return false;
+    unsigned Value = CE->getValue();
+    return ARM_AM::isNEONi16splat(~Value & 0xffff);
   }
 
   bool isNEONi32splat() const {
@@ -1635,12 +1644,18 @@ public:
     const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
     // Must be a constant.
     if (!CE) return false;
-    int64_t Value = CE->getValue();
-    // i32 value with set bits only in one byte X000, 0X00, 00X0, or 000X.
-    return (Value >= 0 && Value < 256) ||
-      (Value >= 0x0100 && Value <= 0xff00) ||
-      (Value >= 0x010000 && Value <= 0xff0000) ||
-      (Value >= 0x01000000 && Value <= 0xff000000);
+    unsigned Value = CE->getValue();
+    return ARM_AM::isNEONi32splat(Value);
+  }
+
+  bool isNEONi32splatNot() const {
+    if (!isImm())
+      return false;
+    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+    // Must be a constant.
+    if (!CE) return false;
+    unsigned Value = CE->getValue();
+    return ARM_AM::isNEONi32splat(~Value);
   }
 
   bool isNEONByteReplicate(unsigned NumBytes) const {
@@ -1676,6 +1691,7 @@ public:
     int64_t Value = CE->getValue();
     // i32 value with set bits only in one byte X000, 0X00, 00X0, or 000X,
     // for VMOV/VMVN only, 00Xf or 0Xff are also accepted.
+    // FIXME: This is probably wrong and a copy and paste from previous example
     return (Value >= 0 && Value < 256) ||
       (Value >= 0x0100 && Value <= 0xff00) ||
       (Value >= 0x010000 && Value <= 0xff0000) ||
@@ -1691,6 +1707,7 @@ public:
     int64_t Value = ~CE->getValue();
     // i32 value with set bits only in one byte X000, 0X00, 00X0, or 000X,
     // for VMOV/VMVN only, 00Xf or 0Xff are also accepted.
+    // FIXME: This is probably wrong and a copy and paste from previous example
     return (Value >= 0 && Value < 256) ||
       (Value >= 0x0100 && Value <= 0xff00) ||
       (Value >= 0x010000 && Value <= 0xff0000) ||
@@ -2404,10 +2421,16 @@ public:
     // The immediate encodes the type of constant as well as the value.
     const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
     unsigned Value = CE->getValue();
-    if (Value >= 256)
-      Value = (Value >> 8) | 0xa00;
-    else
-      Value |= 0x800;
+    Value = ARM_AM::encodeNEONi16splat(Value);
+    Inst.addOperand(MCOperand::CreateImm(Value));
+  }
+
+  void addNEONi16splatNotOperands(MCInst &Inst, unsigned N) const {
+    assert(N == 1 && "Invalid number of operands!");
+    // The immediate encodes the type of constant as well as the value.
+    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+    unsigned Value = CE->getValue();
+    Value = ARM_AM::encodeNEONi16splat(~Value & 0xffff);
     Inst.addOperand(MCOperand::CreateImm(Value));
   }
 
@@ -2416,12 +2439,16 @@ public:
     // The immediate encodes the type of constant as well as the value.
     const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
     unsigned Value = CE->getValue();
-    if (Value >= 256 && Value <= 0xff00)
-      Value = (Value >> 8) | 0x200;
-    else if (Value > 0xffff && Value <= 0xff0000)
-      Value = (Value >> 16) | 0x400;
-    else if (Value > 0xffffff)
-      Value = (Value >> 24) | 0x600;
+    Value = ARM_AM::encodeNEONi32splat(Value);
+    Inst.addOperand(MCOperand::CreateImm(Value));
+  }
+
+  void addNEONi32splatNotOperands(MCInst &Inst, unsigned N) const {
+    assert(N == 1 && "Invalid number of operands!");
+    // The immediate encodes the type of constant as well as the value.
+    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+    unsigned Value = CE->getValue();
+    Value = ARM_AM::encodeNEONi32splat(~Value);
     Inst.addOperand(MCOperand::CreateImm(Value));
   }
 
index 95deed6fca6a08949c1fcd37e676a5736313cad8..f0eed9b811d465efb13ee8a8cbc145d772c59541 100644 (file)
@@ -575,6 +575,53 @@ namespace ARM_AM {
     return Val;
   }
 
+  // Generic validation for single-byte immediate (0X00, 00X0, etc).
+  static inline bool isNEONBytesplat(unsigned Value, unsigned Size) {
+    assert(Size >= 1 && Size <= 4 && "Invalid size");
+    unsigned count = 0;
+    for (unsigned i = 0; i < Size; ++i) {
+      if (Value & 0xff) count++;
+      Value >>= 8;
+    }
+    return count == 1;
+  }
+
+  /// Checks if Value is a correct immediate for instructions like VBIC/VORR.
+  static inline bool isNEONi16splat(unsigned Value) {
+    if (Value > 0xffff)
+      return false;
+    // i16 value with set bits only in one byte X0 or 0X.
+    return Value == 0 || isNEONBytesplat(Value, 2);
+  }
+
+  // Encode NEON 16 bits Splat immediate for instructions like VBIC/VORR
+  static inline unsigned encodeNEONi16splat(unsigned Value) {
+    assert(isNEONi16splat(Value) && "Invalid NEON splat value");
+    if (Value >= 0x100)
+      Value = (Value >> 8) | 0xa00;
+    else
+      Value |= 0x800;
+    return Value;
+  }
+
+  /// Checks if Value is a correct immediate for instructions like VBIC/VORR.
+  static inline bool isNEONi32splat(unsigned Value) {
+    // i32 value with set bits only in one byte X000, 0X00, 00X0, or 000X.
+    return Value == 0 || isNEONBytesplat(Value, 4);
+  }
+
+  /// Encode NEON 32 bits Splat immediate for instructions like VBIC/VORR.
+  static inline unsigned encodeNEONi32splat(unsigned Value) {
+    assert(isNEONi32splat(Value) && "Invalid NEON splat value");
+    if (Value >= 0x100 && Value <= 0xff00)
+      Value = (Value >> 8) | 0x200;
+    else if (Value > 0xffff && Value <= 0xff0000)
+      Value = (Value >> 16) | 0x400;
+    else if (Value > 0xffffff)
+      Value = (Value >> 24) | 0x600;
+    return Value;
+  }
+
   AMSubMode getLoadStoreMultipleSubMode(int Opcode);
 
   //===--------------------------------------------------------------------===//
index 8c7228835c9b1d1679023b53f294960bbfa0ec9a..d142dbabec9e9521b3f3a5647fa9056d79fdda29 100644 (file)
 
        vbic    d16, d17, d16
        vbic    q8, q8, q9
+       vbic q10, q11
+       vbic d9, d1
+       vbic.i16        d16, #0xFF00
+       vbic.i16        q8,  #0xFF00
+       vbic.i16        d16, #0x00FF
+       vbic.i16        q8,  #0x00FF
        vbic.i32        d16, #0xFF000000
-       vbic.i32        q8, #0xFF000000
-        vbic q10, q11
-        vbic d9, d1
+       vbic.i32        q8,  #0xFF000000
+       vbic.i32        d16, #0x00FF0000
+       vbic.i32        q8,  #0x00FF0000
+       vbic.i32        d16, #0x0000FF00
+       vbic.i32        q8,  #0x0000FF00
+       vbic.i32        d16, #0x000000FF
+       vbic.i32        q8,  #0x000000FF
 
 @ CHECK: vbic  d16, d17, d16           @ encoding: [0xb0,0x01,0x51,0xf2]
 @ CHECK: vbic  q8, q8, q9              @ encoding: [0xf2,0x01,0x50,0xf2]
-@ CHECK: vbic.i32      d16, #0xff000000 @ encoding: [0x3f,0x07,0xc7,0xf3]
-@ CHECK: vbic.i32      q8, #0xff000000 @ encoding: [0x7f,0x07,0xc7,0xf3]
 @ CHECK: vbic  q10, q10, q11           @ encoding: [0xf6,0x41,0x54,0xf2]
 @ CHECK: vbic  d9, d9, d1              @ encoding: [0x11,0x91,0x19,0xf2]
-
+@ CHECK: vbic.i16      d16, #0xff00    @ encoding: [0x3f,0x0b,0xc7,0xf3]
+@ CHECK: vbic.i16      q8, #0xff00     @ encoding: [0x7f,0x0b,0xc7,0xf3]
+@ CHECK: vbic.i16      d16, #0xff      @ encoding: [0x3f,0x09,0xc7,0xf3]
+@ CHECK: vbic.i16      q8, #0xff       @ encoding: [0x7f,0x09,0xc7,0xf3]
+@ CHECK: vbic.i32      d16, #0xff000000 @ encoding: [0x3f,0x07,0xc7,0xf3]
+@ CHECK: vbic.i32      q8, #0xff000000 @ encoding: [0x7f,0x07,0xc7,0xf3]
+@ CHECK: vbic.i32      d16, #0xff0000  @ encoding: [0x3f,0x05,0xc7,0xf3]
+@ CHECK: vbic.i32      q8, #0xff0000   @ encoding: [0x7f,0x05,0xc7,0xf3]
+@ CHECK: vbic.i32      d16, #0xff00    @ encoding: [0x3f,0x03,0xc7,0xf3]
+@ CHECK: vbic.i32      q8, #0xff00     @ encoding: [0x7f,0x03,0xc7,0xf3]
+@ CHECK: vbic.i32      d16, #0xff      @ encoding: [0x3f,0x01,0xc7,0xf3]
+@ CHECK: vbic.i32      q8, #0xff       @ encoding: [0x7f,0x01,0xc7,0xf3]
+
+       vand.i16 d10, #0xff03
+       vand.i16 q10, #0xff03
+       vand.i16 d10, #0x03ff
+       vand.i16 q10, #0x03ff
+       vand.i32 d10, #0x03ffffff
+       vand.i32 q10, #0x03ffffff
+       vand.i32 d10, #0xff03ffff
+       vand.i32 q10, #0xff03ffff
+       vand.i32 d10, #0xffff03ff
+       vand.i32 q10, #0xffff03ff
+       vand.i32 d10, #0xffffff03
+       vand.i32 q10, #0xffffff03
+
+@ CHECK: vbic.i16      d10, #0xfc      @ encoding: [0x3c,0xa9,0x87,0xf3]
+@ CHECK: vbic.i16      q10, #0xfc      @ encoding: [0x7c,0x49,0xc7,0xf3]
+@ CHECK: vbic.i16      d10, #0xfc00    @ encoding: [0x3c,0xab,0x87,0xf3]
+@ CHECK: vbic.i16      q10, #0xfc00    @ encoding: [0x7c,0x4b,0xc7,0xf3]
+@ CHECK: vbic.i32      d10, #0xfc000000 @ encoding: [0x3c,0xa7,0x87,0xf3]
+@ CHECK: vbic.i32      q10, #0xfc000000 @ encoding: [0x7c,0x47,0xc7,0xf3]
+@ CHECK: vbic.i32      d10, #0xfc0000  @ encoding: [0x3c,0xa5,0x87,0xf3]
+@ CHECK: vbic.i32      q10, #0xfc0000  @ encoding: [0x7c,0x45,0xc7,0xf3]
+@ CHECK: vbic.i32      d10, #0xfc00    @ encoding: [0x3c,0xa3,0x87,0xf3]
+@ CHECK: vbic.i32      q10, #0xfc00    @ encoding: [0x7c,0x43,0xc7,0xf3]
+@ CHECK: vbic.i32      d10, #0xfc      @ encoding: [0x3c,0xa1,0x87,0xf3]
+@ CHECK: vbic.i32      q10, #0xfc      @ encoding: [0x7c,0x41,0xc7,0xf3]
 
        vorn    d16, d17, d16
        vorn    q8, q8, q9
index 16ab6b5bc74ba1cbde06d777d81a11fbea5d04a4..673098ad5a07a905be33bea928736658ea03eb54 100644 (file)
@@ -1,6 +1,13 @@
 @ RUN: not llvm-mc -triple=armv7-linux-gnueabi %s 2>&1 | FileCheck %s
 .text
 
+        vorr.i32        d2, #0xffffffff
+        vorr.i32        q2, #0xffffffff
+        vorr.i32        d2, #0xabababab
+        vorr.i32        q2, #0xabababab
+        vorr.i16        q2, #0xabab
+        vorr.i16        q2, #0xabab
+
 @ CHECK: error: invalid operand for instruction
 @ CHECK: vorr.i32        d2, #0xffffffff
 @ CHECK: error: invalid operand for instruction
 @ CHECK: error: invalid operand for instruction
 @ CHECK: vorr.i16        q2, #0xabab
 
+        vbic.i32        d2, #0xffffffff
+        vbic.i32        q2, #0xffffffff
+        vbic.i32        d2, #0xabababab
+        vbic.i32        q2, #0xabababab
+        vbic.i16        d2, #0xabab
+        vbic.i16        q2, #0xabab
+
 @ CHECK: error: invalid operand for instruction
 @ CHECK: vbic.i32        d2, #0xffffffff
 @ CHECK: error: invalid operand for instruction
 @ CHECK: error: invalid operand for instruction
 @ CHECK: vbic.i16        q2, #0xabab
 
-        vorr.i32        d2, #0xffffffff
-        vorr.i32        q2, #0xffffffff
-        vorr.i32        d2, #0xabababab
-        vorr.i32        q2, #0xabababab
-        vorr.i16        q2, #0xabab
-        vorr.i16        q2, #0xabab
+        vbic.i32        d2, #0x03ffffff
+        vbic.i32        q2, #0x03ffff
+        vbic.i32        d2, #0x03ff
+        vbic.i32        d2, #0xff00ff
+        vbic.i16        d2, #0x03ff
+        vbic.i16        q2, #0xf0f0
+        vbic.i16        q2, #0xf0f0f0
 
-        vbic.i32        d2, #0xffffffff
-        vbic.i32        q2, #0xffffffff
-        vbic.i32        d2, #0xabababab
-        vbic.i32        q2, #0xabababab
-        vbic.i16        d2, #0xabab
-        vbic.i16        q2, #0xabab
+@ CHECK: error: invalid operand for instruction
+@ CHECK: vbic.i32        d2, #0x03ffffff
+@ CHECK: error: invalid operand for instruction
+@ CHECK: vbic.i32        q2, #0x03ffff
+@ CHECK: error: invalid operand for instruction
+@ CHECK: vbic.i32        d2, #0x03ff
+@ CHECK: error: invalid operand for instruction
+@ CHECK: vbic.i32        d2, #0xff00ff
+@ CHECK: error: invalid operand for instruction
+@ CHECK: vbic.i16        d2, #0x03ff
+@ CHECK: error: invalid operand for instruction
+@ CHECK: vbic.i16        q2, #0xf0f0
+@ CHECK: error: invalid operand for instruction
+@ CHECK: vbic.i16        q2, #0xf0f0f0