return {};
}
+static Instruction *foldSelectShuffleWith1Binop(ShuffleVectorInst &Shuf) {
+ assert(Shuf.isSelect() && "Must have select-equivalent shuffle");
+
+ // Are we shuffling together some value and that same value after it has been
+ // modified by a binop with a constant?
+ Value *Op0 = Shuf.getOperand(0), *Op1 = Shuf.getOperand(1);
+ Constant *C;
+ bool Op0IsBinop;
+ if (match(Op0, m_BinOp(m_Specific(Op1), m_Constant(C))))
+ Op0IsBinop = true;
+ else if (match(Op1, m_BinOp(m_Specific(Op0), m_Constant(C))))
+ Op0IsBinop = false;
+ else
+ return nullptr;
+
+ auto *BO = cast<BinaryOperator>(Op0IsBinop ? Op0 : Op1);
+ Value *X = Op0IsBinop ? Op1 : Op0;
+ // TODO: Allow div/rem by accounting for potential UB due to undef elements.
+ if (BO->isIntDivRem())
+ return nullptr;
+
+ // The identity constant for a binop leaves a variable operand unchanged. For
+ // a vector, this is a splat of something like 0, -1, or 1.
+ // If there's no identity constant for this binop, we're done.
+ BinaryOperator::BinaryOps BOpcode = BO->getOpcode();
+ Constant *IdC = ConstantExpr::getBinOpIdentity(BOpcode, Shuf.getType());
+ if (!IdC)
+ return nullptr;
+
+ // Shuffle identity constants into the lanes that return the original value.
+ // Example: shuf (mul X, {-1,-2,-3,-4}), X, {0,5,6,3} --> mul X, {-1,1,1,-4}
+ // Example: shuf X, (add X, {-1,-2,-3,-4}), {0,1,6,7} --> add X, {0,0,-3,-4}
+ // The existing binop constant vector remains in the same operand position.
+ Constant *Mask = Shuf.getMask();
+ Constant *NewC = Op0IsBinop ? ConstantExpr::getShuffleVector(C, IdC, Mask) :
+ ConstantExpr::getShuffleVector(IdC, C, Mask);
+
+ // shuf (bop X, C), X, M --> bop X, C'
+ // shuf X, (bop X, C), M --> bop X, C'
+ Instruction *NewBO = BinaryOperator::Create(BOpcode, X, NewC);
+ NewBO->copyIRFlags(BO);
+ return NewBO;
+}
+
/// Try to fold shuffles that are the equivalent of a vector select.
static Instruction *foldSelectShuffle(ShuffleVectorInst &Shuf,
InstCombiner::BuilderTy &Builder,
if (!Shuf.isSelect())
return nullptr;
+ if (Instruction *I = foldSelectShuffleWith1Binop(Shuf))
+ return I;
+
BinaryOperator *B0, *B1;
if (!match(Shuf.getOperand(0), m_BinOp(B0)) ||
!match(Shuf.getOperand(1), m_BinOp(B1)))
define <4 x i32> @add(<4 x i32> %v) {
; CHECK-LABEL: @add(
-; CHECK-NEXT: [[B:%.*]] = add <4 x i32> [[V:%.*]], <i32 11, i32 undef, i32 13, i32 undef>
-; CHECK-NEXT: [[S:%.*]] = shufflevector <4 x i32> [[B]], <4 x i32> [[V]], <4 x i32> <i32 0, i32 5, i32 2, i32 7>
+; CHECK-NEXT: [[S:%.*]] = add <4 x i32> [[V:%.*]], <i32 11, i32 0, i32 13, i32 0>
; CHECK-NEXT: ret <4 x i32> [[S]]
;
%b = add <4 x i32> %v, <i32 11, i32 12, i32 13, i32 14>
define <4 x i32> @mul(<4 x i32> %v) {
; CHECK-LABEL: @mul(
-; CHECK-NEXT: [[B:%.*]] = mul nuw nsw <4 x i32> [[V:%.*]], <i32 undef, i32 12, i32 undef, i32 14>
-; CHECK-NEXT: [[S:%.*]] = shufflevector <4 x i32> [[V]], <4 x i32> [[B]], <4 x i32> <i32 undef, i32 5, i32 2, i32 7>
+; CHECK-NEXT: [[S:%.*]] = mul nuw nsw <4 x i32> [[V:%.*]], <i32 undef, i32 12, i32 1, i32 14>
; CHECK-NEXT: ret <4 x i32> [[S]]
;
%b = mul nsw nuw <4 x i32> %v, <i32 11, i32 12, i32 13, i32 14>
define <3 x i42> @and(<3 x i42> %v) {
; CHECK-LABEL: @and(
-; CHECK-NEXT: [[B:%.*]] = and <3 x i42> [[V:%.*]], <i42 undef, i42 12, i42 undef>
-; CHECK-NEXT: [[S:%.*]] = shufflevector <3 x i42> [[V]], <3 x i42> [[B]], <3 x i32> <i32 0, i32 4, i32 undef>
+; CHECK-NEXT: [[S:%.*]] = and <3 x i42> [[V:%.*]], <i42 -1, i42 12, i42 undef>
; CHECK-NEXT: ret <3 x i42> [[S]]
;
%b = and <3 x i42> %v, <i42 11, i42 12, i42 13>
define <4 x i32> @or(<4 x i32> %v) {
; CHECK-LABEL: @or(
; CHECK-NEXT: [[B:%.*]] = or <4 x i32> [[V:%.*]], <i32 11, i32 12, i32 13, i32 14>
-; CHECK-NEXT: [[S:%.*]] = shufflevector <4 x i32> [[B]], <4 x i32> [[V]], <4 x i32> <i32 4, i32 5, i32 2, i32 3>
+; CHECK-NEXT: [[S:%.*]] = or <4 x i32> [[V]], <i32 0, i32 0, i32 13, i32 14>
; CHECK-NEXT: call void @use_v4i32(<4 x i32> [[B]])
; CHECK-NEXT: ret <4 x i32> [[S]]
;
define <4 x i32> @xor(<4 x i32> %v) {
; CHECK-LABEL: @xor(
-; CHECK-NEXT: [[B:%.*]] = xor <4 x i32> [[V:%.*]], <i32 undef, i32 12, i32 undef, i32 undef>
-; CHECK-NEXT: [[S:%.*]] = shufflevector <4 x i32> [[V]], <4 x i32> [[B]], <4 x i32> <i32 0, i32 5, i32 2, i32 3>
+; CHECK-NEXT: [[S:%.*]] = xor <4 x i32> [[V:%.*]], <i32 0, i32 12, i32 0, i32 0>
; CHECK-NEXT: ret <4 x i32> [[S]]
;
%b = xor <4 x i32> %v, <i32 11, i32 12, i32 13, i32 14>