[Hexagon] Generate vector min/max for HVX

llvm-svn: 369014
diff --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
index 7ddc33e..eaae3f2 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
@@ -2877,6 +2877,17 @@
   }
 }
 
+SDValue
+HexagonTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI)
+      const {
+  SDValue Op(N, 0);
+  if (isHvxOperation(Op)) {
+    if (SDValue V = PerformHvxDAGCombine(N, DCI))
+      return V;
+  }
+  return SDValue();
+}
+
 /// Returns relocation base for the given PIC jumptable.
 SDValue
 HexagonTargetLowering::getPICJumpTableRelocBase(SDValue Table,
diff --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.h b/llvm/lib/Target/Hexagon/HexagonISelLowering.h
index e922240..4bc49dd 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelLowering.h
+++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.h
@@ -223,6 +223,8 @@
                         const SmallVectorImpl<SDValue> &OutVals,
                         const SDLoc &dl, SelectionDAG &DAG) const override;
 
+    SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override;
+
     bool mayBeEmittedAsTailCall(const CallInst *CI) const override;
 
     unsigned getRegisterByName(const char* RegName, EVT VT,
@@ -301,7 +303,8 @@
         const AttributeList &FuncAttributes) const override;
 
     bool allowsMisalignedMemoryAccesses(EVT VT, unsigned AddrSpace,
-        unsigned Align, MachineMemOperand::Flags Flags, bool *Fast) const override;
+        unsigned Align, MachineMemOperand::Flags Flags, bool *Fast)
+        const override;
 
     /// Returns relocation base for the given PIC jumptable.
     SDValue getPICJumpTableRelocBase(SDValue Table, SelectionDAG &DAG)
@@ -458,6 +461,8 @@
 
     bool isHvxOperation(SDValue Op) const;
     SDValue LowerHvxOperation(SDValue Op, SelectionDAG &DAG) const;
+
+    SDValue PerformHvxDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const;
   };
 
 } // end namespace llvm
diff --git a/llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp b/llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp
index 345c657..bc8a995 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp
@@ -193,6 +193,8 @@
     setOperationAction(ISD::OR,                 BoolV, Legal);
     setOperationAction(ISD::XOR,                BoolV, Legal);
   }
+
+  setTargetDAGCombine(ISD::VSELECT);
 }
 
 SDValue
@@ -1580,6 +1582,28 @@
   llvm_unreachable("Unhandled HVX operation");
 }
 
+SDValue
+HexagonTargetLowering::PerformHvxDAGCombine(SDNode *N, DAGCombinerInfo &DCI)
+      const {
+  const SDLoc &dl(N);
+  SDValue Op(N, 0);
+
+  unsigned Opc = Op.getOpcode();
+  if (Opc == ISD::VSELECT) {
+    // (vselect (xor x, qtrue), v0, v1) -> (vselect x, v1, v0)
+    SDValue Cond = Op.getOperand(0);
+    if (Cond->getOpcode() == ISD::XOR) {
+      SDValue C0 = Cond.getOperand(0), C1 = Cond.getOperand(1);
+      if (C1->getOpcode() == HexagonISD::QTRUE) {
+        SDValue VSel = DCI.DAG.getNode(ISD::VSELECT, dl, ty(Op), C0,
+                                       Op.getOperand(2), Op.getOperand(1));
+        return VSel;
+      }
+    }
+  }
+  return SDValue();
+}
+
 bool
 HexagonTargetLowering::isHvxOperation(SDValue Op) const {
   // If the type of the result, or any operand type are HVX vector types,
diff --git a/llvm/lib/Target/Hexagon/HexagonPatternsHVX.td b/llvm/lib/Target/Hexagon/HexagonPatternsHVX.td
index a4cfca9..4f3d872 100644
--- a/llvm/lib/Target/Hexagon/HexagonPatternsHVX.td
+++ b/llvm/lib/Target/Hexagon/HexagonPatternsHVX.td
@@ -259,6 +259,31 @@
 class Vnot<ValueType VecTy>
   : PatFrag<(ops node:$Vs), (xor $Vs, Vneg1<VecTy>)>;
 
+multiclass VMinMax_pat<InstHexagon MinInst, InstHexagon MaxInst, PatFrag CmpOp,
+                       ValueType CmpType, PatFrag CmpPred> {
+  def: Pat<(vselect (CmpType (CmpOp CmpPred:$Vs, CmpPred:$Vt)),
+                             CmpPred:$Vt, CmpPred:$Vs),
+           (MinInst CmpPred:$Vs, CmpPred:$Vt)>;
+  def: Pat<(vselect (CmpType (CmpOp CmpPred:$Vs, CmpPred:$Vt)),
+                             CmpPred:$Vs, CmpPred:$Vt),
+           (MaxInst CmpPred:$Vs, CmpPred:$Vt)>;
+}
+
+let Predicates = [UseHVX] in {
+  let AddedComplexity = 220 in {
+    defm: VMinMax_pat<V6_vminb,  V6_vmaxb,   setgt,  VecQ8,  HVI8>;
+    defm: VMinMax_pat<V6_vminb,  V6_vmaxb,   setge,  VecQ8,  HVI8>;
+    defm: VMinMax_pat<V6_vminub, V6_vmaxub, setugt,  VecQ8,  HVI8>;
+    defm: VMinMax_pat<V6_vminub, V6_vmaxub, setuge,  VecQ8,  HVI8>;
+    defm: VMinMax_pat<V6_vminh,  V6_vmaxh,   setgt, VecQ16, HVI16>;
+    defm: VMinMax_pat<V6_vminh,  V6_vmaxh,   setge, VecQ16, HVI16>;
+    defm: VMinMax_pat<V6_vminuh, V6_vmaxuh, setugt, VecQ16, HVI16>;
+    defm: VMinMax_pat<V6_vminuh, V6_vmaxuh, setuge, VecQ16, HVI16>;
+    defm: VMinMax_pat<V6_vminw,  V6_vmaxw,   setgt, VecQ32, HVI32>;
+    defm: VMinMax_pat<V6_vminw,  V6_vmaxw,   setge, VecQ32, HVI32>;
+  }
+}
+
 let Predicates = [UseHVX] in {
   let AddedComplexity = 200 in {
     def: Pat<(Vnot<VecI8>   HVI8:$Vs), (V6_vnot HvxVR:$Vs)>;