Index: llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -656,9 +656,9 @@ // Consider forming "A op' (B op D)". // If "B op D" simplifies then it can be formed with no cost. V = simplifyBinOp(TopLevelOpcode, B, D, SQ.getWithInstruction(&I)); - // If "B op D" doesn't simplify then only go on if both of the existing + // If "B op D" doesn't simplify then only go on if one of the existing // operations "A op' B" and "C op' D" will be zapped as no longer used. - if (!V && LHS->hasOneUse() && RHS->hasOneUse()) + if (!V && (LHS->hasOneUse() || RHS->hasOneUse())) V = Builder.CreateBinOp(TopLevelOpcode, B, D, RHS->getName()); if (V) { SimplifiedInst = Builder.CreateBinOp(InnerOpcode, A, V); @@ -676,9 +676,9 @@ // If "A op C" simplifies then it can be formed with no cost. V = simplifyBinOp(TopLevelOpcode, A, C, SQ.getWithInstruction(&I)); - // If "A op C" doesn't simplify then only go on if both of the existing + // If "A op C" doesn't simplify then only go on if one of the existing // operations "A op' B" and "C op' D" will be zapped as no longer used. - if (!V && LHS->hasOneUse() && RHS->hasOneUse()) + if (!V && (LHS->hasOneUse() || RHS->hasOneUse())) V = Builder.CreateBinOp(TopLevelOpcode, A, C, LHS->getName()); if (V) { SimplifiedInst = Builder.CreateBinOp(InnerOpcode, V, B); Index: llvm/test/Transforms/InstCombine/add.ll =================================================================== --- llvm/test/Transforms/InstCombine/add.ll +++ llvm/test/Transforms/InstCombine/add.ll @@ -1756,10 +1756,12 @@ ret i32 %G } +; x * y + x --> (y + 1) * x + define i8 @mul_add_common_factor_commute1(i8 %x, i8 %y) { ; CHECK-LABEL: @mul_add_common_factor_commute1( -; CHECK-NEXT: [[M:%.*]] = mul nsw i8 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[A:%.*]] = add nsw i8 [[M]], [[X]] +; CHECK-NEXT: [[X1:%.*]] = add i8 [[Y:%.*]], 1 +; CHECK-NEXT: [[A:%.*]] = mul i8 [[X1]], [[X:%.*]] ; CHECK-NEXT: ret i8 [[A]] ; %m = mul nsw i8 %x, %y @@ -1769,8 +1771,8 @@ define <2 x i8> @mul_add_common_factor_commute2(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @mul_add_common_factor_commute2( -; CHECK-NEXT: [[M:%.*]] = mul nuw <2 x i8> [[Y:%.*]], [[X:%.*]] -; CHECK-NEXT: [[A:%.*]] = add nuw <2 x i8> [[M]], [[X]] +; CHECK-NEXT: [[M1:%.*]] = add <2 x i8> [[Y:%.*]], +; CHECK-NEXT: [[A:%.*]] = mul nuw <2 x i8> [[M1]], [[X:%.*]] ; CHECK-NEXT: ret <2 x i8> [[A]] ; %m = mul nuw <2 x i8> %y, %x @@ -1781,8 +1783,8 @@ define i8 @mul_add_common_factor_commute3(i8 %p, i8 %y) { ; CHECK-LABEL: @mul_add_common_factor_commute3( ; CHECK-NEXT: [[X:%.*]] = mul i8 [[P:%.*]], [[P]] -; CHECK-NEXT: [[M:%.*]] = mul nuw i8 [[X]], [[Y:%.*]] -; CHECK-NEXT: [[A:%.*]] = add nsw i8 [[X]], [[M]] +; CHECK-NEXT: [[M1:%.*]] = add i8 [[Y:%.*]], 1 +; CHECK-NEXT: [[A:%.*]] = mul i8 [[X]], [[M1]] ; CHECK-NEXT: ret i8 [[A]] ; %x = mul i8 %p, %p ; thwart complexity-based canonicalization @@ -1795,8 +1797,8 @@ ; CHECK-LABEL: @mul_add_common_factor_commute4( ; CHECK-NEXT: [[X:%.*]] = mul i8 [[P:%.*]], [[P]] ; CHECK-NEXT: [[Y:%.*]] = mul i8 [[Q:%.*]], [[Q]] -; CHECK-NEXT: [[M:%.*]] = mul nsw i8 [[Y]], [[X]] -; CHECK-NEXT: [[A:%.*]] = add nuw i8 [[X]], [[M]] +; CHECK-NEXT: [[M1:%.*]] = add i8 [[Y]], 1 +; CHECK-NEXT: [[A:%.*]] = mul i8 [[X]], [[M1]] ; CHECK-NEXT: ret i8 [[A]] ; %x = mul i8 %p, %p ; thwart complexity-based canonicalization @@ -1806,6 +1808,8 @@ ret i8 %a } +; negative test - uses + define i8 @mul_add_common_factor_use(i8 %x, i8 %y) { ; CHECK-LABEL: @mul_add_common_factor_use( ; CHECK-NEXT: [[M:%.*]] = mul i8 [[X:%.*]], [[Y:%.*]] Index: llvm/test/Transforms/InstCombine/and-or.ll =================================================================== --- llvm/test/Transforms/InstCombine/and-or.ll +++ llvm/test/Transforms/InstCombine/and-or.ll @@ -671,11 +671,11 @@ ; CHECK-NEXT: [[SHR:%.*]] = ashr i32 [[A:%.*]], 23 ; CHECK-NEXT: [[AND:%.*]] = and i32 [[SHR]], 157 ; CHECK-NEXT: call void @use2(i32 [[AND]]) -; CHECK-NEXT: [[AND3:%.*]] = and i32 [[SHR]], [[B:%.*]] +; CHECK-NEXT: [[AND1:%.*]] = or i32 [[B:%.*]], 157 +; CHECK-NEXT: [[OR:%.*]] = and i32 [[SHR]], [[AND1]] ; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[B]], 23 ; CHECK-NEXT: [[AND9:%.*]] = and i32 [[TMP1]], 157 -; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[AND3]], [[AND9]] -; CHECK-NEXT: [[R:%.*]] = or i32 [[TMP2]], [[AND]] +; CHECK-NEXT: [[R:%.*]] = or i32 [[OR]], [[AND9]] ; CHECK-NEXT: ret i32 [[R]] ; %shr = ashr i32 %a, 23 @@ -700,9 +700,9 @@ ; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[A_1:%.*]], [[B_1:%.*]] ; CHECK-NEXT: [[TMP4:%.*]] = xor i1 [[TMP3]], true ; CHECK-NEXT: [[TMP5:%.*]] = and i1 [[TMP0]], [[A_1]] -; CHECK-NEXT: [[TMP6:%.*]] = and i1 [[TMP2]], [[B_1]] -; CHECK-NEXT: [[TMP7:%.*]] = or i1 [[TMP6]], [[TMP5]] -; CHECK-NEXT: [[D:%.*]] = or i1 [[TMP7]], [[TMP3]] +; CHECK-NEXT: [[TMP6:%.*]] = or i1 [[TMP2]], [[A_1]] +; CHECK-NEXT: [[TMP7:%.*]] = and i1 [[TMP6]], [[B_1]] +; CHECK-NEXT: [[D:%.*]] = or i1 [[TMP7]], [[TMP5]] ; CHECK-NEXT: [[TMP8:%.*]] = or i1 [[TMP1]], [[TMP3]] ; CHECK-NEXT: [[TMP9:%.*]] = insertvalue { i1, i1, i1, i1, i1 } zeroinitializer, i1 [[D]], 0 ; CHECK-NEXT: [[TMP10:%.*]] = insertvalue { i1, i1, i1, i1, i1 } [[TMP9]], i1 [[TMP4]], 1 Index: llvm/test/Transforms/InstCombine/ctpop.ll =================================================================== --- llvm/test/Transforms/InstCombine/ctpop.ll +++ llvm/test/Transforms/InstCombine/ctpop.ll @@ -448,9 +448,9 @@ ; CHECK-NEXT: [[I:%.*]] = tail call i32 @llvm.ctpop.i32(i32 [[ARG:%.*]]), !range [[RNG1]] ; CHECK-NEXT: [[I2:%.*]] = and i32 [[I]], 1 ; CHECK-NEXT: tail call void @use(i32 [[I2]]) -; CHECK-NEXT: [[I3:%.*]] = tail call i32 @llvm.ctpop.i32(i32 [[ARG1:%.*]]), !range [[RNG1]] -; CHECK-NEXT: [[I4:%.*]] = and i32 [[I3]], 1 -; CHECK-NEXT: [[I5:%.*]] = xor i32 [[I4]], [[I2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[ARG1:%.*]], [[ARG]] +; CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.ctpop.i32(i32 [[TMP1]]), !range [[RNG1]] +; CHECK-NEXT: [[I5:%.*]] = and i32 [[TMP2]], 1 ; CHECK-NEXT: ret i32 [[I5]] ; %i = tail call i32 @llvm.ctpop.i32(i32 %arg) @@ -467,9 +467,9 @@ ; CHECK-NEXT: [[I:%.*]] = tail call i32 @llvm.ctpop.i32(i32 [[ARG1:%.*]]), !range [[RNG1]] ; CHECK-NEXT: [[I2:%.*]] = and i32 [[I]], 1 ; CHECK-NEXT: tail call void @use(i32 [[I2]]) -; CHECK-NEXT: [[I3:%.*]] = tail call i32 @llvm.ctpop.i32(i32 [[ARG:%.*]]), !range [[RNG1]] -; CHECK-NEXT: [[I4:%.*]] = and i32 [[I3]], 1 -; CHECK-NEXT: [[I5:%.*]] = xor i32 [[I2]], [[I4]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[ARG1]], [[ARG:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.ctpop.i32(i32 [[TMP1]]), !range [[RNG1]] +; CHECK-NEXT: [[I5:%.*]] = and i32 [[TMP2]], 1 ; CHECK-NEXT: ret i32 [[I5]] ; %i = tail call i32 @llvm.ctpop.i32(i32 %arg1) Index: llvm/test/Transforms/InstCombine/sub.ll =================================================================== --- llvm/test/Transforms/InstCombine/sub.ll +++ llvm/test/Transforms/InstCombine/sub.ll @@ -2003,10 +2003,13 @@ ret i16 %z } +; x * y - x --> (y - 1) * x +; TODO: The mul could retain nsw. + define i8 @mul_sub_common_factor_commute1(i8 %x, i8 %y) { ; CHECK-LABEL: @mul_sub_common_factor_commute1( -; CHECK-NEXT: [[M:%.*]] = mul nsw i8 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[A:%.*]] = sub nsw i8 [[M]], [[X]] +; CHECK-NEXT: [[X1:%.*]] = add i8 [[Y:%.*]], -1 +; CHECK-NEXT: [[A:%.*]] = mul i8 [[X1]], [[X:%.*]] ; CHECK-NEXT: ret i8 [[A]] ; %m = mul nsw i8 %x, %y @@ -2014,10 +2017,12 @@ ret i8 %a } +; TODO: The mul could retain nuw. + define <2 x i8> @mul_sub_common_factor_commute2(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @mul_sub_common_factor_commute2( -; CHECK-NEXT: [[M:%.*]] = mul nuw <2 x i8> [[Y:%.*]], [[X:%.*]] -; CHECK-NEXT: [[A:%.*]] = sub nuw <2 x i8> [[M]], [[X]] +; CHECK-NEXT: [[M1:%.*]] = add <2 x i8> [[Y:%.*]], +; CHECK-NEXT: [[A:%.*]] = mul <2 x i8> [[M1]], [[X:%.*]] ; CHECK-NEXT: ret <2 x i8> [[A]] ; %m = mul nuw <2 x i8> %y, %x @@ -2025,10 +2030,12 @@ ret <2 x i8> %a } +; x - (x * y) --> (1 - y) * x + define i8 @mul_sub_common_factor_commute3(i8 %x, i8 %y) { ; CHECK-LABEL: @mul_sub_common_factor_commute3( -; CHECK-NEXT: [[M:%.*]] = mul nuw i8 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[A:%.*]] = sub nsw i8 [[X]], [[M]] +; CHECK-NEXT: [[M1:%.*]] = sub i8 1, [[Y:%.*]] +; CHECK-NEXT: [[A:%.*]] = mul i8 [[M1]], [[X:%.*]] ; CHECK-NEXT: ret i8 [[A]] ; %m = mul nuw i8 %x, %y @@ -2038,8 +2045,8 @@ define i8 @mul_sub_common_factor_commute4(i8 %x, i8 %y) { ; CHECK-LABEL: @mul_sub_common_factor_commute4( -; CHECK-NEXT: [[M:%.*]] = mul nsw i8 [[Y:%.*]], [[X:%.*]] -; CHECK-NEXT: [[A:%.*]] = sub nuw i8 [[X]], [[M]] +; CHECK-NEXT: [[M1:%.*]] = sub i8 1, [[Y:%.*]] +; CHECK-NEXT: [[A:%.*]] = mul i8 [[M1]], [[X:%.*]] ; CHECK-NEXT: ret i8 [[A]] ; %m = mul nsw i8 %y, %x @@ -2047,6 +2054,8 @@ ret i8 %a } +; negative test - uses + define i8 @mul_sub_common_factor_use(i8 %x, i8 %y) { ; CHECK-LABEL: @mul_sub_common_factor_use( ; CHECK-NEXT: [[M:%.*]] = mul i8 [[X:%.*]], [[Y:%.*]]