[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 12:23:04 PDT 2011


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}





More information about the llvm-commits mailing list