Index: llvm/trunk/lib/Target/PowerPC/PPCISelLowering.cpp =================================================================== --- llvm/trunk/lib/Target/PowerPC/PPCISelLowering.cpp +++ llvm/trunk/lib/Target/PowerPC/PPCISelLowering.cpp @@ -6930,6 +6930,11 @@ SDValue PPCTargetLowering::LowerFP_TO_INT(SDValue Op, SelectionDAG &DAG, const SDLoc &dl) const { + + // FP to INT conversions are legal for f128. + if (EnableQuadPrecision && (Op->getOperand(0).getValueType() == MVT::f128)) + return Op; + // Expand ppcf128 to i32 by hand for the benefit of llvm-gcc bootstrap on // PPC (the libcall is not available). if (Op.getOperand(0).getValueType() == MVT::ppcf128) { Index: llvm/trunk/lib/Target/PowerPC/PPCInstrVSX.td =================================================================== --- llvm/trunk/lib/Target/PowerPC/PPCInstrVSX.td +++ llvm/trunk/lib/Target/PowerPC/PPCInstrVSX.td @@ -2530,7 +2530,7 @@ def XSCVQPUDZ : X_VT5_XO5_VB5<63, 17, 836, "xscvqpudz", []>; def XSCVQPUWZ : X_VT5_XO5_VB5<63, 1, 836, "xscvqpuwz", []>; - // Convert (Un)Signed DWord -> QP + // Convert (Un)Signed DWord -> QP. def XSCVSDQP : X_VT5_XO5_VB5_TyVB<63, 10, 836, "xscvsdqp", vfrc, []>; def : Pat<(f128 (sint_to_fp i64:$src)), (f128 (XSCVSDQP (COPY_TO_REGCLASS $src, VFRC)))>; @@ -2538,7 +2538,7 @@ def : Pat<(f128 (uint_to_fp i64:$src)), (f128 (XSCVUDQP (COPY_TO_REGCLASS $src, VFRC)))>; - // Convert (Un)Signed Word -> QP + // Convert (Un)Signed Word -> QP. def : Pat<(f128 (sint_to_fp i32:$src)), (f128 (XSCVSDQP (MTVSRWA $src)))>; def : Pat<(f128 (sint_to_fp (i32 (load xoaddr:$src)))), @@ -3170,9 +3170,21 @@ def : Pat<(f128 (uint_to_fp ScalarLoads.ZELi8)), (f128 (XSCVUDQP (LXSIBZX xoaddr:$src)))>; + // Truncate & Convert QP -> (Un)Signed (D)Word. + def : Pat<(i64 (fp_to_sint f128:$src)), (i64 (MFVRD (XSCVQPSDZ $src)))>; + def : Pat<(i64 (fp_to_uint f128:$src)), (i64 (MFVRD (XSCVQPUDZ $src)))>; + // Instructions for fptosint (i64,i16,i8) feeding a store. // The 8-byte version is repeated here due to availability of D-Form STXSD. def : Pat<(PPCstore_scal_int_from_vsr + (f64 (PPCcv_fp_to_sint_in_vsr f128:$src)), xaddr:$dst, 8), + (STXSDX (COPY_TO_REGCLASS (XSCVQPSDZ f128:$src), VFRC), + xaddr:$dst)>; + def : Pat<(PPCstore_scal_int_from_vsr + (f64 (PPCcv_fp_to_sint_in_vsr f128:$src)), ixaddr:$dst, 8), + (STXSD (COPY_TO_REGCLASS (XSCVQPSDZ f128:$src), VFRC), + ixaddr:$dst)>; + def : Pat<(PPCstore_scal_int_from_vsr (f64 (PPCcv_fp_to_sint_in_vsr f64:$src)), xaddr:$dst, 8), (STXSDX (XSCVDPSXDS f64:$src), xaddr:$dst)>; def : Pat<(PPCstore_scal_int_from_vsr @@ -3187,6 +3199,14 @@ // Instructions for fptouint (i64,i16,i8) feeding a store. def : Pat<(PPCstore_scal_int_from_vsr + (f64 (PPCcv_fp_to_uint_in_vsr f128:$src)), xaddr:$dst, 8), + (STXSDX (COPY_TO_REGCLASS (XSCVQPUDZ f128:$src), VFRC), + xaddr:$dst)>; + def : Pat<(PPCstore_scal_int_from_vsr + (f64 (PPCcv_fp_to_uint_in_vsr f128:$src)), ixaddr:$dst, 8), + (STXSD (COPY_TO_REGCLASS (XSCVQPUDZ f128:$src), VFRC), + ixaddr:$dst)>; + def : Pat<(PPCstore_scal_int_from_vsr (f64 (PPCcv_fp_to_uint_in_vsr f64:$src)), xaddr:$dst, 8), (STXSDX (XSCVDPUXDS f64:$src), xaddr:$dst)>; def : Pat<(PPCstore_scal_int_from_vsr Index: llvm/trunk/test/CodeGen/PowerPC/f128-truncateNconv.ll =================================================================== --- llvm/trunk/test/CodeGen/PowerPC/f128-truncateNconv.ll +++ llvm/trunk/test/CodeGen/PowerPC/f128-truncateNconv.ll @@ -0,0 +1,195 @@ +; RUN: llc -mcpu=pwr9 -mtriple=powerpc64le-unknown-unknown \ +; RUN: -verify-machineinstrs -enable-ppc-quad-precision \ +; RUN: -ppc-vsr-nums-as-vr < %s | FileCheck %s + +@f128Array = global [4 x fp128] [fp128 0xL00000000000000004004C00000000000, + fp128 0xLF000000000000000400808AB851EB851, + fp128 0xL5000000000000000400E0C26324C8366, + fp128 0xL8000000000000000400A24E2E147AE14], + align 16 + +; Function Attrs: norecurse nounwind readonly +define i64 @qpConv2sdw(fp128* nocapture readonly %a) { +entry: + %0 = load fp128, fp128* %a, align 16 + %conv = fptosi fp128 %0 to i64 + ret i64 %conv + +; CHECK-LABEL: qpConv2sdw +; CHECK: lxv [[REG:[0-9]+]], 0(3) +; CHECK-NEXT: xscvqpsdz [[CONV:[0-9]+]], [[REG]] +; CHECK-NEXT: mfvsrd 3, [[CONV]] +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind +define void @qpConv2sdw_02(i64* nocapture %res) local_unnamed_addr #1 { +entry: + %0 = load fp128, fp128* getelementptr inbounds + ([4 x fp128], [4 x fp128]* @f128Array, i64 0, + i64 2), align 16 + %conv = fptosi fp128 %0 to i64 + store i64 %conv, i64* %res, align 8 + ret void + +; CHECK-LABEL: qpConv2sdw_02 +; CHECK: addis [[REG0:[0-9]+]], 2, .LC0@toc@ha +; CHECK: ld [[REG0]], .LC0@toc@l([[REG0]]) +; CHECK: lxv [[REG:[0-9]+]], 32([[REG0]]) +; CHECK-NEXT: xscvqpsdz [[CONV:[0-9]+]], [[REG]] +; CHECK-NEXT: stxsd [[CONV]], 0(3) +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readonly +define i64 @qpConv2sdw_03(fp128* nocapture readonly %a) { +entry: + %0 = load fp128, fp128* %a, align 16 + %1 = load fp128, fp128* getelementptr inbounds + ([4 x fp128], [4 x fp128]* @f128Array, i64 0, + i64 1), align 16 + %add = fadd fp128 %0, %1 + %conv = fptosi fp128 %add to i64 + ret i64 %conv + +; CHECK-LABEL: qpConv2sdw_03 +; CHECK: addis [[REG0:[0-9]+]], 2, .LC0@toc@ha +; CHECK-DAG: ld [[REG0]], .LC0@toc@l([[REG0]]) +; CHECK-DAG: lxv [[REG1:[0-9]+]], 16([[REG0]]) +; CHECK-DAG: lxv [[REG:[0-9]+]], 0(3) +; CHECK: xsaddqp [[REG]], [[REG]], [[REG1]] +; CHECK-NEXT: xscvqpsdz [[CONV:[0-9]+]], [[REG]] +; CHECK-NEXT: mfvsrd 3, [[CONV]] +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind +define void @qpConv2sdw_04(fp128* nocapture readonly %a, + fp128* nocapture readonly %b, i64* nocapture %res) { +entry: + %0 = load fp128, fp128* %a, align 16 + %1 = load fp128, fp128* %b, align 16 + %add = fadd fp128 %0, %1 + %conv = fptosi fp128 %add to i64 + store i64 %conv, i64* %res, align 8 + ret void + +; CHECK-LABEL: qpConv2sdw_04 +; CHECK-DAG: lxv [[REG1:[0-9]+]], 0(4) +; CHECK-DAG: lxv [[REG:[0-9]+]], 0(3) +; CHECK: xsaddqp [[REG]], [[REG]], [[REG1]] +; CHECK-NEXT: xscvqpsdz [[CONV:[0-9]+]], [[REG]] +; CHECK-NEXT: stxsd [[CONV]], 0(5) +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind +define void @qpConv2sdw_testXForm(i64* nocapture %res, i32 signext %idx) { +entry: + %0 = load fp128, fp128* getelementptr inbounds + ([4 x fp128], [4 x fp128]* @f128Array, + i64 0, i64 2), align 16 + %conv = fptosi fp128 %0 to i64 + %idxprom = sext i32 %idx to i64 + %arrayidx = getelementptr inbounds i64, i64* %res, i64 %idxprom + store i64 %conv, i64* %arrayidx, align 8 + ret void + +; CHECK-LABEL: qpConv2sdw_testXForm +; CHECK: xscvqpsdz [[CONV:[0-9]+]], +; CHECK-NEXT: stxsdx [[CONV]], 3, 4 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readonly +define i64 @qpConv2udw(fp128* nocapture readonly %a) { +entry: + %0 = load fp128, fp128* %a, align 16 + %conv = fptoui fp128 %0 to i64 + ret i64 %conv + +; CHECK-LABEL: qpConv2udw +; CHECK: lxv [[REG:[0-9]+]], 0(3) +; CHECK-NEXT: xscvqpudz [[CONV:[0-9]+]], [[REG]] +; CHECK-NEXT: mfvsrd 3, [[CONV]] +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind +define void @qpConv2udw_02(i64* nocapture %res) { +entry: + %0 = load fp128, fp128* getelementptr inbounds + ([4 x fp128], [4 x fp128]* @f128Array, i64 0, + i64 2), align 16 + %conv = fptoui fp128 %0 to i64 + store i64 %conv, i64* %res, align 8 + ret void + +; CHECK-LABEL: qpConv2udw_02 +; CHECK: addis [[REG0:[0-9]+]], 2, .LC0@toc@ha +; CHECK: ld [[REG0]], .LC0@toc@l([[REG0]]) +; CHECK: lxv [[REG:[0-9]+]], 32([[REG0]]) +; CHECK-NEXT: xscvqpudz [[CONV:[0-9]+]], [[REG]] +; CHECK-NEXT: stxsd [[CONV]], 0(3) +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readonly +define i64 @qpConv2udw_03(fp128* nocapture readonly %a) { +entry: + %0 = load fp128, fp128* %a, align 16 + %1 = load fp128, fp128* getelementptr inbounds + ([4 x fp128], [4 x fp128]* @f128Array, i64 0, + i64 1), align 16 + %add = fadd fp128 %0, %1 + %conv = fptoui fp128 %add to i64 + ret i64 %conv + +; CHECK-LABEL: qpConv2udw_03 +; CHECK: addis [[REG0:[0-9]+]], 2, .LC0@toc@ha +; CHECK-DAG: ld [[REG0]], .LC0@toc@l([[REG0]]) +; CHECK-DAG: lxv [[REG1:[0-9]+]], 16([[REG0]]) +; CHECK-DAG: lxv [[REG:[0-9]+]], 0(3) +; CHECK: xsaddqp [[REG]], [[REG]], [[REG1]] +; CHECK-NEXT: xscvqpudz [[CONV:[0-9]+]], [[REG]] +; CHECK-NEXT: mfvsrd 3, [[CONV]] +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind +define void @qpConv2udw_04(fp128* nocapture readonly %a, + fp128* nocapture readonly %b, i64* nocapture %res) { +entry: + %0 = load fp128, fp128* %a, align 16 + %1 = load fp128, fp128* %b, align 16 + %add = fadd fp128 %0, %1 + %conv = fptoui fp128 %add to i64 + store i64 %conv, i64* %res, align 8 + ret void + +; CHECK-LABEL: qpConv2udw_04 +; CHECK-DAG: lxv [[REG1:[0-9]+]], 0(4) +; CHECK-DAG: lxv [[REG:[0-9]+]], 0(3) +; CHECK: xsaddqp [[REG]], [[REG]], [[REG1]] +; CHECK-NEXT: xscvqpudz [[CONV:[0-9]+]], [[REG]] +; CHECK-NEXT: stxsd [[CONV]], 0(5) +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind +define void @qpConv2udw_testXForm(i64* nocapture %res, i32 signext %idx) { +entry: + %0 = load fp128, fp128* getelementptr inbounds + ([4 x fp128], [4 x fp128]* @f128Array, + i64 0, i64 0), align 16 + %conv = fptoui fp128 %0 to i64 + %idxprom = sext i32 %idx to i64 + %arrayidx = getelementptr inbounds i64, i64* %res, i64 %idxprom + store i64 %conv, i64* %arrayidx, align 8 + ret void + +; CHECK-LABEL: qpConv2udw_testXForm +; CHECK: xscvqpudz [[CONV:[0-9]+]], +; CHECK-NEXT: stxsdx [[CONV]], 3, 4 +; CHECK-NEXT: blr +}