From ed1c8bfec21e74052173dabd719717bb5c0191ba Mon Sep 17 00:00:00 2001 From: Mikhail Maltsev Date: Fri, 16 Mar 2018 14:10:56 +0000 Subject: [PATCH] [ARM] Convert more invalid NEON immediate loads Summary: Currently the LLVM MC assembler is able to convert e.g. vmov.i32 d0, #0xabababab (which is technically invalid) into a valid instruction vmov.i8 d0, #0xab this patch adds support for vmov.i64 and for cases with the resulting load types other than i8, e.g.: vmov.i32 d0, #0xab00ab00 -> vmov.i16 d0, #0xab00 Reviewers: olista01, rengolin Reviewed By: rengolin Subscribers: rengolin, javed.absar, kristof.beyls, rogfer01, llvm-commits Differential Revision: https://reviews.llvm.org/D44467 llvm-svn: 327709 --- llvm/lib/Target/ARM/ARMInstrNEON.td | 127 +++++++------- .../lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 165 ++++++++++++------ llvm/test/MC/ARM/vmov-vmvn-byte-replicate.s | 31 ---- llvm/test/MC/ARM/vmov-vmvn-replicate.s | 102 +++++++++++ 4 files changed, 280 insertions(+), 145 deletions(-) delete mode 100644 llvm/test/MC/ARM/vmov-vmvn-byte-replicate.s create mode 100644 llvm/test/MC/ARM/vmov-vmvn-replicate.s diff --git a/llvm/lib/Target/ARM/ARMInstrNEON.td b/llvm/lib/Target/ARM/ARMInstrNEON.td index cd67dded5853..ca56835f9848 100644 --- a/llvm/lib/Target/ARM/ARMInstrNEON.td +++ b/llvm/lib/Target/ARM/ARMInstrNEON.td @@ -48,46 +48,28 @@ def nImmVMOVI32 : Operand { let ParserMatchClass = nImmVMOVI32AsmOperand; } -def nImmVMOVI16AsmOperandByteReplicate : - AsmOperandClass { - let Name = "NEONi16vmovByteReplicate"; - let PredicateMethod = "isNEONi16ByteReplicate"; - let RenderMethod = "addNEONvmovByteReplicateOperands"; -} -def nImmVMOVI32AsmOperandByteReplicate : - AsmOperandClass { - let Name = "NEONi32vmovByteReplicate"; - let PredicateMethod = "isNEONi32ByteReplicate"; - let RenderMethod = "addNEONvmovByteReplicateOperands"; -} -def nImmVMVNI16AsmOperandByteReplicate : - AsmOperandClass { - let Name = "NEONi16invByteReplicate"; - let PredicateMethod = "isNEONi16ByteReplicate"; - let RenderMethod = "addNEONinvByteReplicateOperands"; -} -def nImmVMVNI32AsmOperandByteReplicate : - AsmOperandClass { - let Name = "NEONi32invByteReplicate"; - let PredicateMethod = "isNEONi32ByteReplicate"; - let RenderMethod = "addNEONinvByteReplicateOperands"; +class nImmVMOVIAsmOperandReplicate + : AsmOperandClass { + let Name = "NEONi" # To.Size # "vmovi" # From.Size # "Replicate"; + let PredicateMethod = "isNEONmovReplicate<" # From.Size # ", " # To.Size # ">"; + let RenderMethod = "addNEONvmovi" # From.Size # "ReplicateOperands"; } -def nImmVMOVI16ByteReplicate : Operand { - let PrintMethod = "printNEONModImmOperand"; - let ParserMatchClass = nImmVMOVI16AsmOperandByteReplicate; +class nImmVINVIAsmOperandReplicate + : AsmOperandClass { + let Name = "NEONi" # To.Size # "invi" # From.Size # "Replicate"; + let PredicateMethod = "isNEONinvReplicate<" # From.Size # ", " # To.Size # ">"; + let RenderMethod = "addNEONinvi" # From.Size # "ReplicateOperands"; } -def nImmVMOVI32ByteReplicate : Operand { + +class nImmVMOVIReplicate : Operand { let PrintMethod = "printNEONModImmOperand"; - let ParserMatchClass = nImmVMOVI32AsmOperandByteReplicate; + let ParserMatchClass = nImmVMOVIAsmOperandReplicate; } -def nImmVMVNI16ByteReplicate : Operand { + +class nImmVINVIReplicate : Operand { let PrintMethod = "printNEONModImmOperand"; - let ParserMatchClass = nImmVMVNI16AsmOperandByteReplicate; -} -def nImmVMVNI32ByteReplicate : Operand { - let PrintMethod = "printNEONModImmOperand"; - let ParserMatchClass = nImmVMVNI32AsmOperandByteReplicate; + let ParserMatchClass = nImmVINVIAsmOperandReplicate; } def nImmVMOVI32NegAsmOperand : AsmOperandClass { let Name = "NEONi32vmovNeg"; } @@ -5933,34 +5915,57 @@ def VMOVv4f32 : N1ModImm<1, 0b000, 0b1111, 0, 1, 0, 1, (outs QPR:$Vd), } // isReMaterializable, isAsCheapAsAMove // Add support for bytes replication feature, so it could be GAS compatible. -// E.g. instructions below: -// "vmov.i32 d0, 0xffffffff" -// "vmov.i32 d0, 0xabababab" -// "vmov.i16 d0, 0xabab" -// are incorrect, but we could deal with such cases. -// For last two instructions, for example, it should emit: -// "vmov.i8 d0, 0xab" -def : NEONInstAlias<"vmov${p}.i16 $Vd, $Vm", - (VMOVv8i8 DPR:$Vd, nImmVMOVI16ByteReplicate:$Vm, pred:$p)>; -def : NEONInstAlias<"vmov${p}.i32 $Vd, $Vm", - (VMOVv8i8 DPR:$Vd, nImmVMOVI32ByteReplicate:$Vm, pred:$p)>; -def : NEONInstAlias<"vmov${p}.i16 $Vd, $Vm", - (VMOVv16i8 QPR:$Vd, nImmVMOVI16ByteReplicate:$Vm, pred:$p)>; -def : NEONInstAlias<"vmov${p}.i32 $Vd, $Vm", - (VMOVv16i8 QPR:$Vd, nImmVMOVI32ByteReplicate:$Vm, pred:$p)>; +multiclass NEONImmReplicateI8InstAlias { + // E.g. instructions below: + // "vmov.i32 d0, #0xffffffff" + // "vmov.i32 d0, #0xabababab" + // "vmov.i16 d0, #0xabab" + // are incorrect, but we could deal with such cases. + // For last two instructions, for example, it should emit: + // "vmov.i8 d0, #0xab" + def : NEONInstAlias<"vmov${p}.i" # To.Size # " $Vd, $Vm", + (VMOVv8i8 DPR:$Vd, nImmVMOVIReplicate:$Vm, pred:$p)>; + def : NEONInstAlias<"vmov${p}.i" # To.Size # " $Vd, $Vm", + (VMOVv16i8 QPR:$Vd, nImmVMOVIReplicate:$Vm, pred:$p)>; + // Also add same support for VMVN instructions. So instruction: + // "vmvn.i32 d0, #0xabababab" + // actually means: + // "vmov.i8 d0, #0x54" + def : NEONInstAlias<"vmvn${p}.i" # To.Size # " $Vd, $Vm", + (VMOVv8i8 DPR:$Vd, nImmVINVIReplicate:$Vm, pred:$p)>; + def : NEONInstAlias<"vmvn${p}.i" # To.Size # " $Vd, $Vm", + (VMOVv16i8 QPR:$Vd, nImmVINVIReplicate:$Vm, pred:$p)>; +} -// Also add same support for VMVN instructions. So instruction: -// "vmvn.i32 d0, 0xabababab" -// actually means: -// "vmov.i8 d0, 0x54" -def : NEONInstAlias<"vmvn${p}.i16 $Vd, $Vm", - (VMOVv8i8 DPR:$Vd, nImmVMVNI16ByteReplicate:$Vm, pred:$p)>; -def : NEONInstAlias<"vmvn${p}.i32 $Vd, $Vm", - (VMOVv8i8 DPR:$Vd, nImmVMVNI32ByteReplicate:$Vm, pred:$p)>; -def : NEONInstAlias<"vmvn${p}.i16 $Vd, $Vm", - (VMOVv16i8 QPR:$Vd, nImmVMVNI16ByteReplicate:$Vm, pred:$p)>; -def : NEONInstAlias<"vmvn${p}.i32 $Vd, $Vm", - (VMOVv16i8 QPR:$Vd, nImmVMVNI32ByteReplicate:$Vm, pred:$p)>; +defm : NEONImmReplicateI8InstAlias; +defm : NEONImmReplicateI8InstAlias; +defm : NEONImmReplicateI8InstAlias; + +// Similar to above for types other than i8, e.g.: +// "vmov.i32 d0, #0xab00ab00" -> "vmov.i16 d0, #0xab00" +// "vmvn.i64 q0, #0xab000000ab000000" -> "vmvn.i32 q0, #0xab000000" +// In this case we do not canonicalize VMVN to VMOV +multiclass NEONImmReplicateInstAlias { + def : NEONInstAlias<"vmov${p}.i" # To.Size # " $Vd, $Vm", + (V8 DPR:$Vd, nImmVMOVIReplicate:$Vm, pred:$p)>; + def : NEONInstAlias<"vmov${p}.i" # To.Size # " $Vd, $Vm", + (V16 QPR:$Vd, nImmVMOVIReplicate:$Vm, pred:$p)>; + def : NEONInstAlias<"vmvn${p}.i" # To.Size # " $Vd, $Vm", + (NV8 DPR:$Vd, nImmVMOVIReplicate:$Vm, pred:$p)>; + def : NEONInstAlias<"vmvn${p}.i" # To.Size # " $Vd, $Vm", + (NV16 QPR:$Vd, nImmVMOVIReplicate:$Vm, pred:$p)>; +} + +defm : NEONImmReplicateInstAlias; +defm : NEONImmReplicateInstAlias; +defm : NEONImmReplicateInstAlias; +// TODO: add "VMOV <-> VMVN" conversion for cases like +// "vmov.i32 d0, #0xffaaffaa" -> "vmvn.i16 d0, #0x55" +// "vmvn.i32 d0, #0xaaffaaff" -> "vmov.i16 d0, #0xff00" // On some CPUs the two instructions "vmov.i32 dD, #0" and "vmov.i32 qD, #0" // require zero cycles to execute so they should be used wherever possible for diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 78973d16e2d4..d2b9b28519cc 100644 --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -1857,29 +1857,6 @@ public: return ARM_AM::isNEONi32splat(~Value); } - bool isNEONByteReplicate(unsigned NumBytes) const { - if (!isImm()) - return false; - const MCConstantExpr *CE = dyn_cast(getImm()); - // Must be a constant. - if (!CE) - return false; - int64_t Value = CE->getValue(); - if (!Value) - return false; // Don't bother with zero. - - unsigned char B = Value & 0xff; - for (unsigned i = 1; i < NumBytes; ++i) { - Value >>= 8; - if ((Value & 0xff) != B) - return false; - } - return true; - } - - bool isNEONi16ByteReplicate() const { return isNEONByteReplicate(2); } - bool isNEONi32ByteReplicate() const { return isNEONByteReplicate(4); } - static bool isValidNEONi32vmovImm(int64_t Value) { // i32 value with set bits only in one byte X000, 0X00, 00X0, or 000X, // for VMOV/VMVN only, 00Xf or 0Xff are also accepted. @@ -1891,6 +1868,63 @@ public: ((Value & 0xffffffffff00ffff) == 0xffff); } + bool isNEONReplicate(unsigned Width, unsigned NumElems, bool Inv, + bool AllowMinusOne) const { + assert(Width == 8 || Width == 16 || Width == 32 && "Invalid element width"); + assert(NumElems * Width <= 64 && "Invalid result width"); + + if (!isImm()) + return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + // Must be a constant. + if (!CE) + return false; + int64_t Value = CE->getValue(); + if (!Value) + return false; // Don't bother with zero. + if (Inv) + Value = ~Value; + + uint64_t Mask = (1ull << Width) - 1; + uint64_t Elem = Value & Mask; + if (!AllowMinusOne && Elem == Mask) + return false; + if (Width == 16 && (Elem & 0x00ff) != 0 && (Elem & 0xff00) != 0) + return false; + if (Width == 32 && !isValidNEONi32vmovImm(Elem)) + return false; + + for (unsigned i = 1; i < NumElems; ++i) { + Value >>= Width; + if ((Value & Mask) != Elem) + return false; + } + return true; + } + + bool isNEONByteReplicate(unsigned NumBytes) const { + return isNEONReplicate(8, NumBytes, false, true); + } + + static void checkNeonReplicateArgs(unsigned FromW, unsigned ToW) { + assert(FromW == 8 || FromW == 16 || FromW == 32 && "Invalid source width"); + assert(ToW == 16 || ToW == 32 || ToW == 64 && "Invalid destination width"); + assert(FromW < ToW && "ToW is not less than FromW"); + } + + template + bool isNEONmovReplicate() const { + checkNeonReplicateArgs(FromW, ToW); + bool AllowMinusOne = ToW != 64; + return isNEONReplicate(FromW, ToW / FromW, false, AllowMinusOne); + } + + template + bool isNEONinvReplicate() const { + checkNeonReplicateArgs(FromW, ToW); + return isNEONReplicate(FromW, ToW / FromW, true, true); + } + bool isNEONi32vmov() const { if (isNEONByteReplicate(4)) return false; // Let it to be classified as byte-replicate case. @@ -2726,62 +2760,87 @@ public: Inst.addOperand(MCOperand::createImm(Value)); } - void addNEONinvByteReplicateOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); + void addNEONi8ReplicateOperands(MCInst &Inst, bool Inv) const { // The immediate encodes the type of constant as well as the value. const MCConstantExpr *CE = dyn_cast(getImm()); - unsigned Value = CE->getValue(); assert((Inst.getOpcode() == ARM::VMOVv8i8 || Inst.getOpcode() == ARM::VMOVv16i8) && - "All vmvn instructions that wants to replicate non-zero byte " - "always must be replaced with VMOVv8i8 or VMOVv16i8."); - unsigned B = ((~Value) & 0xff); + "All instructions that wants to replicate non-zero byte " + "always must be replaced with VMOVv8i8 or VMOVv16i8."); + unsigned Value = CE->getValue(); + if (Inv) + Value = ~Value; + unsigned B = Value & 0xff; B |= 0xe00; // cmode = 0b1110 Inst.addOperand(MCOperand::createImm(B)); } + void addNEONinvi8ReplicateOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addNEONi8ReplicateOperands(Inst, true); + } + + static unsigned encodeNeonVMOVImmediate(unsigned Value) { + if (Value >= 256 && Value <= 0xffff) + Value = (Value >> 8) | ((Value & 0xff) ? 0xc00 : 0x200); + else if (Value > 0xffff && Value <= 0xffffff) + Value = (Value >> 16) | ((Value & 0xff) ? 0xd00 : 0x400); + else if (Value > 0xffffff) + Value = (Value >> 24) | 0x600; + return Value; + } + void addNEONi32vmovOperands(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(); - if (Value >= 256 && Value <= 0xffff) - Value = (Value >> 8) | ((Value & 0xff) ? 0xc00 : 0x200); - else if (Value > 0xffff && Value <= 0xffffff) - Value = (Value >> 16) | ((Value & 0xff) ? 0xd00 : 0x400); - else if (Value > 0xffffff) - Value = (Value >> 24) | 0x600; + unsigned Value = encodeNeonVMOVImmediate(CE->getValue()); Inst.addOperand(MCOperand::createImm(Value)); } - void addNEONvmovByteReplicateOperands(MCInst &Inst, unsigned N) const { + void addNEONvmovi8ReplicateOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addNEONi8ReplicateOperands(Inst, false); + } + + void addNEONvmovi16ReplicateOperands(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(); - assert((Inst.getOpcode() == ARM::VMOVv8i8 || - Inst.getOpcode() == ARM::VMOVv16i8) && - "All instructions that wants to replicate non-zero byte " - "always must be replaced with VMOVv8i8 or VMOVv16i8."); - unsigned B = Value & 0xff; - B |= 0xe00; // cmode = 0b1110 - Inst.addOperand(MCOperand::createImm(B)); + assert((Inst.getOpcode() == ARM::VMOVv4i16 || + Inst.getOpcode() == ARM::VMOVv8i16 || + Inst.getOpcode() == ARM::VMVNv4i16 || + Inst.getOpcode() == ARM::VMVNv8i16) && + "All instructions that want to replicate non-zero half-word " + "always must be replaced with V{MOV,MVN}v{4,8}i16."); + uint64_t Value = CE->getValue(); + unsigned Elem = Value & 0xffff; + if (Elem >= 256) + Elem = (Elem >> 8) | 0x200; + Inst.addOperand(MCOperand::createImm(Elem)); } void addNEONi32vmovNegOperands(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(); - if (Value >= 256 && Value <= 0xffff) - Value = (Value >> 8) | ((Value & 0xff) ? 0xc00 : 0x200); - else if (Value > 0xffff && Value <= 0xffffff) - Value = (Value >> 16) | ((Value & 0xff) ? 0xd00 : 0x400); - else if (Value > 0xffffff) - Value = (Value >> 24) | 0x600; + unsigned Value = encodeNeonVMOVImmediate(~CE->getValue()); Inst.addOperand(MCOperand::createImm(Value)); } + void addNEONvmovi32ReplicateOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + const MCConstantExpr *CE = dyn_cast(getImm()); + assert((Inst.getOpcode() == ARM::VMOVv2i32 || + Inst.getOpcode() == ARM::VMOVv4i32 || + Inst.getOpcode() == ARM::VMVNv2i32 || + Inst.getOpcode() == ARM::VMVNv4i32) && + "All instructions that want to replicate non-zero word " + "always must be replaced with V{MOV,MVN}v{2,4}i32."); + uint64_t Value = CE->getValue(); + unsigned Elem = encodeNeonVMOVImmediate(Value & 0xffffffff); + Inst.addOperand(MCOperand::createImm(Elem)); + } + void addNEONi64splatOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The immediate encodes the type of constant as well as the value. diff --git a/llvm/test/MC/ARM/vmov-vmvn-byte-replicate.s b/llvm/test/MC/ARM/vmov-vmvn-byte-replicate.s deleted file mode 100644 index 5931160afbc5..000000000000 --- a/llvm/test/MC/ARM/vmov-vmvn-byte-replicate.s +++ /dev/null @@ -1,31 +0,0 @@ -@ PR18921, "vmov" part. -@ RUN: llvm-mc -triple=armv7-linux-gnueabi -show-encoding < %s | FileCheck %s -.text - -@ CHECK: vmov.i8 d2, #0xff @ encoding: [0x1f,0x2e,0x87,0xf3] -@ CHECK: vmov.i8 q2, #0xff @ encoding: [0x5f,0x4e,0x87,0xf3] -@ CHECK: vmov.i8 d2, #0xab @ encoding: [0x1b,0x2e,0x82,0xf3] -@ CHECK: vmov.i8 q2, #0xab @ encoding: [0x5b,0x4e,0x82,0xf3] -@ CHECK: vmov.i8 q2, #0xab @ encoding: [0x5b,0x4e,0x82,0xf3] -@ CHECK: vmov.i8 q2, #0xab @ encoding: [0x5b,0x4e,0x82,0xf3] - -@ CHECK: vmov.i8 d2, #0x0 @ encoding: [0x10,0x2e,0x80,0xf2] -@ CHECK: vmov.i8 q2, #0x0 @ encoding: [0x50,0x4e,0x80,0xf2] -@ CHECK: vmov.i8 d2, #0x54 @ encoding: [0x14,0x2e,0x85,0xf2] -@ CHECK: vmov.i8 q2, #0x54 @ encoding: [0x54,0x4e,0x85,0xf2] -@ CHECK: vmov.i8 d2, #0x54 @ encoding: [0x14,0x2e,0x85,0xf2] -@ CHECK: vmov.i8 q2, #0x54 @ encoding: [0x54,0x4e,0x85,0xf2] - - vmov.i32 d2, #0xffffffff - vmov.i32 q2, #0xffffffff - vmov.i32 d2, #0xabababab - vmov.i32 q2, #0xabababab - vmov.i16 q2, #0xabab - vmov.i16 q2, #0xabab - - vmvn.i32 d2, #0xffffffff - vmvn.i32 q2, #0xffffffff - vmvn.i32 d2, #0xabababab - vmvn.i32 q2, #0xabababab - vmvn.i16 d2, #0xabab - vmvn.i16 q2, #0xabab diff --git a/llvm/test/MC/ARM/vmov-vmvn-replicate.s b/llvm/test/MC/ARM/vmov-vmvn-replicate.s new file mode 100644 index 000000000000..3169ea359f33 --- /dev/null +++ b/llvm/test/MC/ARM/vmov-vmvn-replicate.s @@ -0,0 +1,102 @@ +@ PR18921, "vmov" part. +@ RUN: llvm-mc -triple=armv7-linux-gnueabi -show-encoding < %s | FileCheck %s +.text + vmov.i64 d2, #0xffffffffffffffff + vmov.i64 q2, #0xffffffffffffffff + vmov.i32 d2, #0xffffffff + vmov.i32 q2, #0xffffffff + vmov.i64 d2, #0xabababababababab + vmov.i64 q2, #0xabababababababab + vmov.i32 d2, #0xabababab + vmov.i32 q2, #0xabababab + vmov.i16 q2, #0xabab + vmov.i16 q2, #0xabab + +@ CHECK: vmov.i64 d2, #0xffffffffffffffff @ encoding: [0x3f,0x2e,0x87,0xf3] +@ CHECK: vmov.i64 q2, #0xffffffffffffffff @ encoding: [0x7f,0x4e,0x87,0xf3] +@ CHECK: vmov.i8 d2, #0xff @ encoding: [0x1f,0x2e,0x87,0xf3] +@ CHECK: vmov.i8 q2, #0xff @ encoding: [0x5f,0x4e,0x87,0xf3] +@ CHECK: vmov.i8 d2, #0xab @ encoding: [0x1b,0x2e,0x82,0xf3] +@ CHECK: vmov.i8 q2, #0xab @ encoding: [0x5b,0x4e,0x82,0xf3] +@ CHECK: vmov.i8 d2, #0xab @ encoding: [0x1b,0x2e,0x82,0xf3] +@ CHECK: vmov.i8 q2, #0xab @ encoding: [0x5b,0x4e,0x82,0xf3] +@ CHECK: vmov.i8 q2, #0xab @ encoding: [0x5b,0x4e,0x82,0xf3] +@ CHECK: vmov.i8 q2, #0xab @ encoding: [0x5b,0x4e,0x82,0xf3] + + vmov.i64 d2, #0x00a500a500a500a5 + vmov.i64 q2, #0x00a500a500a500a5 + vmov.i32 d2, #0x00a500a5 + vmov.i32 q2, #0x00a500a5 + vmov.i64 d2, #0xa500a500a500a500 + vmov.i64 q2, #0xa500a500a500a500 + vmov.i32 d2, #0xa500a500 + vmov.i32 q2, #0xa500a500 + +@ CHECK: vmov.i16 d2, #0xa5 @ encoding: [0x15,0x28,0x82,0xf3] +@ CHECK: vmov.i16 q2, #0xa5 @ encoding: [0x55,0x48,0x82,0xf3] +@ CHECK: vmov.i16 d2, #0xa5 @ encoding: [0x15,0x28,0x82,0xf3] +@ CHECK: vmov.i16 q2, #0xa5 @ encoding: [0x55,0x48,0x82,0xf3] +@ CHECK: vmov.i16 d2, #0xa500 @ encoding: [0x15,0x2a,0x82,0xf3] +@ CHECK: vmov.i16 q2, #0xa500 @ encoding: [0x55,0x4a,0x82,0xf3] +@ CHECK: vmov.i16 d2, #0xa500 @ encoding: [0x15,0x2a,0x82,0xf3] +@ CHECK: vmov.i16 q2, #0xa500 @ encoding: [0x55,0x4a,0x82,0xf3] + + vmov.i64 d2, #0x000000a5000000a5 + vmov.i64 q2, #0x000000a5000000a5 + vmov.i64 d2, #0x00a5ffff00a5ffff + vmov.i64 q2, #0x00a5ffff00a5ffff + +@ CHECK: vmov.i32 d2, #0xa5 @ encoding: [0x15,0x20,0x82,0xf3] +@ CHECK: vmov.i32 q2, #0xa5 @ encoding: [0x55,0x40,0x82,0xf3] +@ CHECK: vmov.i32 d2, #0xa5ffff @ encoding: [0x15,0x2d,0x82,0xf3] +@ CHECK: vmov.i32 q2, #0xa5ffff @ encoding: [0x55,0x4d,0x82,0xf3] + + vmvn.i64 d2, #0xffffffffffffffff + vmvn.i64 q2, #0xffffffffffffffff + vmvn.i32 d2, #0xffffffff + vmvn.i32 q2, #0xffffffff + vmvn.i64 d2, #0xabababababababab + vmvn.i64 q2, #0xabababababababab + vmvn.i32 d2, #0xabababab + vmvn.i32 q2, #0xabababab + vmvn.i16 d2, #0xabab + vmvn.i16 q2, #0xabab + +@ CHECK: vmov.i8 d2, #0x0 @ encoding: [0x10,0x2e,0x80,0xf2] +@ CHECK: vmov.i8 q2, #0x0 @ encoding: [0x50,0x4e,0x80,0xf2] +@ CHECK: vmov.i8 d2, #0x0 @ encoding: [0x10,0x2e,0x80,0xf2] +@ CHECK: vmov.i8 q2, #0x0 @ encoding: [0x50,0x4e,0x80,0xf2] +@ CHECK: vmov.i8 d2, #0x54 @ encoding: [0x14,0x2e,0x85,0xf2] +@ CHECK: vmov.i8 q2, #0x54 @ encoding: [0x54,0x4e,0x85,0xf2] +@ CHECK: vmov.i8 d2, #0x54 @ encoding: [0x14,0x2e,0x85,0xf2] +@ CHECK: vmov.i8 q2, #0x54 @ encoding: [0x54,0x4e,0x85,0xf2] +@ CHECK: vmov.i8 d2, #0x54 @ encoding: [0x14,0x2e,0x85,0xf2] +@ CHECK: vmov.i8 q2, #0x54 @ encoding: [0x54,0x4e,0x85,0xf2] + + vmvn.i64 d2, #0x00a500a500a500a5 + vmvn.i64 q2, #0x00a500a500a500a5 + vmvn.i32 d2, #0x00a500a5 + vmvn.i32 q2, #0x00a500a5 + vmvn.i64 d2, #0xa500a500a500a500 + vmvn.i64 q2, #0xa500a500a500a500 + vmvn.i32 d2, #0xa500a500 + vmvn.i32 q2, #0xa500a500 + +@ CHECK: vmvn.i16 d2, #0xa5 @ encoding: [0x35,0x28,0x82,0xf3] +@ CHECK: vmvn.i16 q2, #0xa5 @ encoding: [0x75,0x48,0x82,0xf3] +@ CHECK: vmvn.i16 d2, #0xa5 @ encoding: [0x35,0x28,0x82,0xf3] +@ CHECK: vmvn.i16 q2, #0xa5 @ encoding: [0x75,0x48,0x82,0xf3] +@ CHECK: vmvn.i16 d2, #0xa500 @ encoding: [0x35,0x2a,0x82,0xf3] +@ CHECK: vmvn.i16 q2, #0xa500 @ encoding: [0x75,0x4a,0x82,0xf3] +@ CHECK: vmvn.i16 d2, #0xa500 @ encoding: [0x35,0x2a,0x82,0xf3] +@ CHECK: vmvn.i16 q2, #0xa500 @ encoding: [0x75,0x4a,0x82,0xf3] + + vmvn.i64 d2, #0x000000a5000000a5 + vmvn.i64 q2, #0x000000a5000000a5 + vmvn.i64 d2, #0x00a5ffff00a5ffff + vmvn.i64 q2, #0x00a5ffff00a5ffff + +@ CHECK: vmvn.i32 d2, #0xa5 @ encoding: [0x35,0x20,0x82,0xf3] +@ CHECK: vmvn.i32 q2, #0xa5 @ encoding: [0x75,0x40,0x82,0xf3] +@ CHECK: vmvn.i32 d2, #0xa5ffff @ encoding: [0x35,0x2d,0x82,0xf3] +@ CHECK: vmvn.i32 q2, #0xa5ffff @ encoding: [0x75,0x4d,0x82,0xf3]