Add aliases for VAND imm to VBIC ~imm

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.

llvm-svn: 218450
This commit is contained in:
Renato Golin 2014-09-25 11:31:24 +00:00
parent 65ea352f53
commit 075db70d6a
5 changed files with 196 additions and 36 deletions

View 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.

View 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));
}

View 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);
//===--------------------------------------------------------------------===//

View File

@ -29,18 +29,63 @@
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

View 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
@ -14,6 +21,13 @@
@ 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
@ -27,16 +41,25 @@
@ 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