<div dir="ltr">AFAIK, there is no generic integer min/max pattern matching so far, but I agree that it would better if there were and if NVPTX were using the generic min/max nodes. See my last comment in the review.</div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Aug 28, 2015 at 8:10 AM, Tom Stellard <span dir="ltr"><<a href="mailto:tom@stellard.net" target="_blank">tom@stellard.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On Wed, Aug 26, 2015 at 11:22:02PM -0000, Bjarke Hammersholt Roune via llvm-commits wrote:<br>
> Author: broune<br>
> Date: Wed Aug 26 18:22:02 2015<br>
> New Revision: 246107<br>
><br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=246107&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=246107&view=rev</a><br>
> Log:<br>
> [NVPTX] Let NVPTX backend detect integer min and max patterns.<br>
><br>
> Summary:<br>
> Let NVPTX backend detect integer min and max patterns during isel and emit intrinsics that enable hardware support.<br>
><br>
<br>
</span>Now that there are integer min/max SDNodes nvptx should mark those as legal<br>
so it can use the generic patterns.<br>
<span class="HOEnZb"><font color="#888888"><br>
-Tom<br>
</font></span><div class="HOEnZb"><div class="h5"><br>
><br>
> Reviewers: jholewinski, meheff, jingyue<br>
><br>
> Subscribers: arsenm, llvm-commits, meheff, jingyue, eliben, jholewinski<br>
><br>
> Differential Revision: <a href="http://reviews.llvm.org/D12377" rel="noreferrer" target="_blank">http://reviews.llvm.org/D12377</a><br>
><br>
> Added:<br>
>     llvm/trunk/test/CodeGen/NVPTX/combine-min-max.ll<br>
> Modified:<br>
>     llvm/trunk/lib/Target/NVPTX/NVPTXISelLowering.cpp<br>
><br>
> Modified: llvm/trunk/lib/Target/NVPTX/NVPTXISelLowering.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/NVPTX/NVPTXISelLowering.cpp?rev=246107&r1=246106&r2=246107&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/NVPTX/NVPTXISelLowering.cpp?rev=246107&r1=246106&r2=246107&view=diff</a><br>
> ==============================================================================<br>
> --- llvm/trunk/lib/Target/NVPTX/NVPTXISelLowering.cpp (original)<br>
> +++ llvm/trunk/lib/Target/NVPTX/NVPTXISelLowering.cpp Wed Aug 26 18:22:02 2015<br>
> @@ -279,6 +279,7 @@ NVPTXTargetLowering::NVPTXTargetLowering<br>
>    setTargetDAGCombine(ISD::FADD);<br>
>    setTargetDAGCombine(ISD::MUL);<br>
>    setTargetDAGCombine(ISD::SHL);<br>
> +  setTargetDAGCombine(ISD::SELECT);<br>
><br>
>    // Now deduce the information based on the above mentioned<br>
>    // actions<br>
> @@ -4059,6 +4060,67 @@ static SDValue PerformANDCombine(SDNode<br>
>    return SDValue();<br>
>  }<br>
><br>
> +static SDValue PerformSELECTCombine(SDNode *N,<br>
> +                                    TargetLowering::DAGCombinerInfo &DCI) {<br>
> +  // Currently this detects patterns for integer min and max and<br>
> +  // lowers them to PTX-specific intrinsics that enable hardware<br>
> +  // support.<br>
> +<br>
> +  const SDValue Cond = N->getOperand(0);<br>
> +  if (Cond.getOpcode() != ISD::SETCC) return SDValue();<br>
> +<br>
> +  const SDValue LHS = Cond.getOperand(0);<br>
> +  const SDValue RHS = Cond.getOperand(1);<br>
> +  const SDValue True = N->getOperand(1);<br>
> +  const SDValue False = N->getOperand(2);<br>
> +  if (!(LHS == True && RHS == False) && !(LHS == False && RHS == True))<br>
> +    return SDValue();<br>
> +<br>
> +  const EVT VT = N->getValueType(0);<br>
> +  if (VT != MVT::i32 && VT != MVT::i64) return SDValue();<br>
> +<br>
> +  const ISD::CondCode CC = cast<CondCodeSDNode>(Cond.getOperand(2))->get();<br>
> +  SDValue Larger;  // The larger of LHS and RHS when condition is true.<br>
> +  switch (CC) {<br>
> +    case ISD::SETULT:<br>
> +    case ISD::SETULE:<br>
> +    case ISD::SETLT:<br>
> +    case ISD::SETLE:<br>
> +      Larger = RHS;<br>
> +      break;<br>
> +<br>
> +    case ISD::SETGT:<br>
> +    case ISD::SETGE:<br>
> +    case ISD::SETUGT:<br>
> +    case ISD::SETUGE:<br>
> +      Larger = LHS;<br>
> +      break;<br>
> +<br>
> +    default:<br>
> +      return SDValue();<br>
> +  }<br>
> +  const bool IsMax = (Larger == True);<br>
> +  const bool IsSigned = ISD::isSignedIntSetCC(CC);<br>
> +<br>
> +  unsigned IntrinsicId;<br>
> +  if (VT == MVT::i32) {<br>
> +    if (IsSigned)<br>
> +      IntrinsicId = IsMax ? Intrinsic::nvvm_max_i : Intrinsic::nvvm_min_i;<br>
> +    else<br>
> +      IntrinsicId = IsMax ? Intrinsic::nvvm_max_ui : Intrinsic::nvvm_min_ui;<br>
> +  } else {<br>
> +    assert(VT == MVT::i64);<br>
> +    if (IsSigned)<br>
> +      IntrinsicId = IsMax ? Intrinsic::nvvm_max_ll : Intrinsic::nvvm_min_ll;<br>
> +    else<br>
> +      IntrinsicId = IsMax ? Intrinsic::nvvm_max_ull : Intrinsic::nvvm_min_ull;<br>
> +  }<br>
> +<br>
> +  SDLoc DL(N);<br>
> +  return DCI.DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, VT,<br>
> +                         DCI.DAG.getConstant(IntrinsicId, DL, VT), LHS, RHS);<br>
> +}<br>
> +<br>
>  enum OperandSignedness {<br>
>    Signed = 0,<br>
>    Unsigned,<br>
> @@ -4240,6 +4302,8 @@ SDValue NVPTXTargetLowering::PerformDAGC<br>
>        return PerformSHLCombine(N, DCI, OptLevel);<br>
>      case ISD::AND:<br>
>        return PerformANDCombine(N, DCI);<br>
> +    case ISD::SELECT:<br>
> +      return PerformSELECTCombine(N, DCI);<br>
>    }<br>
>    return SDValue();<br>
>  }<br>
><br>
> Added: llvm/trunk/test/CodeGen/NVPTX/combine-min-max.ll<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/NVPTX/combine-min-max.ll?rev=246107&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/NVPTX/combine-min-max.ll?rev=246107&view=auto</a><br>
> ==============================================================================<br>
> --- llvm/trunk/test/CodeGen/NVPTX/combine-min-max.ll (added)<br>
> +++ llvm/trunk/test/CodeGen/NVPTX/combine-min-max.ll Wed Aug 26 18:22:02 2015<br>
> @@ -0,0 +1,307 @@<br>
> +; RUN: llc < %s -march=nvptx -mcpu=sm_20 -O2 | FileCheck %s<br>
> +<br>
> +; *************************************<br>
> +; * Cases with no min/max<br>
> +<br>
> +define i32 @ab_eq_i32(i32 %a, i32 %b) {<br>
> +; LABEL: @ab_slt_i32<br>
> +; CHECK-NOT: min<br>
> +; CHECK-NOT: max<br>
> +  %cmp = icmp eq i32 %a, %b<br>
> +  %sel = select i1 %cmp, i32 %a, i32 %b<br>
> +  ret i32 %sel<br>
> +}<br>
> +<br>
> +define i64 @ba_ne_i64(i64 %a, i64 %b) {<br>
> +; LABEL: @ab_ne_i64<br>
> +; CHECK-NOT: min<br>
> +; CHECK-NOT: max<br>
> +  %cmp = icmp ne i64 %a, %b<br>
> +  %sel = select i1 %cmp, i64 %b, i64 %a<br>
> +  ret i64 %sel<br>
> +}<br>
> +<br>
> +; PTX does have e.g. max.s16, but at least as of Kepler (sm_3x) that<br>
> +; gets compiled to SASS that converts the 16 bit parameters to 32 bit<br>
> +; before using a 32 bit instruction. That is probably not a win and<br>
> +; NVCC 7.5 does not emit 16 bit min/max either, presumably for that<br>
> +; reason.<br>
> +define i16 @ab_ugt_i16(i16 %a, i16 %b) {<br>
> +; LABEL: @ab_ugt_i16<br>
> +; CHECK-NOT: min<br>
> +; CHECK-NOT: max<br>
> +  %cmp = icmp ugt i16 %a, %b<br>
> +  %sel = select i1 %cmp, i16 %a, i16 %b<br>
> +  ret i16 %sel<br>
> +}<br>
> +<br>
> +<br>
> +; *************************************<br>
> +; * All variations with i32<br>
> +<br>
> +; *** ab, unsigned, i32<br>
> +define i32 @ab_ugt_i32(i32 %a, i32 %b) {<br>
> +; LABEL: @ab_ugt_i32<br>
> +; CHECK: max.u32<br>
> +  %cmp = icmp ugt i32 %a, %b<br>
> +  %sel = select i1 %cmp, i32 %a, i32 %b<br>
> +  ret i32 %sel<br>
> +}<br>
> +<br>
> +define i32 @ab_uge_i32(i32 %a, i32 %b) {<br>
> +; LABEL: @ab_uge_i32<br>
> +; CHECK: max.u32<br>
> +  %cmp = icmp uge i32 %a, %b<br>
> +  %sel = select i1 %cmp, i32 %a, i32 %b<br>
> +  ret i32 %sel<br>
> +}<br>
> +<br>
> +define i32 @ab_ult_i32(i32 %a, i32 %b) {<br>
> +; LABEL: @ab_ult_i32<br>
> +; CHECK: min.u32<br>
> +  %cmp = icmp ult i32 %a, %b<br>
> +  %sel = select i1 %cmp, i32 %a, i32 %b<br>
> +  ret i32 %sel<br>
> +}<br>
> +<br>
> +define i32 @ab_ule_i32(i32 %a, i32 %b) {<br>
> +; LABEL: @ab_ule_i32<br>
> +; CHECK: min.u32<br>
> +  %cmp = icmp ule i32 %a, %b<br>
> +  %sel = select i1 %cmp, i32 %a, i32 %b<br>
> +  ret i32 %sel<br>
> +}<br>
> +<br>
> +; *** ab, signed, i32<br>
> +define i32 @ab_sgt_i32(i32 %a, i32 %b) {<br>
> +; LABEL: @ab_ugt_i32<br>
> +; CHECK: max.s32<br>
> +  %cmp = icmp sgt i32 %a, %b<br>
> +  %sel = select i1 %cmp, i32 %a, i32 %b<br>
> +  ret i32 %sel<br>
> +}<br>
> +<br>
> +define i32 @ab_sge_i32(i32 %a, i32 %b) {<br>
> +; LABEL: @ab_sge_i32<br>
> +; CHECK: max.s32<br>
> +  %cmp = icmp sge i32 %a, %b<br>
> +  %sel = select i1 %cmp, i32 %a, i32 %b<br>
> +  ret i32 %sel<br>
> +}<br>
> +<br>
> +define i32 @ab_slt_i32(i32 %a, i32 %b) {<br>
> +; LABEL: @ab_slt_i32<br>
> +; CHECK: min.s32<br>
> +  %cmp = icmp slt i32 %a, %b<br>
> +  %sel = select i1 %cmp, i32 %a, i32 %b<br>
> +  ret i32 %sel<br>
> +}<br>
> +<br>
> +define i32 @ab_sle_i32(i32 %a, i32 %b) {<br>
> +; LABEL: @ab_sle_i32<br>
> +; CHECK: min.s32<br>
> +  %cmp = icmp sle i32 %a, %b<br>
> +  %sel = select i1 %cmp, i32 %a, i32 %b<br>
> +  ret i32 %sel<br>
> +}<br>
> +<br>
> +; *** ba, unsigned, i32<br>
> +define i32 @ba_ugt_i32(i32 %a, i32 %b) {<br>
> +; LABEL: @ba_ugt_i32<br>
> +; CHECK: min.u32<br>
> +  %cmp = icmp ugt i32 %a, %b<br>
> +  %sel = select i1 %cmp, i32 %b, i32 %a<br>
> +  ret i32 %sel<br>
> +}<br>
> +<br>
> +define i32 @ba_uge_i32(i32 %a, i32 %b) {<br>
> +; LABEL: @ba_uge_i32<br>
> +; CHECK: min.u32<br>
> +  %cmp = icmp uge i32 %a, %b<br>
> +  %sel = select i1 %cmp, i32 %b, i32 %a<br>
> +  ret i32 %sel<br>
> +}<br>
> +<br>
> +define i32 @ba_ult_i32(i32 %a, i32 %b) {<br>
> +; LABEL: @ba_ult_i32<br>
> +; CHECK: max.u32<br>
> +  %cmp = icmp ult i32 %a, %b<br>
> +  %sel = select i1 %cmp, i32 %b, i32 %a<br>
> +  ret i32 %sel<br>
> +}<br>
> +<br>
> +define i32 @ba_ule_i32(i32 %a, i32 %b) {<br>
> +; LABEL: @ba_ule_i32<br>
> +; CHECK: max.u32<br>
> +  %cmp = icmp ule i32 %a, %b<br>
> +  %sel = select i1 %cmp, i32 %b, i32 %a<br>
> +  ret i32 %sel<br>
> +}<br>
> +<br>
> +; *** ba, signed, i32<br>
> +define i32 @ba_sgt_i32(i32 %a, i32 %b) {<br>
> +; LBAEL: @ba_ugt_i32<br>
> +; CHECK: min.s32<br>
> +  %cmp = icmp sgt i32 %a, %b<br>
> +  %sel = select i1 %cmp, i32 %b, i32 %a<br>
> +  ret i32 %sel<br>
> +}<br>
> +<br>
> +define i32 @ba_sge_i32(i32 %a, i32 %b) {<br>
> +; LABEL: @ba_sge_i32<br>
> +; CHECK: min.s32<br>
> +  %cmp = icmp sge i32 %a, %b<br>
> +  %sel = select i1 %cmp, i32 %b, i32 %a<br>
> +  ret i32 %sel<br>
> +}<br>
> +<br>
> +define i32 @ba_slt_i32(i32 %a, i32 %b) {<br>
> +; LABEL: @ba_slt_i32<br>
> +; CHECK: max.s32<br>
> +  %cmp = icmp slt i32 %a, %b<br>
> +  %sel = select i1 %cmp, i32 %b, i32 %a<br>
> +  ret i32 %sel<br>
> +}<br>
> +<br>
> +define i32 @ba_sle_i32(i32 %a, i32 %b) {<br>
> +; LABEL: @ba_sle_i32<br>
> +; CHECK: max.s32<br>
> +  %cmp = icmp sle i32 %a, %b<br>
> +  %sel = select i1 %cmp, i32 %b, i32 %a<br>
> +  ret i32 %sel<br>
> +}<br>
> +<br>
> +; *************************************<br>
> +; * All variations with i64<br>
> +<br>
> +; *** ab, unsigned, i64<br>
> +define i64 @ab_ugt_i64(i64 %a, i64 %b) {<br>
> +; LABEL: @ab_ugt_i64<br>
> +; CHECK: max.u64<br>
> +  %cmp = icmp ugt i64 %a, %b<br>
> +  %sel = select i1 %cmp, i64 %a, i64 %b<br>
> +  ret i64 %sel<br>
> +}<br>
> +<br>
> +define i64 @ab_uge_i64(i64 %a, i64 %b) {<br>
> +; LABEL: @ab_uge_i64<br>
> +; CHECK: max.u64<br>
> +  %cmp = icmp uge i64 %a, %b<br>
> +  %sel = select i1 %cmp, i64 %a, i64 %b<br>
> +  ret i64 %sel<br>
> +}<br>
> +<br>
> +define i64 @ab_ult_i64(i64 %a, i64 %b) {<br>
> +; LABEL: @ab_ult_i64<br>
> +; CHECK: min.u64<br>
> +  %cmp = icmp ult i64 %a, %b<br>
> +  %sel = select i1 %cmp, i64 %a, i64 %b<br>
> +  ret i64 %sel<br>
> +}<br>
> +<br>
> +define i64 @ab_ule_i64(i64 %a, i64 %b) {<br>
> +; LABEL: @ab_ule_i64<br>
> +; CHECK: min.u64<br>
> +  %cmp = icmp ule i64 %a, %b<br>
> +  %sel = select i1 %cmp, i64 %a, i64 %b<br>
> +  ret i64 %sel<br>
> +}<br>
> +<br>
> +; *** ab, signed, i64<br>
> +define i64 @ab_sgt_i64(i64 %a, i64 %b) {<br>
> +; LABEL: @ab_ugt_i64<br>
> +; CHECK: max.s64<br>
> +  %cmp = icmp sgt i64 %a, %b<br>
> +  %sel = select i1 %cmp, i64 %a, i64 %b<br>
> +  ret i64 %sel<br>
> +}<br>
> +<br>
> +define i64 @ab_sge_i64(i64 %a, i64 %b) {<br>
> +; LABEL: @ab_sge_i64<br>
> +; CHECK: max.s64<br>
> +  %cmp = icmp sge i64 %a, %b<br>
> +  %sel = select i1 %cmp, i64 %a, i64 %b<br>
> +  ret i64 %sel<br>
> +}<br>
> +<br>
> +define i64 @ab_slt_i64(i64 %a, i64 %b) {<br>
> +; LABEL: @ab_slt_i64<br>
> +; CHECK: min.s64<br>
> +  %cmp = icmp slt i64 %a, %b<br>
> +  %sel = select i1 %cmp, i64 %a, i64 %b<br>
> +  ret i64 %sel<br>
> +}<br>
> +<br>
> +define i64 @ab_sle_i64(i64 %a, i64 %b) {<br>
> +; LABEL: @ab_sle_i64<br>
> +; CHECK: min.s64<br>
> +  %cmp = icmp sle i64 %a, %b<br>
> +  %sel = select i1 %cmp, i64 %a, i64 %b<br>
> +  ret i64 %sel<br>
> +}<br>
> +<br>
> +; *** ba, unsigned, i64<br>
> +define i64 @ba_ugt_i64(i64 %a, i64 %b) {<br>
> +; LABEL: @ba_ugt_i64<br>
> +; CHECK: min.u64<br>
> +  %cmp = icmp ugt i64 %a, %b<br>
> +  %sel = select i1 %cmp, i64 %b, i64 %a<br>
> +  ret i64 %sel<br>
> +}<br>
> +<br>
> +define i64 @ba_uge_i64(i64 %a, i64 %b) {<br>
> +; LABEL: @ba_uge_i64<br>
> +; CHECK: min.u64<br>
> +  %cmp = icmp uge i64 %a, %b<br>
> +  %sel = select i1 %cmp, i64 %b, i64 %a<br>
> +  ret i64 %sel<br>
> +}<br>
> +<br>
> +define i64 @ba_ult_i64(i64 %a, i64 %b) {<br>
> +; LABEL: @ba_ult_i64<br>
> +; CHECK: max.u64<br>
> +  %cmp = icmp ult i64 %a, %b<br>
> +  %sel = select i1 %cmp, i64 %b, i64 %a<br>
> +  ret i64 %sel<br>
> +}<br>
> +<br>
> +define i64 @ba_ule_i64(i64 %a, i64 %b) {<br>
> +; LABEL: @ba_ule_i64<br>
> +; CHECK: max.u64<br>
> +  %cmp = icmp ule i64 %a, %b<br>
> +  %sel = select i1 %cmp, i64 %b, i64 %a<br>
> +  ret i64 %sel<br>
> +}<br>
> +<br>
> +; *** ba, signed, i64<br>
> +define i64 @ba_sgt_i64(i64 %a, i64 %b) {<br>
> +; LBAEL: @ba_ugt_i64<br>
> +; CHECK: min.s64<br>
> +  %cmp = icmp sgt i64 %a, %b<br>
> +  %sel = select i1 %cmp, i64 %b, i64 %a<br>
> +  ret i64 %sel<br>
> +}<br>
> +<br>
> +define i64 @ba_sge_i64(i64 %a, i64 %b) {<br>
> +; LABEL: @ba_sge_i64<br>
> +; CHECK: min.s64<br>
> +  %cmp = icmp sge i64 %a, %b<br>
> +  %sel = select i1 %cmp, i64 %b, i64 %a<br>
> +  ret i64 %sel<br>
> +}<br>
> +<br>
> +define i64 @ba_slt_i64(i64 %a, i64 %b) {<br>
> +; LABEL: @ba_slt_i64<br>
> +; CHECK: max.s64<br>
> +  %cmp = icmp slt i64 %a, %b<br>
> +  %sel = select i1 %cmp, i64 %b, i64 %a<br>
> +  ret i64 %sel<br>
> +}<br>
> +<br>
> +define i64 @ba_sle_i64(i64 %a, i64 %b) {<br>
> +; LABEL: @ba_sle_i64<br>
> +; CHECK: max.s64<br>
> +  %cmp = icmp sle i64 %a, %b<br>
> +  %sel = select i1 %cmp, i64 %b, i64 %a<br>
> +  ret i64 %sel<br>
> +}<br>
><br>
><br>
> _______________________________________________<br>
> llvm-commits mailing list<br>
> <a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
> <a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</div></div></blockquote></div><br></div>