Index: lib/Target/ARM/ARMInstrNEON.td =================================================================== --- lib/Target/ARM/ARMInstrNEON.td +++ lib/Target/ARM/ARMInstrNEON.td @@ -34,6 +34,14 @@ let PrintMethod = "printNEONModImmOperand"; let ParserMatchClass = nImmSplatI32AsmOperand; } +def nImmSplatNotI16AsmOperand : AsmOperandClass { let Name = "NEONi16splatNot"; } +def nImmSplatNotI16 : Operand { + let ParserMatchClass = nImmSplatNotI16AsmOperand; +} +def nImmSplatNotI32AsmOperand : AsmOperandClass { let Name = "NEONi32splatNot"; } +def nImmSplatNotI32 : Operand { + let ParserMatchClass = nImmSplatNotI32AsmOperand; +} def nImmVMOVI32AsmOperand : AsmOperandClass { let Name = "NEONi32vmov"; } def nImmVMOVI32 : Operand { let PrintMethod = "printNEONModImmOperand"; @@ -6638,6 +6646,16 @@ (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: lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -1620,9 +1620,18 @@ const MCConstantExpr *CE = dyn_cast(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(getImm()); + // Must be a constant. + if (!CE) return false; + unsigned Value = CE->getValue(); + return ARM_AM::isNEONi16splat(~Value & 0xffff); } bool isNEONi32splat() const { @@ -1633,12 +1642,18 @@ const MCConstantExpr *CE = dyn_cast(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(getImm()); + // Must be a constant. + if (!CE) return false; + unsigned Value = CE->getValue(); + return ARM_AM::isNEONi32splat(~Value); } bool isNEONByteReplicate(unsigned NumBytes) const { @@ -1674,6 +1689,7 @@ 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) || @@ -1689,6 +1705,7 @@ 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) || @@ -2402,10 +2419,16 @@ // The immediate encodes the type of constant as well as the value. const MCConstantExpr *CE = dyn_cast(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(getImm()); + unsigned Value = CE->getValue(); + Value = ARM_AM::encodeNEONi16splat(~Value & 0xffff); Inst.addOperand(MCOperand::CreateImm(Value)); } @@ -2414,12 +2437,16 @@ // The immediate encodes the type of constant as well as the value. const MCConstantExpr *CE = dyn_cast(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(getImm()); + unsigned Value = CE->getValue(); + Value = ARM_AM::encodeNEONi32splat(~Value); Inst.addOperand(MCOperand::CreateImm(Value)); } Index: lib/Target/ARM/MCTargetDesc/ARMAddressingModes.h =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMAddressingModes.h +++ lib/Target/ARM/MCTargetDesc/ARMAddressingModes.h @@ -575,6 +575,53 @@ 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: test/MC/ARM/neon-bitwise-encoding.s =================================================================== --- test/MC/ARM/neon-bitwise-encoding.s +++ test/MC/ARM/neon-bitwise-encoding.s @@ -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 Index: test/MC/ARM/vorr-vbic-illegal-cases.s =================================================================== --- test/MC/ARM/vorr-vbic-illegal-cases.s +++ test/MC/ARM/vorr-vbic-illegal-cases.s @@ -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