From 9b0878512fb57ee4b0bc483509e4d9f4f0b9e426 Mon Sep 17 00:00:00 2001 From: Jim Grosbach Date: Mon, 19 Dec 2011 23:51:07 +0000 Subject: [PATCH] ARM NEON assembly aliases for VMOV<-->VMVN for i32 immediates. e.g., "vmov.i32 d4, #-118" can be assembled as "vmvn.i32 d4, #117" rdar://10603913 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@146925 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/ARMInstrNEON.td | 15 ++++++++++++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 30 +++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/lib/Target/ARM/ARMInstrNEON.td b/lib/Target/ARM/ARMInstrNEON.td index ef987d21052..cd10dde0e1e 100644 --- a/lib/Target/ARM/ARMInstrNEON.td +++ b/lib/Target/ARM/ARMInstrNEON.td @@ -39,6 +39,11 @@ def nImmVMOVI32 : Operand { let PrintMethod = "printNEONModImmOperand"; let ParserMatchClass = nImmVMOVI32AsmOperand; } +def nImmVMOVI32NegAsmOperand : AsmOperandClass { let Name = "NEONi32vmovNeg"; } +def nImmVMOVI32Neg : Operand { + let PrintMethod = "printNEONModImmOperand"; + let ParserMatchClass = nImmVMOVI32NegAsmOperand; +} def nImmVMOVF32 : Operand { let PrintMethod = "printFPImmOperand"; let ParserMatchClass = FPImmOperand; @@ -5949,6 +5954,16 @@ def : NEONInstAlias<"vpadd${p}.i32 $Vdn, $Vm", def : NEONInstAlias<"vpadd${p}.f32 $Vdn, $Vm", (VPADDf DPR:$Vdn, DPR:$Vdn, DPR:$Vm, pred:$p)>; +// "vmov Rd, #-imm" can be handled via "vmvn". +def : NEONInstAlias<"vmov${p}.i32 $Vd, $imm", + (VMVNv2i32 DPR:$Vd, nImmVMOVI32Neg:$imm, pred:$p)>; +def : NEONInstAlias<"vmov${p}.i32 $Vd, $imm", + (VMVNv4i32 QPR:$Vd, nImmVMOVI32Neg:$imm, pred:$p)>; +def : NEONInstAlias<"vmvn${p}.i32 $Vd, $imm", + (VMOVv2i32 DPR:$Vd, nImmVMOVI32Neg:$imm, pred:$p)>; +def : NEONInstAlias<"vmvn${p}.i32 $Vd, $imm", + (VMOVv4i32 QPR:$Vd, nImmVMOVI32Neg:$imm, pred:$p)>; + // 'gas' compatibility aliases for quad-word instructions. Strictly speaking, // these should restrict to just the Q register variants, but the register // classes are enough to match correctly regardless, so we keep it simple diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 1c109f0a520..9852cc8b805 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -1222,6 +1222,22 @@ public: (Value >= 0x01ff && Value <= 0xffff && (Value & 0xff) == 0xff) || (Value >= 0x01ffff && Value <= 0xffffff && (Value & 0xffff) == 0xffff); } + bool isNEONi32vmovNeg() const { + if (Kind != k_Immediate) + return false; + 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, + // for VMOV/VMVN only, 00Xf or 0Xff are also accepted. + return (Value >= 0 && Value < 256) || + (Value >= 0x0100 && Value <= 0xff00) || + (Value >= 0x010000 && Value <= 0xff0000) || + (Value >= 0x01000000 && Value <= 0xff000000) || + (Value >= 0x01ff && Value <= 0xffff && (Value & 0xff) == 0xff) || + (Value >= 0x01ffff && Value <= 0xffffff && (Value & 0xffff) == 0xffff); + } bool isNEONi64splat() const { if (Kind != k_Immediate) @@ -1825,6 +1841,20 @@ public: Inst.addOperand(MCOperand::CreateImm(Value)); } + 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; + Inst.addOperand(MCOperand::CreateImm(Value)); + } + 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. -- 2.34.1