diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1752,15 +1752,19 @@ InstCombinerImpl::BuilderTy &Builder) { Instruction::BinaryOps Opcode = BO.getOpcode(); Value *X, *Y, *Z; - if (match(&BO, m_c_BinOp(Opcode, - m_OneUse(m_c_BinOp(Opcode, m_Value(X), - m_OneUse(m_Value(Y)))), - m_OneUse(m_Value(Z))))) { + if (match(&BO, + m_c_BinOp(Opcode, m_OneUse(m_BinOp(Opcode, m_Value(X), m_Value(Y))), + m_OneUse(m_Value(Z))))) { // (X op Y) op Z --> (Y op Z) op X - if (!isa(X) && !isa(Y) && !isa(Z) && - !X->hasOneUse()) { - Value *YZ = Builder.CreateBinOp(Opcode, Y, Z); - return BinaryOperator::Create(Opcode, YZ, X); + if (!isa(X) && !isa(Y) && !isa(Z)) { + if (!X->hasOneUse()) { + Value *YZ = Builder.CreateBinOp(Opcode, Y, Z); + return BinaryOperator::Create(Opcode, YZ, X); + } + if (!Y->hasOneUse()) { + Value *XZ = Builder.CreateBinOp(Opcode, X, Z); + return BinaryOperator::Create(Opcode, XZ, Y); + } } } diff --git a/llvm/test/Transforms/InstCombine/and-or-not.ll b/llvm/test/Transforms/InstCombine/and-or-not.ll --- a/llvm/test/Transforms/InstCombine/and-or-not.ll +++ b/llvm/test/Transforms/InstCombine/and-or-not.ll @@ -747,12 +747,8 @@ define i4 @simplify_and_common_op_use1(i4 %x, i4 %y, i4 %z) { ; CHECK-LABEL: @simplify_and_common_op_use1( -; CHECK-NEXT: [[XY:%.*]] = or i4 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: call void @use(i4 [[Y]]) -; CHECK-NEXT: [[XYZ:%.*]] = or i4 [[XY]], [[Z:%.*]] -; CHECK-NEXT: [[NOT_XYZ:%.*]] = xor i4 [[XYZ]], -1 -; CHECK-NEXT: [[R:%.*]] = and i4 [[NOT_XYZ]], [[X]] -; CHECK-NEXT: ret i4 [[R]] +; CHECK-NEXT: call void @use(i4 [[Y:%.*]]) +; CHECK-NEXT: ret i4 0 ; %xy = or i4 %x, %y call void @use(i4 %y) @@ -766,6 +762,25 @@ define i4 @simplify_and_common_op_use2(i4 %x, i4 %y, i4 %z) { ; CHECK-LABEL: @simplify_and_common_op_use2( +; CHECK-NEXT: call void @use(i4 [[Y:%.*]]) +; CHECK-NEXT: [[TMP1:%.*]] = or i4 [[X:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[XYZ:%.*]] = or i4 [[TMP1]], [[Y]] +; CHECK-NEXT: [[NOT_XYZ:%.*]] = xor i4 [[XYZ]], -1 +; CHECK-NEXT: [[R:%.*]] = and i4 [[NOT_XYZ]], [[X]] +; CHECK-NEXT: ret i4 [[R]] +; + %xy = or i4 %y, %x + call void @use(i4 %y) + %xyz = or i4 %xy, %z + %not_xyz = xor i4 %xyz, -1 + %r = and i4 %not_xyz, %x + ret i4 %r +} + +; TODO: This should simplify. + +define i4 @simplify_and_common_op_use3(i4 %x, i4 %y, i4 %z) { +; CHECK-LABEL: @simplify_and_common_op_use3( ; CHECK-NEXT: [[XY:%.*]] = or i4 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: [[XYZ:%.*]] = or i4 [[XY]], [[Z:%.*]] ; CHECK-NEXT: call void @use(i4 [[Z]])