summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp')
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp31
1 files changed, 31 insertions, 0 deletions
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 75fb6559b9b..b8af674a1e2 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -19537,6 +19537,37 @@ SDValue DAGCombiner::SimplifyVBinOp(SDNode *N) {
}
}
+ // Make sure all but the first op are undef.
+ auto ConcatWithUndef = [](SDValue Concat) {
+ return Concat.getOpcode() == ISD::CONCAT_VECTORS &&
+ std::all_of(std::next(Concat->op_begin()), Concat->op_end(),
+ [](const SDValue &Op) {
+ return Op.isUndef();
+ });
+ };
+
+ // The following pattern is likely to emerge with vector reduction ops. Moving
+ // the binary operation ahead of the concat may allow using a narrower vector
+ // instruction that has better performance than the wide version of the op:
+ // VBinOp (concat X, undef), (concat Y, undef) --> concat (VBinOp X, Y), VecC
+ if (ConcatWithUndef(LHS) && ConcatWithUndef(RHS) &&
+ (LHS.hasOneUse() || RHS.hasOneUse())) {
+ SDValue X = LHS.getOperand(0);
+ SDValue Y = RHS.getOperand(0);
+ EVT NarrowVT = X.getValueType();
+ if (NarrowVT == Y.getValueType() &&
+ TLI.isOperationLegalOrCustomOrPromote(Opcode, NarrowVT)) {
+ // (binop undef, undef) may not return undef, so compute that result.
+ SDLoc DL(N);
+ SDValue VecC =
+ DAG.getNode(Opcode, DL, NarrowVT, DAG.getUNDEF(NarrowVT),
+ DAG.getUNDEF(NarrowVT));
+ SmallVector<SDValue, 4> Ops(LHS.getNumOperands(), VecC);
+ Ops[0] = DAG.getNode(Opcode, DL, NarrowVT, X, Y);
+ return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, Ops);
+ }
+ }
+
if (SDValue V = scalarizeBinOpOfSplats(N, DAG))
return V;
OpenPOWER on IntegriCloud