Index: lib/Target/PowerPC/PPCISelDAGToDAG.cpp =================================================================== --- lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -3617,9 +3617,12 @@ } } else if (LHS.getValueType() == MVT::f32) { Opc = PPC::FCMPUS; - } else { - assert(LHS.getValueType() == MVT::f64 && "Unknown vt!"); + } else if (LHS.getValueType() == MVT::f64) { Opc = PPCSubTarget->hasVSX() ? PPC::XSCMPUDP : PPC::FCMPUD; + } else { + assert(LHS.getValueType() == MVT::f128 && "Unknown vt!"); + assert(PPCSubTarget->hasVSX() && "__float128 requires VSX"); + Opc = PPC::XSCMPUQP; } return SDValue(CurDAG->getMachineNode(Opc, dl, MVT::i32, LHS, RHS), 0); } @@ -4564,6 +4567,8 @@ SelectCCOp = PPC::SELECT_CC_VSFRC; else SelectCCOp = PPC::SELECT_CC_F8; + else if (N->getValueType(0) == MVT::f128) + SelectCCOp = PPC::SELECT_CC_F16; else if (PPCSubTarget->hasQPX() && N->getValueType(0) == MVT::v4f64) SelectCCOp = PPC::SELECT_CC_QFRC; else if (PPCSubTarget->hasQPX() && N->getValueType(0) == MVT::v4f32) Index: lib/Target/PowerPC/PPCISelLowering.cpp =================================================================== --- lib/Target/PowerPC/PPCISelLowering.cpp +++ lib/Target/PowerPC/PPCISelLowering.cpp @@ -808,6 +808,13 @@ setOperationAction(ISD::FP_EXTEND, MVT::f128, Legal); setLoadExtAction(ISD::EXTLOAD, MVT::f128, MVT::f64, Expand); setOperationAction(ISD::FMA, MVT::f128, Legal); + setCondCodeAction(ISD::SETULT, MVT::f128, Expand); + setCondCodeAction(ISD::SETUGT, MVT::f128, Expand); + setCondCodeAction(ISD::SETUEQ, MVT::f128, Expand); + setCondCodeAction(ISD::SETOGE, MVT::f128, Expand); + setCondCodeAction(ISD::SETOLE, MVT::f128, Expand); + setCondCodeAction(ISD::SETONE, MVT::f128, Expand); + setOperationAction(ISD::SELECT, MVT::f128, Expand); } } @@ -10155,6 +10162,7 @@ MI.getOpcode() == PPC::SELECT_CC_I8 || MI.getOpcode() == PPC::SELECT_CC_F4 || MI.getOpcode() == PPC::SELECT_CC_F8 || + MI.getOpcode() == PPC::SELECT_CC_F16 || MI.getOpcode() == PPC::SELECT_CC_QFRC || MI.getOpcode() == PPC::SELECT_CC_QSRC || MI.getOpcode() == PPC::SELECT_CC_QBRC || @@ -10166,6 +10174,7 @@ MI.getOpcode() == PPC::SELECT_I8 || MI.getOpcode() == PPC::SELECT_F4 || MI.getOpcode() == PPC::SELECT_F8 || + MI.getOpcode() == PPC::SELECT_F16 || MI.getOpcode() == PPC::SELECT_QFRC || MI.getOpcode() == PPC::SELECT_QSRC || MI.getOpcode() == PPC::SELECT_QBRC || @@ -10201,6 +10210,7 @@ if (MI.getOpcode() == PPC::SELECT_I4 || MI.getOpcode() == PPC::SELECT_I8 || MI.getOpcode() == PPC::SELECT_F4 || MI.getOpcode() == PPC::SELECT_F8 || + MI.getOpcode() == PPC::SELECT_F16 || MI.getOpcode() == PPC::SELECT_QFRC || MI.getOpcode() == PPC::SELECT_QSRC || MI.getOpcode() == PPC::SELECT_QBRC || Index: lib/Target/PowerPC/PPCInstrInfo.td =================================================================== --- lib/Target/PowerPC/PPCInstrInfo.td +++ lib/Target/PowerPC/PPCInstrInfo.td @@ -1209,6 +1209,9 @@ def SELECT_CC_F8 : Pseudo<(outs f8rc:$dst), (ins crrc:$cond, f8rc:$T, f8rc:$F, i32imm:$BROPC), "#SELECT_CC_F8", []>; + def SELECT_CC_F16 : Pseudo<(outs vrrc:$dst), (ins crrc:$cond, vrrc:$T, vrrc:$F, + i32imm:$BROPC), "#SELECT_CC_F16", + []>; def SELECT_CC_VRRC: Pseudo<(outs vrrc:$dst), (ins crrc:$cond, vrrc:$T, vrrc:$F, i32imm:$BROPC), "#SELECT_CC_VRRC", []>; @@ -1227,6 +1230,9 @@ def SELECT_F8 : Pseudo<(outs f8rc:$dst), (ins crbitrc:$cond, f8rc:$T, f8rc:$F), "#SELECT_F8", [(set f64:$dst, (select i1:$cond, f64:$T, f64:$F))]>; + def SELECT_F16 : Pseudo<(outs vrrc:$dst), (ins crbitrc:$cond, + vrrc:$T, vrrc:$F), "#SELECT_F16", + [(set f128:$dst, (select i1:$cond, f128:$T, f128:$F))]>; def SELECT_VRRC: Pseudo<(outs vrrc:$dst), (ins crbitrc:$cond, vrrc:$T, vrrc:$F), "#SELECT_VRRC", [(set v4i32:$dst, @@ -3615,6 +3621,37 @@ defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETO)), (EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_un)>; +// SETCC for f128. +def : Pat<(i1 (setcc f128:$s1, f128:$s2, SETOLT)), + (EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_lt)>; +def : Pat<(i1 (setcc f128:$s1, f128:$s2, SETLT)), + (EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_lt)>; +def : Pat<(i1 (setcc f128:$s1, f128:$s2, SETOGT)), + (EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_gt)>; +def : Pat<(i1 (setcc f128:$s1, f128:$s2, SETGT)), + (EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_gt)>; +def : Pat<(i1 (setcc f128:$s1, f128:$s2, SETOEQ)), + (EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_eq)>; +def : Pat<(i1 (setcc f128:$s1, f128:$s2, SETEQ)), + (EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_eq)>; +def : Pat<(i1 (setcc f128:$s1, f128:$s2, SETUO)), + (EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_un)>; + +defm : CRNotPat<(i1 (setcc f128:$s1, f128:$s2, SETUGE)), + (EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_lt)>; +defm : CRNotPat<(i1 (setcc f128:$s1, f128:$s2, SETGE)), + (EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_lt)>; +defm : CRNotPat<(i1 (setcc f128:$s1, f128:$s2, SETULE)), + (EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_gt)>; +defm : CRNotPat<(i1 (setcc f128:$s1, f128:$s2, SETLE)), + (EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_gt)>; +defm : CRNotPat<(i1 (setcc f128:$s1, f128:$s2, SETUNE)), + (EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_eq)>; +defm : CRNotPat<(i1 (setcc f128:$s1, f128:$s2, SETNE)), + (EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_eq)>; +defm : CRNotPat<(i1 (setcc f128:$s1, f128:$s2, SETO)), + (EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_un)>; + // match select on i1 variables: def : Pat<(i1 (select i1:$cond, i1:$tval, i1:$fval)), (CROR (CRAND $cond , $tval), @@ -3739,6 +3776,27 @@ def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETNE)), (SELECT_F8 (CRXOR $lhs, $rhs), $tval, $fval)>; +def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETLT)), + (SELECT_F16 (CRANDC $lhs, $rhs), $tval, $fval)>; +def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETULT)), + (SELECT_F16 (CRANDC $rhs, $lhs), $tval, $fval)>; +def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETLE)), + (SELECT_F16 (CRORC $lhs, $rhs), $tval, $fval)>; +def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETULE)), + (SELECT_F16 (CRORC $rhs, $lhs), $tval, $fval)>; +def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETEQ)), + (SELECT_F16 (CREQV $lhs, $rhs), $tval, $fval)>; +def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETGE)), + (SELECT_F16 (CRORC $rhs, $lhs), $tval, $fval)>; +def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETUGE)), + (SELECT_F16 (CRORC $lhs, $rhs), $tval, $fval)>; +def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETGT)), + (SELECT_F16 (CRANDC $rhs, $lhs), $tval, $fval)>; +def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETUGT)), + (SELECT_F16 (CRANDC $lhs, $rhs), $tval, $fval)>; +def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETNE)), + (SELECT_F16 (CRXOR $lhs, $rhs), $tval, $fval)>; + def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETLT)), (SELECT_VRRC (CRANDC $lhs, $rhs), $tval, $fval)>; def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETULT)), Index: test/CodeGen/PowerPC/f128-compare.ll =================================================================== --- /dev/null +++ test/CodeGen/PowerPC/f128-compare.ll @@ -0,0 +1,225 @@ +; RUN: llc -mcpu=pwr9 -mtriple=powerpc64le-unknown-unknown \ +; RUN: -enable-ppc-quad-precision -verify-machineinstrs < %s | FileCheck %s + +@a_qp = common global fp128 0xL00000000000000000000000000000000, align 16 +@b_qp = common global fp128 0xL00000000000000000000000000000000, align 16 + +; Function Attrs: noinline nounwind optnone +define signext i32 @greater_qp() { +entry: + %0 = load fp128, fp128* @a_qp, align 16 + %1 = load fp128, fp128* @b_qp, align 16 + %cmp = fcmp ogt fp128 %0, %1 + %conv = zext i1 %cmp to i32 + ret i32 %conv +; CHECK-LABEL: greater_qp +; CHECK: xscmpuqp +; CHECK: isel {{[0-9]+}}, {{[0-9]+}}, {{[0-9]+}}, 1 +; CHECK: blr +} + +; Function Attrs: noinline nounwind optnone +define signext i32 @less_qp() { +entry: + %0 = load fp128, fp128* @a_qp, align 16 + %1 = load fp128, fp128* @b_qp, align 16 + %cmp = fcmp olt fp128 %0, %1 + %conv = zext i1 %cmp to i32 + ret i32 %conv +; CHECK-LABEL: less_qp +; CHECK: xscmpuqp +; CHECK: isel {{[0-9]+}}, {{[0-9]+}}, {{[0-9]+}}, 0 +; CHECK: blr +} + +; Function Attrs: noinline nounwind optnone +define signext i32 @greater_eq_qp() { +entry: + %0 = load fp128, fp128* @a_qp, align 16 + %1 = load fp128, fp128* @b_qp, align 16 + %cmp = fcmp oge fp128 %0, %1 + %conv = zext i1 %cmp to i32 + ret i32 %conv +; CHECK-LABEL: greater_eq_qp +; CHECK: xscmpuqp +; CHECK: cror [[REG:[0-9]+]], {{[0-9]+}}, 0 +; CHECK: isel {{[0-9]+}}, {{[0-9]+}}, {{[0-9]+}}, [[REG]] +; CHECK: blr +} + +; Function Attrs: noinline nounwind optnone +define signext i32 @less_eq_qp() { +entry: + %0 = load fp128, fp128* @a_qp, align 16 + %1 = load fp128, fp128* @b_qp, align 16 + %cmp = fcmp ole fp128 %0, %1 + %conv = zext i1 %cmp to i32 + ret i32 %conv +; CHECK-LABEL: less_eq_qp +; CHECK: xscmpuqp +; CHECK: cror [[REG:[0-9]+]], {{[0-9]+}}, 1 +; CHECK: isel {{[0-9]+}}, {{[0-9]+}}, {{[0-9]+}}, [[REG]] +; CHECK: blr +} + +; Function Attrs: noinline nounwind optnone +define signext i32 @equal_qp() { +entry: + %0 = load fp128, fp128* @a_qp, align 16 + %1 = load fp128, fp128* @b_qp, align 16 + %cmp = fcmp oeq fp128 %0, %1 + %conv = zext i1 %cmp to i32 + ret i32 %conv +; CHECK-LABEL: equal_qp +; CHECK: xscmpuqp +; CHECK: isel {{[0-9]+}}, {{[0-9]+}}, {{[0-9]+}}, 2 +; CHECK: blr +} + +; Function Attrs: noinline nounwind optnone +define signext i32 @not_greater_qp() { +entry: + %0 = load fp128, fp128* @a_qp, align 16 + %1 = load fp128, fp128* @b_qp, align 16 + %cmp = fcmp ogt fp128 %0, %1 + %lnot = xor i1 %cmp, true + %lnot.ext = zext i1 %lnot to i32 + ret i32 %lnot.ext +; CHECK-LABEL: not_greater_qp +; CHECK: xscmpuqp +; CHECK: isel {{[0-9]+}}, {{[0-9]+}}, {{[0-9]+}}, 1 +; CHECK: blr +} + +; Function Attrs: noinline nounwind optnone +define signext i32 @not_less_qp() { +entry: + %0 = load fp128, fp128* @a_qp, align 16 + %1 = load fp128, fp128* @b_qp, align 16 + %cmp = fcmp olt fp128 %0, %1 + %lnot = xor i1 %cmp, true + %lnot.ext = zext i1 %lnot to i32 + ret i32 %lnot.ext +; CHECK-LABEL: not_less_qp +; CHECK: xscmpuqp +; CHECK: isel {{[0-9]+}}, {{[0-9]+}}, {{[0-9]+}}, 0 +; CHECK: blr +} + +; Function Attrs: noinline nounwind optnone +define signext i32 @not_greater_eq_qp() { +entry: + %0 = load fp128, fp128* @a_qp, align 16 + %1 = load fp128, fp128* @b_qp, align 16 + %cmp = fcmp oge fp128 %0, %1 + %lnot = xor i1 %cmp, true + %lnot.ext = zext i1 %lnot to i32 + ret i32 %lnot.ext +; CHECK-LABEL: not_greater_eq_qp +; CHECK: xscmpuqp +; CHECK: crnor [[REG:[0-9]+]], 0, {{[0-9]+}} +; CHECK: isel {{[0-9]+}}, {{[0-9]+}}, {{[0-9]+}}, [[REG]] +; CHECK: blr +} + +; Function Attrs: noinline nounwind optnone +define signext i32 @not_less_eq_qp() { +entry: + %0 = load fp128, fp128* @a_qp, align 16 + %1 = load fp128, fp128* @b_qp, align 16 + %cmp = fcmp ole fp128 %0, %1 + %lnot = xor i1 %cmp, true + %lnot.ext = zext i1 %lnot to i32 + ret i32 %lnot.ext +; CHECK-LABEL: not_less_eq_qp +; CHECK: xscmpuqp +; CHECK: crnor [[REG:[0-9]+]], 1, {{[0-9]+}} +; CHECK: isel {{[0-9]+}}, {{[0-9]+}}, {{[0-9]+}}, [[REG]] +; CHECK: blr +} + +; Function Attrs: noinline nounwind optnone +define signext i32 @not_equal_qp() { +entry: + %0 = load fp128, fp128* @a_qp, align 16 + %1 = load fp128, fp128* @b_qp, align 16 + %cmp = fcmp une fp128 %0, %1 + %conv = zext i1 %cmp to i32 + ret i32 %conv +; CHECK-LABEL: not_equal_qp +; CHECK: xscmpuqp +; CHECK: isel {{[0-9]+}}, {{[0-9]+}}, {{[0-9]+}}, 2 +; CHECK: blr +} + +; Function Attrs: norecurse nounwind readonly +define fp128 @greater_sel_qp() { +entry: + %0 = load fp128, fp128* @a_qp, align 16 + %1 = load fp128, fp128* @b_qp, align 16 + %cmp = fcmp ogt fp128 %0, %1 + %cond = select i1 %cmp, fp128 %0, fp128 %1 + ret fp128 %cond +; CHECK-LABEL: greater_sel_qp +; CHECK: xscmpuqp [[REG:[0-9]+]] +; CHECK: bgt [[REG]] +; CHECK: blr +} + +; Function Attrs: noinline nounwind optnone +define fp128 @less_sel_qp() { +entry: + %0 = load fp128, fp128* @a_qp, align 16 + %1 = load fp128, fp128* @b_qp, align 16 + %cmp = fcmp olt fp128 %0, %1 + %cond = select i1 %cmp, fp128 %0, fp128 %1 + ret fp128 %cond +; CHECK-LABEL: less_sel_qp +; CHECK: xscmpuqp [[REG:[0-9]+]] +; CHECK: blt [[REG]] +; CHECK: blr +} + +; Function Attrs: noinline nounwind optnone +define fp128 @greater_eq_sel_qp() { +entry: + %0 = load fp128, fp128* @a_qp, align 16 + %1 = load fp128, fp128* @b_qp, align 16 + %cmp = fcmp oge fp128 %0, %1 + %cond = select i1 %cmp, fp128 %0, fp128 %1 + ret fp128 %cond +; CHECK-LABEL: greater_eq_sel_qp +; CHECK: xscmpuqp +; CHECK: crnor [[REG:[0-9]+]], {{[0-9]+}}, 0 +; CHECK: bc {{[0-9]+}}, [[REG]] +; CHECK: blr +} + +; Function Attrs: noinline nounwind optnone +define fp128 @less_eq_sel_qp() { +entry: + %0 = load fp128, fp128* @a_qp, align 16 + %1 = load fp128, fp128* @b_qp, align 16 + %cmp = fcmp ole fp128 %0, %1 + %cond = select i1 %cmp, fp128 %0, fp128 %1 + ret fp128 %cond +; CHECK-LABEL: less_eq_sel_qp +; CHECK: xscmpuqp +; CHECK: crnor [[REG:[0-9]+]], {{[0-9]+}}, 1 +; CHECK: bc {{[0-9]+}}, [[REG]] +; CHECK: blr +} + +; Function Attrs: noinline nounwind optnone +define fp128 @equal_sel_qp() { +entry: + %0 = load fp128, fp128* @a_qp, align 16 + %1 = load fp128, fp128* @b_qp, align 16 + %cmp = fcmp oeq fp128 %0, %1 + %cond = select i1 %cmp, fp128 %0, fp128 %1 + ret fp128 %cond +; CHECK-LABEL: equal_sel_qp +; CHECK: xscmpuqp [[REG:[0-9]+]] +; CHECK: beq [[REG]] +; CHECK: blr +}