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,21 @@ 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); + int Value = CE->getValue(); + return ARM_AM::isNEONi16splat(Value); + } + + bool isNEONi16splatNot() const { + if (isNEONByteReplicate(2)) + return false; // Leave that for bytes replication and forbid by default. + if (!isImm()) + return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + // Must be a constant. + if (!CE) return false; + int Value = CE->getValue(); + Value = ~Value & 0xffff; + return ARM_AM::isNEONi16splat(Value); } bool isNEONi32splat() const { @@ -1634,11 +1646,20 @@ // 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); + return ARM_AM::isNEONi32splat(Value); + } + + bool isNEONi32splatNot() const { + if (isNEONByteReplicate(4)) + return false; // Leave that for bytes replication and forbid by default. + if (!isImm()) + return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + // Must be a constant. + if (!CE) return false; + int64_t Value = CE->getValue(); + Value = ~Value & 0xffffffff; + return ARM_AM::isNEONi32splat(Value); } bool isNEONByteReplicate(unsigned NumBytes) const { @@ -2402,10 +2423,17 @@ // 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::encodeNEONi16splatOperands(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 = ~Value & 0xffff; + Value = ARM_AM::encodeNEONi16splatOperands(Value); Inst.addOperand(MCOperand::CreateImm(Value)); } @@ -2414,12 +2442,17 @@ // 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::encodeNEONi32splatOperands(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 = ~Value & 0xffffffff; + Value = ARM_AM::encodeNEONi32splatOperands(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,41 @@ return Val; } + // Encode NEON 16 bits Splat immediate for instructions like VBIC/VMOV/VORR + static inline unsigned encodeNEONi16splatOperands(unsigned Value) { + if (Value >= 256) + Value = (Value >> 8) | 0xa00; + else + Value |= 0x800; + return Value; + } + + // Checks if Value is a correct immediate for instructions like VBIC/VMOV/VORR + static inline bool isNEONi16splat(int Value) { + // i16 value in the range [0,255] or [0x0100, 0xff00] + return (Value >= 0 && Value < 256) || (Value >= 0x0100 && Value <= 0xff00); + } + + // Encode NEON 32 bits Splat immediate for instructions like VBIC/VMOV/VORR + static inline unsigned encodeNEONi32splatOperands(unsigned Value) { + 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; + return Value; + } + + // Checks if Value is a correct immediate for instructions like VBIC/VMOV/VORR + static inline bool isNEONi32splat(int64_t Value) { + // 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); + } + 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 @@ -41,6 +41,15 @@ @ CHECK: vbic q10, q10, q11 @ encoding: [0xf6,0x41,0x54,0xf2] @ CHECK: vbic d9, d9, d1 @ encoding: [0x11,0x91,0x19,0xf2] + vand.i16 d10, #0x03ff + vand.i32 d10, #0x03ffffff + vand.i16 q10, #0x03ff + vand.i32 q10, #0x03ffffff + +@ CHECK: vbic.i16 d10, #0xfc00 @ encoding: [0x3c,0xab,0x87,0xf3] +@ CHECK: vbic.i32 d10, #0xfc000000 @ encoding: [0x3c,0xa7,0x87,0xf3] +@ CHECK: vbic.i16 q10, #0xfc00 @ encoding: [0x7c,0x4b,0xc7,0xf3] +@ CHECK: vbic.i32 q10, #0xfc000000 @ encoding: [0x7c,0x47,0xc7,0xf3] vorn d16, d17, d16 vorn q8, q8, q9