From 71313f88cb9ad3b30eaede19cbbb4ef1be1ff882 Mon Sep 17 00:00:00 2001 From: Tim Northover Date: Mon, 10 Feb 2014 16:20:29 +0000 Subject: ARM: use natural LLVM IR for vshll instructions Similarly to the vshrn instructions, these are simple zext/sext + trunc operations. Using normal LLVM IR should allow for better code, and more sharing with the AArch64 backend. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@201093 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/IntrinsicsARM.td | 2 - lib/Target/ARM/ARMISelLowering.cpp | 19 -------- lib/Target/ARM/ARMISelLowering.h | 3 -- lib/Target/ARM/ARMInstrNEON.td | 41 ++++++++++------ test/CodeGen/ARM/vshll.ll | 99 +++++++++++++++++++++++++------------- 5 files changed, 93 insertions(+), 71 deletions(-) diff --git a/include/llvm/IR/IntrinsicsARM.td b/include/llvm/IR/IntrinsicsARM.td index 8002cc49b5..e86ee12570 100644 --- a/include/llvm/IR/IntrinsicsARM.td +++ b/include/llvm/IR/IntrinsicsARM.td @@ -287,8 +287,6 @@ def int_arm_neon_vpminu : Neon_2Arg_Intrinsic; // Vector Shift. def int_arm_neon_vshifts : Neon_2Arg_Intrinsic; def int_arm_neon_vshiftu : Neon_2Arg_Intrinsic; -def int_arm_neon_vshiftls : Neon_2Arg_Long_Intrinsic; -def int_arm_neon_vshiftlu : Neon_2Arg_Long_Intrinsic; // Vector Rounding Shift. def int_arm_neon_vrshifts : Neon_2Arg_Intrinsic; diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index 73f1b8f747..414922a69a 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -1078,9 +1078,6 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const { case ARMISD::VSHL: return "ARMISD::VSHL"; case ARMISD::VSHRs: return "ARMISD::VSHRs"; case ARMISD::VSHRu: return "ARMISD::VSHRu"; - case ARMISD::VSHLLs: return "ARMISD::VSHLLs"; - case ARMISD::VSHLLu: return "ARMISD::VSHLLu"; - case ARMISD::VSHLLi: return "ARMISD::VSHLLi"; case ARMISD::VRSHRs: return "ARMISD::VRSHRs"; case ARMISD::VRSHRu: return "ARMISD::VRSHRu"; case ARMISD::VRSHRN: return "ARMISD::VRSHRN"; @@ -9714,8 +9711,6 @@ static SDValue PerformIntrinsicCombine(SDNode *N, SelectionDAG &DAG) { // loads from a constant pool. case Intrinsic::arm_neon_vshifts: case Intrinsic::arm_neon_vshiftu: - case Intrinsic::arm_neon_vshiftls: - case Intrinsic::arm_neon_vshiftlu: case Intrinsic::arm_neon_vrshifts: case Intrinsic::arm_neon_vrshiftu: case Intrinsic::arm_neon_vrshiftn: @@ -9746,12 +9741,6 @@ static SDValue PerformIntrinsicCombine(SDNode *N, SelectionDAG &DAG) { } return SDValue(); - case Intrinsic::arm_neon_vshiftls: - case Intrinsic::arm_neon_vshiftlu: - if (isVShiftLImm(N->getOperand(2), VT, true, Cnt)) - break; - llvm_unreachable("invalid shift count for vshll intrinsic"); - case Intrinsic::arm_neon_vrshifts: case Intrinsic::arm_neon_vrshiftu: if (isVShiftRImm(N->getOperand(2), VT, false, true, Cnt)) @@ -9791,14 +9780,6 @@ static SDValue PerformIntrinsicCombine(SDNode *N, SelectionDAG &DAG) { case Intrinsic::arm_neon_vshiftu: // Opcode already set above. break; - case Intrinsic::arm_neon_vshiftls: - case Intrinsic::arm_neon_vshiftlu: - if (Cnt == VT.getVectorElementType().getSizeInBits()) - VShiftOpc = ARMISD::VSHLLi; - else - VShiftOpc = (IntNo == Intrinsic::arm_neon_vshiftls ? - ARMISD::VSHLLs : ARMISD::VSHLLu); - break; case Intrinsic::arm_neon_vrshifts: VShiftOpc = ARMISD::VRSHRs; break; case Intrinsic::arm_neon_vrshiftu: diff --git a/lib/Target/ARM/ARMISelLowering.h b/lib/Target/ARM/ARMISelLowering.h index fd54cbb647..bae23a69b5 100644 --- a/lib/Target/ARM/ARMISelLowering.h +++ b/lib/Target/ARM/ARMISelLowering.h @@ -113,9 +113,6 @@ namespace llvm { VSHL, // ...left VSHRs, // ...right (signed) VSHRu, // ...right (unsigned) - VSHLLs, // ...left long (signed) - VSHLLu, // ...left long (unsigned) - VSHLLi, // ...left long (with maximum shift count) // Vector rounding shift by immediate: VRSHRs, // ...right (signed) diff --git a/lib/Target/ARM/ARMInstrNEON.td b/lib/Target/ARM/ARMInstrNEON.td index a1e4159259..4bc82a2e43 100644 --- a/lib/Target/ARM/ARMInstrNEON.td +++ b/lib/Target/ARM/ARMInstrNEON.td @@ -466,9 +466,6 @@ def SDTARMVSHINS : SDTypeProfile<1, 3, [SDTCisInt<0>, SDTCisSameAs<0, 1>, def NEONvshl : SDNode<"ARMISD::VSHL", SDTARMVSH>; def NEONvshrs : SDNode<"ARMISD::VSHRs", SDTARMVSH>; def NEONvshru : SDNode<"ARMISD::VSHRu", SDTARMVSH>; -def NEONvshlls : SDNode<"ARMISD::VSHLLs", SDTARMVSHX>; -def NEONvshllu : SDNode<"ARMISD::VSHLLu", SDTARMVSHX>; -def NEONvshlli : SDNode<"ARMISD::VSHLLi", SDTARMVSHX>; def NEONvshrn : SDNode<"ARMISD::VSHRN", SDTARMVSHX>; def NEONvrshrs : SDNode<"ARMISD::VRSHRs", SDTARMVSH>; @@ -3038,12 +3035,12 @@ class N2VQSh op11_8, bit op7, bit op4, // Long shift by immediate. class N2VLSh op11_8, bit op7, bit op6, bit op4, string OpcodeStr, string Dt, - ValueType ResTy, ValueType OpTy, Operand ImmTy, SDNode OpNode> + ValueType ResTy, ValueType OpTy, Operand ImmTy, + SDPatternOperator OpNode> : N2VImm; + [(set QPR:$Vd, (ResTy (OpNode (OpTy DPR:$Vm), ImmTy:$SIMM)))]>; // Narrow shift by immediate. class N2VNSh op11_8, bit op7, bit op6, bit op4, @@ -3942,7 +3939,8 @@ multiclass N2VShInsR_QHSD op11_8, bit op4, // Neon Shift Long operations, // element sizes of 8, 16, 32 bits: multiclass N2VLSh_QHS op11_8, bit op7, bit op6, - bit op4, string OpcodeStr, string Dt, SDNode OpNode> { + bit op4, string OpcodeStr, string Dt, + SDPatternOperator OpNode> { def v8i16 : N2VLSh { let Inst{21-19} = 0b001; // imm6 = 001xxx @@ -4947,24 +4945,39 @@ defm VSHRu : N2VShR_QHSD<1, 1, 0b0000, 1, IIC_VSHLiD, "vshr", "u", "VSHRu", NEONvshru>; // VSHLL : Vector Shift Left Long -defm VSHLLs : N2VLSh_QHS<0, 1, 0b1010, 0, 0, 1, "vshll", "s", NEONvshlls>; -defm VSHLLu : N2VLSh_QHS<1, 1, 0b1010, 0, 0, 1, "vshll", "u", NEONvshllu>; +defm VSHLLs : N2VLSh_QHS<0, 1, 0b1010, 0, 0, 1, "vshll", "s", + PatFrag<(ops node:$LHS, node:$RHS), (NEONvshl (sext node:$LHS), node:$RHS)>>; +defm VSHLLu : N2VLSh_QHS<1, 1, 0b1010, 0, 0, 1, "vshll", "u", + PatFrag<(ops node:$LHS, node:$RHS), (NEONvshl (zext node:$LHS), node:$RHS)>>; // VSHLL : Vector Shift Left Long (with maximum shift count) class N2VLShMax op21_16, bits<4> op11_8, bit op7, bit op6, bit op4, string OpcodeStr, string Dt, ValueType ResTy, - ValueType OpTy, Operand ImmTy, SDNode OpNode> + ValueType OpTy, Operand ImmTy> : N2VLSh { + ResTy, OpTy, ImmTy, null_frag> { let Inst{21-16} = op21_16; let DecoderMethod = "DecodeVSHLMaxInstruction"; } def VSHLLi8 : N2VLShMax<1, 1, 0b110010, 0b0011, 0, 0, 0, "vshll", "i8", - v8i16, v8i8, imm8, NEONvshlli>; + v8i16, v8i8, imm8>; def VSHLLi16 : N2VLShMax<1, 1, 0b110110, 0b0011, 0, 0, 0, "vshll", "i16", - v4i32, v4i16, imm16, NEONvshlli>; + v4i32, v4i16, imm16>; def VSHLLi32 : N2VLShMax<1, 1, 0b111010, 0b0011, 0, 0, 0, "vshll", "i32", - v2i64, v2i32, imm32, NEONvshlli>; + v2i64, v2i32, imm32>; + +def : Pat<(v8i16 (NEONvshl (zext (v8i8 DPR:$Rn)), (i32 8))), + (VSHLLi8 DPR:$Rn, 8)>; +def : Pat<(v4i32 (NEONvshl (zext (v4i16 DPR:$Rn)), (i32 16))), + (VSHLLi16 DPR:$Rn, 16)>; +def : Pat<(v2i64 (NEONvshl (zext (v2i32 DPR:$Rn)), (i32 32))), + (VSHLLi32 DPR:$Rn, 32)>; +def : Pat<(v8i16 (NEONvshl (sext (v8i8 DPR:$Rn)), (i32 8))), + (VSHLLi8 DPR:$Rn, 8)>; +def : Pat<(v4i32 (NEONvshl (sext (v4i16 DPR:$Rn)), (i32 16))), + (VSHLLi16 DPR:$Rn, 16)>; +def : Pat<(v2i64 (NEONvshl (sext (v2i32 DPR:$Rn)), (i32 32))), + (VSHLLi32 DPR:$Rn, 32)>; // VSHRN : Vector Shift Right and Narrow defm VSHRN : N2VNSh_HSD<0,1,0b1000,0,0,1, IIC_VSHLiD, "vshrn", "i", diff --git a/test/CodeGen/ARM/vshll.ll b/test/CodeGen/ARM/vshll.ll index ae80664148..8faee118ff 100644 --- a/test/CodeGen/ARM/vshll.ll +++ b/test/CodeGen/ARM/vshll.ll @@ -3,49 +3,55 @@ define <8 x i16> @vshlls8(<8 x i8>* %A) nounwind { ;CHECK-LABEL: vshlls8: ;CHECK: vshll.s8 - %tmp1 = load <8 x i8>* %A - %tmp2 = call <8 x i16> @llvm.arm.neon.vshiftls.v8i16(<8 x i8> %tmp1, <8 x i8> < i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7 >) - ret <8 x i16> %tmp2 + %tmp1 = load <8 x i8>* %A + %sext = sext <8 x i8> %tmp1 to <8 x i16> + %shift = shl <8 x i16> %sext, + ret <8 x i16> %shift } define <4 x i32> @vshlls16(<4 x i16>* %A) nounwind { ;CHECK-LABEL: vshlls16: ;CHECK: vshll.s16 - %tmp1 = load <4 x i16>* %A - %tmp2 = call <4 x i32> @llvm.arm.neon.vshiftls.v4i32(<4 x i16> %tmp1, <4 x i16> < i16 15, i16 15, i16 15, i16 15 >) - ret <4 x i32> %tmp2 + %tmp1 = load <4 x i16>* %A + %sext = sext <4 x i16> %tmp1 to <4 x i32> + %shift = shl <4 x i32> %sext, + ret <4 x i32> %shift } define <2 x i64> @vshlls32(<2 x i32>* %A) nounwind { ;CHECK-LABEL: vshlls32: ;CHECK: vshll.s32 - %tmp1 = load <2 x i32>* %A - %tmp2 = call <2 x i64> @llvm.arm.neon.vshiftls.v2i64(<2 x i32> %tmp1, <2 x i32> < i32 31, i32 31 >) - ret <2 x i64> %tmp2 + %tmp1 = load <2 x i32>* %A + %sext = sext <2 x i32> %tmp1 to <2 x i64> + %shift = shl <2 x i64> %sext, + ret <2 x i64> %shift } define <8 x i16> @vshllu8(<8 x i8>* %A) nounwind { ;CHECK-LABEL: vshllu8: ;CHECK: vshll.u8 - %tmp1 = load <8 x i8>* %A - %tmp2 = call <8 x i16> @llvm.arm.neon.vshiftlu.v8i16(<8 x i8> %tmp1, <8 x i8> < i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7 >) - ret <8 x i16> %tmp2 + %tmp1 = load <8 x i8>* %A + %zext = zext <8 x i8> %tmp1 to <8 x i16> + %shift = shl <8 x i16> %zext, + ret <8 x i16> %shift } define <4 x i32> @vshllu16(<4 x i16>* %A) nounwind { ;CHECK-LABEL: vshllu16: ;CHECK: vshll.u16 - %tmp1 = load <4 x i16>* %A - %tmp2 = call <4 x i32> @llvm.arm.neon.vshiftlu.v4i32(<4 x i16> %tmp1, <4 x i16> < i16 15, i16 15, i16 15, i16 15 >) - ret <4 x i32> %tmp2 + %tmp1 = load <4 x i16>* %A + %zext = zext <4 x i16> %tmp1 to <4 x i32> + %shift = shl <4 x i32> %zext, + ret <4 x i32> %shift } define <2 x i64> @vshllu32(<2 x i32>* %A) nounwind { ;CHECK-LABEL: vshllu32: ;CHECK: vshll.u32 - %tmp1 = load <2 x i32>* %A - %tmp2 = call <2 x i64> @llvm.arm.neon.vshiftlu.v2i64(<2 x i32> %tmp1, <2 x i32> < i32 31, i32 31 >) - ret <2 x i64> %tmp2 + %tmp1 = load <2 x i32>* %A + %zext = zext <2 x i32> %tmp1 to <2 x i64> + %shift = shl <2 x i64> %zext, + ret <2 x i64> %shift } ; The following tests use the maximum shift count, so the signedness is @@ -53,31 +59,58 @@ define <2 x i64> @vshllu32(<2 x i32>* %A) nounwind { define <8 x i16> @vshlli8(<8 x i8>* %A) nounwind { ;CHECK-LABEL: vshlli8: ;CHECK: vshll.i8 - %tmp1 = load <8 x i8>* %A - %tmp2 = call <8 x i16> @llvm.arm.neon.vshiftls.v8i16(<8 x i8> %tmp1, <8 x i8> < i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8, i8 8 >) - ret <8 x i16> %tmp2 + %tmp1 = load <8 x i8>* %A + %sext = sext <8 x i8> %tmp1 to <8 x i16> + %shift = shl <8 x i16> %sext, + ret <8 x i16> %shift } define <4 x i32> @vshlli16(<4 x i16>* %A) nounwind { ;CHECK-LABEL: vshlli16: ;CHECK: vshll.i16 - %tmp1 = load <4 x i16>* %A - %tmp2 = call <4 x i32> @llvm.arm.neon.vshiftlu.v4i32(<4 x i16> %tmp1, <4 x i16> < i16 16, i16 16, i16 16, i16 16 >) - ret <4 x i32> %tmp2 + %tmp1 = load <4 x i16>* %A + %zext = zext <4 x i16> %tmp1 to <4 x i32> + %shift = shl <4 x i32> %zext, + ret <4 x i32> %shift } define <2 x i64> @vshlli32(<2 x i32>* %A) nounwind { ;CHECK-LABEL: vshlli32: ;CHECK: vshll.i32 - %tmp1 = load <2 x i32>* %A - %tmp2 = call <2 x i64> @llvm.arm.neon.vshiftls.v2i64(<2 x i32> %tmp1, <2 x i32> < i32 32, i32 32 >) - ret <2 x i64> %tmp2 + %tmp1 = load <2 x i32>* %A + %zext = zext <2 x i32> %tmp1 to <2 x i64> + %shift = shl <2 x i64> %zext, + ret <2 x i64> %shift } -declare <8 x i16> @llvm.arm.neon.vshiftls.v8i16(<8 x i8>, <8 x i8>) nounwind readnone -declare <4 x i32> @llvm.arm.neon.vshiftls.v4i32(<4 x i16>, <4 x i16>) nounwind readnone -declare <2 x i64> @llvm.arm.neon.vshiftls.v2i64(<2 x i32>, <2 x i32>) nounwind readnone +; And these have a shift just out of range so separate vmovl and vshl +; instructions are needed. +define <8 x i16> @vshllu8_bad(<8 x i8>* %A) nounwind { +; CHECK-LABEL: vshllu8_bad: +; CHECK: vmovl.u8 +; CHECK: vshl.i16 + %tmp1 = load <8 x i8>* %A + %zext = zext <8 x i8> %tmp1 to <8 x i16> + %shift = shl <8 x i16> %zext, + ret <8 x i16> %shift +} + +define <4 x i32> @vshlls16_bad(<4 x i16>* %A) nounwind { +; CHECK-LABEL: vshlls16_bad: +; CHECK: vmovl.s16 +; CHECK: vshl.i32 + %tmp1 = load <4 x i16>* %A + %sext = sext <4 x i16> %tmp1 to <4 x i32> + %shift = shl <4 x i32> %sext, + ret <4 x i32> %shift +} -declare <8 x i16> @llvm.arm.neon.vshiftlu.v8i16(<8 x i8>, <8 x i8>) nounwind readnone -declare <4 x i32> @llvm.arm.neon.vshiftlu.v4i32(<4 x i16>, <4 x i16>) nounwind readnone -declare <2 x i64> @llvm.arm.neon.vshiftlu.v2i64(<2 x i32>, <2 x i32>) nounwind readnone +define <2 x i64> @vshllu32_bad(<2 x i32>* %A) nounwind { +; CHECK-LABEL: vshllu32_bad: +; CHECK: vmovl.u32 +; CHECK: vshl.i64 + %tmp1 = load <2 x i32>* %A + %zext = zext <2 x i32> %tmp1 to <2 x i64> + %shift = shl <2 x i64> %zext, + ret <2 x i64> %shift +} -- cgit v1.2.3