diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -1682,6 +1682,34 @@ return new ShuffleVectorInst(NewBO0, NewBO1, Mask); } + auto createBinOpReverse = [&](Value *X, Value *Y) { + Value *V = Builder.CreateBinOp(Opcode, X, Y, Inst.getName()); + if (auto *BO = dyn_cast(V)) + BO->copyIRFlags(&Inst); + Module *M = Inst.getModule(); + Function *F = Intrinsic::getDeclaration( + M, Intrinsic::experimental_vector_reverse, V->getType()); + return CallInst::Create(F, V); + }; + + // NOTE: Reverse shuffles don't require the speculative execution protection + // below because they don't affect which lanes take part in the computation. + + Value *V1, *V2; + if (match(LHS, m_VecReverse(m_Value(V1)))) { + // Op(rev(V1), rev(V2)) -> rev(Op(V1, V2)) + if (match(RHS, m_VecReverse(m_Value(V2))) && + (LHS->hasOneUse() || RHS->hasOneUse() || LHS == RHS)) + return createBinOpReverse(V1, V2); + + // Op(rev(V1), RHSSplat)) -> rev(Op(V1, RHSSplat)) + if (LHS->hasOneUse() && isSplatValue(RHS)) + return createBinOpReverse(V1, RHS); + } + // Op(LHSSplat, rev(V2)) -> rev(Op(LHSSplat, V2)) + else if (isSplatValue(LHS) && match(RHS, m_OneUse(m_VecReverse(m_Value(V2))))) + return createBinOpReverse(LHS, V2); + // It may not be safe to reorder shuffles and things like div, urem, etc. // because we may trap when executing those ops on unknown vector elements. // See PR20059. @@ -1697,7 +1725,6 @@ // If both arguments of the binary operation are shuffles that use the same // mask and shuffle within a single vector, move the shuffle after the binop. - Value *V1, *V2; if (match(LHS, m_Shuffle(m_Value(V1), m_Undef(), m_Mask(Mask))) && match(RHS, m_Shuffle(m_Value(V2), m_Undef(), m_SpecificMask(Mask))) && V1->getType() == V2->getType() && diff --git a/llvm/test/Transforms/InstCombine/vector-reverse.ll b/llvm/test/Transforms/InstCombine/vector-reverse.ll --- a/llvm/test/Transforms/InstCombine/vector-reverse.ll +++ b/llvm/test/Transforms/InstCombine/vector-reverse.ll @@ -7,9 +7,8 @@ define @binop_reverse( %a, %b) { ; CHECK-LABEL: @binop_reverse( -; CHECK-NEXT: [[A_REV:%.*]] = tail call @llvm.experimental.vector.reverse.nxv4i32( [[A:%.*]]) -; CHECK-NEXT: [[B_REV:%.*]] = tail call @llvm.experimental.vector.reverse.nxv4i32( [[B:%.*]]) -; CHECK-NEXT: [[ADD:%.*]] = add [[A_REV]], [[B_REV]] +; CHECK-NEXT: [[ADD1:%.*]] = add [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[ADD:%.*]] = call @llvm.experimental.vector.reverse.nxv4i32( [[ADD1]]) ; CHECK-NEXT: ret [[ADD]] ; %a.rev = tail call @llvm.experimental.vector.reverse.nxv4i32( %a) @@ -22,9 +21,9 @@ define @binop_reverse_1( %a, %b) { ; CHECK-LABEL: @binop_reverse_1( ; CHECK-NEXT: [[A_REV:%.*]] = tail call @llvm.experimental.vector.reverse.nxv4i32( [[A:%.*]]) -; CHECK-NEXT: [[B_REV:%.*]] = tail call @llvm.experimental.vector.reverse.nxv4i32( [[B:%.*]]) ; CHECK-NEXT: call void @use_nxv4i32( [[A_REV]]) -; CHECK-NEXT: [[ADD:%.*]] = add [[A_REV]], [[B_REV]] +; CHECK-NEXT: [[ADD1:%.*]] = add [[A]], [[B:%.*]] +; CHECK-NEXT: [[ADD:%.*]] = call @llvm.experimental.vector.reverse.nxv4i32( [[ADD1]]) ; CHECK-NEXT: ret [[ADD]] ; %a.rev = tail call @llvm.experimental.vector.reverse.nxv4i32( %a) @@ -37,10 +36,10 @@ ; %b.rev has multiple uses define @binop_reverse_2( %a, %b) { ; CHECK-LABEL: @binop_reverse_2( -; CHECK-NEXT: [[A_REV:%.*]] = tail call @llvm.experimental.vector.reverse.nxv4i32( [[A:%.*]]) ; CHECK-NEXT: [[B_REV:%.*]] = tail call @llvm.experimental.vector.reverse.nxv4i32( [[B:%.*]]) ; CHECK-NEXT: call void @use_nxv4i32( [[B_REV]]) -; CHECK-NEXT: [[ADD:%.*]] = add [[A_REV]], [[B_REV]] +; CHECK-NEXT: [[ADD1:%.*]] = add [[A:%.*]], [[B]] +; CHECK-NEXT: [[ADD:%.*]] = call @llvm.experimental.vector.reverse.nxv4i32( [[ADD1]]) ; CHECK-NEXT: ret [[ADD]] ; %a.rev = tail call @llvm.experimental.vector.reverse.nxv4i32( %a) @@ -71,8 +70,8 @@ ; %a.rev used as both operands define @binop_reverse_4( %a) { ; CHECK-LABEL: @binop_reverse_4( -; CHECK-NEXT: [[A_REV:%.*]] = tail call @llvm.experimental.vector.reverse.nxv4i32( [[A:%.*]]) -; CHECK-NEXT: [[MUL:%.*]] = mul [[A_REV]], [[A_REV]] +; CHECK-NEXT: [[MUL1:%.*]] = mul [[A:%.*]], [[A]] +; CHECK-NEXT: [[MUL:%.*]] = call @llvm.experimental.vector.reverse.nxv4i32( [[MUL1]]) ; CHECK-NEXT: ret [[MUL]] ; %a.rev = tail call @llvm.experimental.vector.reverse.nxv4i32( %a) @@ -82,10 +81,10 @@ define @binop_reverse_splat_RHS( %a, i32 %b) { ; CHECK-LABEL: @binop_reverse_splat_RHS( -; CHECK-NEXT: [[A_REV:%.*]] = tail call @llvm.experimental.vector.reverse.nxv4i32( [[A:%.*]]) ; CHECK-NEXT: [[B_INSERT:%.*]] = insertelement poison, i32 [[B:%.*]], i64 0 ; CHECK-NEXT: [[B_SPLAT:%.*]] = shufflevector [[B_INSERT]], poison, zeroinitializer -; CHECK-NEXT: [[DIV:%.*]] = udiv [[A_REV]], [[B_SPLAT]] +; CHECK-NEXT: [[DIV1:%.*]] = udiv [[A:%.*]], [[B_SPLAT]] +; CHECK-NEXT: [[DIV:%.*]] = call @llvm.experimental.vector.reverse.nxv4i32( [[DIV1]]) ; CHECK-NEXT: ret [[DIV]] ; %a.rev = tail call @llvm.experimental.vector.reverse.nxv4i32( %a) @@ -115,10 +114,10 @@ define @binop_reverse_splat_LHS( %a, i32 %b) { ; CHECK-LABEL: @binop_reverse_splat_LHS( -; CHECK-NEXT: [[A_REV:%.*]] = tail call @llvm.experimental.vector.reverse.nxv4i32( [[A:%.*]]) ; CHECK-NEXT: [[B_INSERT:%.*]] = insertelement poison, i32 [[B:%.*]], i64 0 ; CHECK-NEXT: [[B_SPLAT:%.*]] = shufflevector [[B_INSERT]], poison, zeroinitializer -; CHECK-NEXT: [[DIV:%.*]] = udiv [[B_SPLAT]], [[A_REV]] +; CHECK-NEXT: [[DIV1:%.*]] = udiv [[B_SPLAT]], [[A:%.*]] +; CHECK-NEXT: [[DIV:%.*]] = call @llvm.experimental.vector.reverse.nxv4i32( [[DIV1]]) ; CHECK-NEXT: ret [[DIV]] ; %a.rev = tail call @llvm.experimental.vector.reverse.nxv4i32( %a)