[llvm-commits] [llvm] r133813 - in /llvm/trunk: lib/Target/ARM/ARMISelLowering.cpp test/CodeGen/ARM/vcvt_combine.ll test/CodeGen/ARM/vdiv_combine.ll

Chad Rosier mcrosier at apple.com
Fri Jun 24 13:51:38 PDT 2011


This commit is for rdar://9603036.  The radar number was accidentally omitted in the svn commit message, so I thought it would be best to at least document it here.

 Chad

On Jun 24, 2011, at 12:23 PM, Chad Rosier wrote:

> Author: mcrosier
> Date: Fri Jun 24 14:23:04 2011
> New Revision: 133813
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=133813&view=rev
> Log:
> The Neon VCVT (between floating-point and fixed-point, Advanced SIMD) 
> instructions can be used to match combinations of multiply/divide and VCVT 
> (between floating-point and integer, Advanced SIMD).  Basically the VCVT 
> immediate operand that specifies the number of fraction bits corresponds to a 
> floating-point multiply or divide by the corresponding power of 2.
> 
> For example, VCVT (floating-point to fixed-point, Advanced SIMD) can replace a 
> combination of VMUL and VCVT (floating-point to integer) as follows:
> 
> Example (assume d17 = <float 8.000000e+00, float 8.000000e+00>):
>  vmul.f32        d16, d17, d16
>  vcvt.s32.f32    d16, d16
> becomes:
>  vcvt.s32.f32    d16, d16, #3
> 
> Similarly, VCVT (fixed-point to floating-point, Advanced SIMD) can replace a 
> combinations of VCVT (integer to floating-point) and VDIV as follows:
> 
> Example (assume d17 = <float 8.000000e+00, float 8.000000e+00>):
>  vcvt.f32.s32    d16, d16
>  vdiv.f32        d16, d17, d16
> becomes:
>  vcvt.f32.s32    d16, d16, #3
> 
> Added:
>    llvm/trunk/test/CodeGen/ARM/vcvt_combine.ll
>    llvm/trunk/test/CodeGen/ARM/vdiv_combine.ll
> Modified:
>    llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp
> 
> Modified: llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp?rev=133813&r1=133812&r2=133813&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp (original)
> +++ llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp Fri Jun 24 14:23:04 2011
> @@ -506,6 +506,9 @@
>     setTargetDAGCombine(ISD::VECTOR_SHUFFLE);
>     setTargetDAGCombine(ISD::INSERT_VECTOR_ELT);
>     setTargetDAGCombine(ISD::STORE);
> +    setTargetDAGCombine(ISD::FP_TO_SINT);
> +    setTargetDAGCombine(ISD::FP_TO_UINT);
> +    setTargetDAGCombine(ISD::FDIV);
>   }
> 
>   computeRegisterProperties();
> @@ -6479,7 +6482,104 @@
>   return DCI.DAG.getNode(ISD::BITCAST, N->getDebugLoc(), VT, Op);
> }
> 
> -/// getVShiftImm - Check if this is a valid build_vector for the immediate
> +// isConstVecPow2 - Return true if each vector element is a power of 2, all 
> +// elements are the same constant, C, and Log2(C) ranges from 1 to 32.
> +static bool isConstVecPow2(SDValue ConstVec, bool isSigned, uint64_t &C)
> +{
> +  integerPart c0, cN;
> +  for (unsigned I = 0, E = ConstVec.getValueType().getVectorNumElements();
> +       I != E; I++) {
> +    ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(ConstVec.getOperand(I));
> +    if (!C)
> +      return false;
> +
> +    bool isExact;    
> +    APFloat APF = C->getValueAPF();
> +    if (APF.convertToInteger(&cN, 64, isSigned, APFloat::rmTowardZero, &isExact)
> +        != APFloat::opOK || !isExact)
> +      return false;
> +
> +    c0 = (I == 0) ? cN : c0;
> +    if (!isPowerOf2_64(cN) || c0 != cN || Log2_64(c0) < 1 || Log2_64(c0) > 32)
> +      return false;
> +  }
> +  C = c0;
> +  return true;
> +}
> +
> +/// PerformVCVTCombine - VCVT (floating-point to fixed-point, Advanced SIMD)
> +/// can replace combinations of VMUL and VCVT (floating-point to integer)
> +/// when the VMUL has a constant operand that is a power of 2.
> +///
> +/// Example (assume d17 = <float 8.000000e+00, float 8.000000e+00>):
> +///  vmul.f32        d16, d17, d16
> +///  vcvt.s32.f32    d16, d16
> +/// becomes:
> +///  vcvt.s32.f32    d16, d16, #3
> +static SDValue PerformVCVTCombine(SDNode *N,
> +                                  TargetLowering::DAGCombinerInfo &DCI,
> +                                  const ARMSubtarget *Subtarget) {
> +  SelectionDAG &DAG = DCI.DAG;
> +  SDValue Op = N->getOperand(0);
> +
> +  if (!Subtarget->hasNEON() || !Op.getValueType().isVector() ||
> +      Op.getOpcode() != ISD::FMUL)
> +    return SDValue();
> +
> +  uint64_t C;
> +  SDValue N0 = Op->getOperand(0);
> +  SDValue ConstVec = Op->getOperand(1);
> +  bool isSigned = N->getOpcode() == ISD::FP_TO_SINT;
> +
> +  if (ConstVec.getOpcode() != ISD::BUILD_VECTOR || 
> +      !isConstVecPow2(ConstVec, isSigned, C))
> +    return SDValue();
> +
> +  unsigned IntrinsicOpcode = isSigned ? Intrinsic::arm_neon_vcvtfp2fxs :
> +    Intrinsic::arm_neon_vcvtfp2fxu;
> +  return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, N->getDebugLoc(),
> +                     N->getValueType(0),
> +                     DAG.getConstant(IntrinsicOpcode, MVT::i32), N0, 
> +                     DAG.getConstant(Log2_64(C), MVT::i32));
> +}
> +
> +/// PerformVDIVCombine - VCVT (fixed-point to floating-point, Advanced SIMD)
> +/// can replace combinations of VCVT (integer to floating-point) and VDIV
> +/// when the VDIV has a constant operand that is a power of 2.
> +///
> +/// Example (assume d17 = <float 8.000000e+00, float 8.000000e+00>):
> +///  vcvt.f32.s32    d16, d16
> +///  vdiv.f32        d16, d17, d16
> +/// becomes:
> +///  vcvt.f32.s32    d16, d16, #3
> +static SDValue PerformVDIVCombine(SDNode *N,
> +                                  TargetLowering::DAGCombinerInfo &DCI,
> +                                  const ARMSubtarget *Subtarget) {
> +  SelectionDAG &DAG = DCI.DAG;
> +  SDValue Op = N->getOperand(0);
> +  unsigned OpOpcode = Op.getNode()->getOpcode();
> +
> +  if (!Subtarget->hasNEON() || !N->getValueType(0).isVector() ||
> +      (OpOpcode != ISD::SINT_TO_FP && OpOpcode != ISD::UINT_TO_FP))
> +    return SDValue();
> +
> +  uint64_t C;
> +  SDValue ConstVec = N->getOperand(1);
> +  bool isSigned = OpOpcode == ISD::SINT_TO_FP;
> +
> +  if (ConstVec.getOpcode() != ISD::BUILD_VECTOR ||
> +      !isConstVecPow2(ConstVec, isSigned, C))
> +    return SDValue();
> +
> +  unsigned IntrinsicOpcode = isSigned ? Intrinsic::arm_neon_vcvtfxs2fp : 
> +    Intrinsic::arm_neon_vcvtfxu2fp;
> +  return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, N->getDebugLoc(),
> +                     Op.getValueType(),
> +                     DAG.getConstant(IntrinsicOpcode, MVT::i32), 
> +                     Op.getOperand(0), DAG.getConstant(Log2_64(C), MVT::i32));
> +}
> +
> +/// Getvshiftimm - Check if this is a valid build_vector for the immediate
> /// operand of a vector shift operation, where all the elements of the
> /// build_vector must have the same constant integer value.
> static bool getVShiftImm(SDValue Op, unsigned ElementBits, int64_t &Cnt) {
> @@ -6868,6 +6968,9 @@
>   case ISD::INSERT_VECTOR_ELT: return PerformInsertEltCombine(N, DCI);
>   case ISD::VECTOR_SHUFFLE: return PerformVECTOR_SHUFFLECombine(N, DCI.DAG);
>   case ARMISD::VDUPLANE: return PerformVDUPLANECombine(N, DCI);
> +  case ISD::FP_TO_SINT:
> +  case ISD::FP_TO_UINT: return PerformVCVTCombine(N, DCI, Subtarget);
> +  case ISD::FDIV:       return PerformVDIVCombine(N, DCI, Subtarget);
>   case ISD::INTRINSIC_WO_CHAIN: return PerformIntrinsicCombine(N, DCI.DAG);
>   case ISD::SHL:
>   case ISD::SRA:
> 
> Added: llvm/trunk/test/CodeGen/ARM/vcvt_combine.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/vcvt_combine.ll?rev=133813&view=auto
> ==============================================================================
> --- llvm/trunk/test/CodeGen/ARM/vcvt_combine.ll (added)
> +++ llvm/trunk/test/CodeGen/ARM/vcvt_combine.ll Fri Jun 24 14:23:04 2011
> @@ -0,0 +1,99 @@
> +; RUN: llc < %s -mtriple=armv7-apple-ios | FileCheck %s
> +
> + at in = global float 0x400921FA00000000, align 4
> +
> +; Test signed conversion.
> +; CHECK: t0
> +; CHECK-NOT: vmul
> +define void @t0() nounwind {
> +entry:
> +  %tmp = load float* @in, align 4, !tbaa !0
> +  %vecinit.i = insertelement <2 x float> undef, float %tmp, i32 0
> +  %vecinit2.i = insertelement <2 x float> %vecinit.i, float %tmp, i32 1
> +  %mul.i = fmul <2 x float> %vecinit2.i, <float 8.000000e+00, float 8.000000e+00>
> +  %vcvt.i = fptosi <2 x float> %mul.i to <2 x i32>
> +  tail call void @foo_int32x2_t(<2 x i32> %vcvt.i) nounwind
> +  ret void
> +}
> +
> +declare void @foo_int32x2_t(<2 x i32>)
> +
> +; Test unsigned conversion.
> +; CHECK: t1
> +; CHECK-NOT: vmul
> +define void @t1() nounwind {
> +entry:
> +  %tmp = load float* @in, align 4, !tbaa !0
> +  %vecinit.i = insertelement <2 x float> undef, float %tmp, i32 0
> +  %vecinit2.i = insertelement <2 x float> %vecinit.i, float %tmp, i32 1
> +  %mul.i = fmul <2 x float> %vecinit2.i, <float 8.000000e+00, float 8.000000e+00>
> +  %vcvt.i = fptoui <2 x float> %mul.i to <2 x i32>
> +  tail call void @foo_uint32x2_t(<2 x i32> %vcvt.i) nounwind
> +  ret void
> +}
> +
> +declare void @foo_uint32x2_t(<2 x i32>)
> +
> +; Test which should not fold due to non-power of 2.
> +; CHECK: t2
> +; CHECK: vmul
> +define void @t2() nounwind {
> +entry:
> +  %tmp = load float* @in, align 4, !tbaa !0
> +  %vecinit.i = insertelement <2 x float> undef, float %tmp, i32 0
> +  %vecinit2.i = insertelement <2 x float> %vecinit.i, float %tmp, i32 1
> +  %mul.i = fmul <2 x float> %vecinit2.i, <float 0x401B333340000000, float 0x401B333340000000>
> +  %vcvt.i = fptosi <2 x float> %mul.i to <2 x i32>
> +  tail call void @foo_int32x2_t(<2 x i32> %vcvt.i) nounwind
> +  ret void
> +}
> +
> +; Test which should not fold due to power of 2 out of range.
> +; CHECK: t3
> +; CHECK: vmul
> +define void @t3() nounwind {
> +entry:
> +  %tmp = load float* @in, align 4, !tbaa !0
> +  %vecinit.i = insertelement <2 x float> undef, float %tmp, i32 0
> +  %vecinit2.i = insertelement <2 x float> %vecinit.i, float %tmp, i32 1
> +  %mul.i = fmul <2 x float> %vecinit2.i, <float 0x4200000000000000, float 0x4200000000000000>
> +  %vcvt.i = fptosi <2 x float> %mul.i to <2 x i32>
> +  tail call void @foo_int32x2_t(<2 x i32> %vcvt.i) nounwind
> +  ret void
> +}
> +
> +; Test which case where const is max power of 2 (i.e., 2^32).
> +; CHECK: t4
> +; CHECK-NOT: vmul
> +define void @t4() nounwind {
> +entry:
> +  %tmp = load float* @in, align 4, !tbaa !0
> +  %vecinit.i = insertelement <2 x float> undef, float %tmp, i32 0
> +  %vecinit2.i = insertelement <2 x float> %vecinit.i, float %tmp, i32 1
> +  %mul.i = fmul <2 x float> %vecinit2.i, <float 0x41F0000000000000, float 0x41F0000000000000>
> +  %vcvt.i = fptosi <2 x float> %mul.i to <2 x i32>
> +  tail call void @foo_int32x2_t(<2 x i32> %vcvt.i) nounwind
> +  ret void
> +}
> +
> +; Test quadword.
> +; CHECK: t5
> +; CHECK-NOT: vmul
> +define void @t5() nounwind {
> +entry:
> +  %tmp = load float* @in, align 4, !tbaa !0
> +  %vecinit.i = insertelement <4 x float> undef, float %tmp, i32 0
> +  %vecinit2.i = insertelement <4 x float> %vecinit.i, float %tmp, i32 1
> +  %vecinit4.i = insertelement <4 x float> %vecinit2.i, float %tmp, i32 2
> +  %vecinit6.i = insertelement <4 x float> %vecinit4.i, float %tmp, i32 3
> +  %mul.i = fmul <4 x float> %vecinit6.i, <float 8.000000e+00, float 8.000000e+00, float 8.000000e+00, float 8.000000e+00>
> +  %vcvt.i = fptosi <4 x float> %mul.i to <4 x i32>
> +  tail call void @foo_int32x4_t(<4 x i32> %vcvt.i) nounwind
> +  ret void
> +}
> +
> +declare void @foo_int32x4_t(<4 x i32>)
> +
> +!0 = metadata !{metadata !"float", metadata !1}
> +!1 = metadata !{metadata !"omnipotent char", metadata !2}
> +!2 = metadata !{metadata !"Simple C/C++ TBAA", null}
> 
> Added: llvm/trunk/test/CodeGen/ARM/vdiv_combine.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/vdiv_combine.ll?rev=133813&view=auto
> ==============================================================================
> --- llvm/trunk/test/CodeGen/ARM/vdiv_combine.ll (added)
> +++ llvm/trunk/test/CodeGen/ARM/vdiv_combine.ll Fri Jun 24 14:23:04 2011
> @@ -0,0 +1,102 @@
> +; RUN: llc < %s -mtriple=armv7-apple-ios | FileCheck %s
> +
> + at in = global float 0x400921FA00000000, align 4
> + at iin = global i32 -1023, align 4
> + at uin = global i32 1023, align 4
> +
> +declare void @foo_int32x4_t(<4 x i32>)
> +
> +; Test signed conversion.
> +; CHECK: t1
> +; CHECK-NOT: vdiv
> +define void @t1() nounwind {
> +entry:
> +  %tmp = load i32* @iin, align 4, !tbaa !3
> +  %vecinit.i = insertelement <2 x i32> undef, i32 %tmp, i32 0
> +  %vecinit2.i = insertelement <2 x i32> %vecinit.i, i32 %tmp, i32 1
> +  %vcvt.i = sitofp <2 x i32> %vecinit2.i to <2 x float>
> +  %div.i = fdiv <2 x float> %vcvt.i, <float 8.000000e+00, float 8.000000e+00>
> +  tail call void @foo_float32x2_t(<2 x float> %div.i) nounwind
> +  ret void
> +}
> +
> +declare void @foo_float32x2_t(<2 x float>)
> +
> +; Test unsigned conversion.
> +; CHECK: t2
> +; CHECK-NOT: vdiv
> +define void @t2() nounwind {
> +entry:
> +  %tmp = load i32* @uin, align 4, !tbaa !3
> +  %vecinit.i = insertelement <2 x i32> undef, i32 %tmp, i32 0
> +  %vecinit2.i = insertelement <2 x i32> %vecinit.i, i32 %tmp, i32 1
> +  %vcvt.i = uitofp <2 x i32> %vecinit2.i to <2 x float>
> +  %div.i = fdiv <2 x float> %vcvt.i, <float 8.000000e+00, float 8.000000e+00>
> +  tail call void @foo_float32x2_t(<2 x float> %div.i) nounwind
> +  ret void
> +}
> +
> +; Test which should not fold due to non-power of 2.
> +; CHECK: t3
> +; CHECK: vdiv
> +define void @t3() nounwind {
> +entry:
> +  %tmp = load i32* @iin, align 4, !tbaa !3
> +  %vecinit.i = insertelement <2 x i32> undef, i32 %tmp, i32 0
> +  %vecinit2.i = insertelement <2 x i32> %vecinit.i, i32 %tmp, i32 1
> +  %vcvt.i = sitofp <2 x i32> %vecinit2.i to <2 x float>
> +  %div.i = fdiv <2 x float> %vcvt.i, <float 0x401B333340000000, float 0x401B333340000000>
> +  tail call void @foo_float32x2_t(<2 x float> %div.i) nounwind
> +  ret void
> +}
> +
> +; Test which should not fold due to power of 2 out of range.
> +; CHECK: t4
> +; CHECK: vdiv
> +define void @t4() nounwind {
> +entry:
> +  %tmp = load i32* @iin, align 4, !tbaa !3
> +  %vecinit.i = insertelement <2 x i32> undef, i32 %tmp, i32 0
> +  %vecinit2.i = insertelement <2 x i32> %vecinit.i, i32 %tmp, i32 1
> +  %vcvt.i = sitofp <2 x i32> %vecinit2.i to <2 x float>
> +  %div.i = fdiv <2 x float> %vcvt.i, <float 0x4200000000000000, float 0x4200000000000000>
> +  tail call void @foo_float32x2_t(<2 x float> %div.i) nounwind
> +  ret void
> +}
> +
> +; Test case where const is max power of 2 (i.e., 2^32).
> +; CHECK: t5
> +; CHECK-NOT: vdiv
> +define void @t5() nounwind {
> +entry:
> +  %tmp = load i32* @iin, align 4, !tbaa !3
> +  %vecinit.i = insertelement <2 x i32> undef, i32 %tmp, i32 0
> +  %vecinit2.i = insertelement <2 x i32> %vecinit.i, i32 %tmp, i32 1
> +  %vcvt.i = sitofp <2 x i32> %vecinit2.i to <2 x float>
> +  %div.i = fdiv <2 x float> %vcvt.i, <float 0x41F0000000000000, float 0x41F0000000000000>
> +  tail call void @foo_float32x2_t(<2 x float> %div.i) nounwind
> +  ret void
> +}
> +
> +; Test quadword.
> +; CHECK: t6
> +; CHECK-NOT: vdiv
> +define void @t6() nounwind {
> +entry:
> +  %tmp = load i32* @iin, align 4, !tbaa !3
> +  %vecinit.i = insertelement <4 x i32> undef, i32 %tmp, i32 0
> +  %vecinit2.i = insertelement <4 x i32> %vecinit.i, i32 %tmp, i32 1
> +  %vecinit4.i = insertelement <4 x i32> %vecinit2.i, i32 %tmp, i32 2
> +  %vecinit6.i = insertelement <4 x i32> %vecinit4.i, i32 %tmp, i32 3
> +  %vcvt.i = sitofp <4 x i32> %vecinit6.i to <4 x float>
> +  %div.i = fdiv <4 x float> %vcvt.i, <float 8.000000e+00, float 8.000000e+00, float 8.000000e+00, float 8.000000e+00>
> +  tail call void @foo_float32x4_t(<4 x float> %div.i) nounwind
> +  ret void
> +}
> +
> +declare void @foo_float32x4_t(<4 x float>)
> +
> +!0 = metadata !{metadata !"float", metadata !1}
> +!1 = metadata !{metadata !"omnipotent char", metadata !2}
> +!2 = metadata !{metadata !"Simple C/C++ TBAA", null}
> +!3 = metadata !{metadata !"int", metadata !1}
> 
> 
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits




More information about the llvm-commits mailing list