forked from OSchip/llvm-project
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 llvm-svn: 133813
This commit is contained in:
parent
1be944a466
commit
fa8d89327f
|
@ -506,6 +506,9 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM)
|
|||
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 @@ static SDValue PerformVDUPLANECombine(SDNode *N,
|
|||
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 @@ SDValue ARMTargetLowering::PerformDAGCombine(SDNode *N,
|
|||
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:
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
; RUN: llc < %s -mtriple=armv7-apple-ios | FileCheck %s
|
||||
|
||||
@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}
|
|
@ -0,0 +1,102 @@
|
|||
; RUN: llc < %s -mtriple=armv7-apple-ios | FileCheck %s
|
||||
|
||||
@in = global float 0x400921FA00000000, align 4
|
||||
@iin = global i32 -1023, align 4
|
||||
@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}
|
Loading…
Reference in New Issue