diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -877,7 +877,13 @@ // add (sub C1, X), C2 --> sub (add C1, C2), X if (match(Op0, m_Sub(m_Constant(Op00C), m_Value(X)))) - return BinaryOperator::CreateSub(ConstantExpr::getAdd(Op00C, Op1C), X); + if (Op0->hasOneUse()) + return BinaryOperator::CreateSub(ConstantExpr::getAdd(Op00C, Op1C), X); + + // add (add C1, X), C2 -> add (C1, C2), X + if (match(Op0, m_Add(m_Constant(Op00C), m_Value(X)))) + if (Op0->hasOneUse()) + return BinaryOperator::CreateAdd(ConstantExpr::getAdd(Op00C, Op1C), X); Value *Y; @@ -1762,11 +1768,15 @@ // C-(C2-X) --> X+(C-C2) if (match(Op1, m_Sub(m_Constant(C2), m_Value(X)))) - return BinaryOperator::CreateAdd(X, ConstantExpr::getSub(C, C2)); + // Skip combine if Op1 (C2-X) is used somewhere else, as it will add an extra unnecessary instruction, since the original (C2-X) won't be able to be removed. + if (Op1->hasOneUse()) + return BinaryOperator::CreateAdd(X, ConstantExpr::getSub(C, C2)); // C-(X+C2) --> (C-C2)-X if (match(Op1, m_Add(m_Value(X), m_Constant(C2)))) - return BinaryOperator::CreateSub(ConstantExpr::getSub(C, C2), X); + // Skip combine if Op1 (X+C2) is used somewhere else, as it will add an extra unnecessary instruction, since the original (X+C2) won't be able to be removed. + if (Op1->hasOneUse()) + return BinaryOperator::CreateSub(ConstantExpr::getSub(C, C2), X); } const APInt *Op0C; diff --git a/llvm/test/Transforms/InstCombine/addsub-constant-folding.ll b/llvm/test/Transforms/InstCombine/addsub-constant-folding.ll --- a/llvm/test/Transforms/InstCombine/addsub-constant-folding.ll +++ b/llvm/test/Transforms/InstCombine/addsub-constant-folding.ll @@ -136,7 +136,7 @@ ; CHECK-LABEL: @add_const_const_sub_extrause( ; CHECK-NEXT: [[T0:%.*]] = add i32 [[ARG:%.*]], 8 ; CHECK-NEXT: call void @use(i32 [[T0]]) -; CHECK-NEXT: [[T1:%.*]] = sub i32 -6, [[ARG]] +; CHECK-NEXT: [[T1:%.*]] = sub i32 2, [[T0:%.*]] ; CHECK-NEXT: ret i32 [[T1]] ; %t0 = add i32 %arg, 8 @@ -159,7 +159,7 @@ ; CHECK-LABEL: @vec_add_const_const_sub_extrause( ; CHECK-NEXT: [[T0:%.*]] = add <4 x i32> [[ARG:%.*]], ; CHECK-NEXT: call void @vec_use(<4 x i32> [[T0]]) -; CHECK-NEXT: [[T1:%.*]] = sub <4 x i32> , [[ARG]] +; CHECK-NEXT: [[T1:%.*]] = sub <4 x i32> , [[T0:%.*]] ; CHECK-NEXT: ret <4 x i32> [[T1]] ; %t0 = add <4 x i32> %arg, @@ -310,7 +310,7 @@ ; CHECK-LABEL: @sub_const_const_sub_extrause( ; CHECK-NEXT: [[T0:%.*]] = add i32 [[ARG:%.*]], -8 ; CHECK-NEXT: call void @use(i32 [[T0]]) -; CHECK-NEXT: [[T1:%.*]] = sub i32 10, [[ARG]] +; CHECK-NEXT: [[T1:%.*]] = sub i32 2, [[T0:%.*]] ; CHECK-NEXT: ret i32 [[T1]] ; %t0 = sub i32 %arg, 8 @@ -319,6 +319,20 @@ ret i32 %t1 } +define i32 @sub_const_const_sub_neg(i32 %arg) { +; CHECK-LABEL: @sub_const_const_sub_neg( +; CHECK-NEXT: [[T0:%.*]] = add i32 [[ARG:%.*]], -10 +; CHECK-NEXT: call void @use(i32 [[T0]]) +; CHECK-NEXT: [[T1:%.*]] = sub i32 0, [[T0:%.*]] +; CHECK-NEXT: ret i32 [[T1]] +; + %t0 = sub i32 %arg, 10 + call void @use(i32 %t0) + %t1 = sub i32 0, %t0 + %t2 = add i32 8, %t1 + ret i32 %t1 +} + define <4 x i32> @vec_sub_const_const_sub(<4 x i32> %arg) { ; CHECK-LABEL: @vec_sub_const_const_sub( ; CHECK-NEXT: [[T1:%.*]] = sub <4 x i32> , [[ARG:%.*]] @@ -333,7 +347,7 @@ ; CHECK-LABEL: @vec_sub_const_const_sub_extrause( ; CHECK-NEXT: [[T0:%.*]] = add <4 x i32> [[ARG:%.*]], ; CHECK-NEXT: call void @vec_use(<4 x i32> [[T0]]) -; CHECK-NEXT: [[T1:%.*]] = sub <4 x i32> , [[ARG]] +; CHECK-NEXT: [[T1:%.*]] = sub <4 x i32> , [[T0:%.*]] ; CHECK-NEXT: ret <4 x i32> [[T1]] ; %t0 = sub <4 x i32> %arg, @@ -368,7 +382,7 @@ ; CHECK-LABEL: @const_sub_add_const_extrause( ; CHECK-NEXT: [[T0:%.*]] = sub i32 8, [[ARG:%.*]] ; CHECK-NEXT: call void @use(i32 [[T0]]) -; CHECK-NEXT: [[T1:%.*]] = sub i32 10, [[ARG]] +; CHECK-NEXT: [[T1:%.*]] = add i32 [[T0:%.*]], 2 ; CHECK-NEXT: ret i32 [[T1]] ; %t0 = sub i32 8, %arg @@ -391,7 +405,7 @@ ; CHECK-LABEL: @vec_const_sub_add_const_extrause( ; CHECK-NEXT: [[T0:%.*]] = sub <4 x i32> , [[ARG:%.*]] ; CHECK-NEXT: call void @vec_use(<4 x i32> [[T0]]) -; CHECK-NEXT: [[T1:%.*]] = sub <4 x i32> , [[ARG]] +; CHECK-NEXT: [[T1:%.*]] = add <4 x i32> [[T0:%.*]], ; CHECK-NEXT: ret <4 x i32> [[T1]] ; %t0 = sub <4 x i32> , %arg @@ -426,7 +440,7 @@ ; CHECK-LABEL: @const_sub_sub_const_extrause( ; CHECK-NEXT: [[T0:%.*]] = sub i32 8, [[ARG:%.*]] ; CHECK-NEXT: call void @use(i32 [[T0]]) -; CHECK-NEXT: [[T1:%.*]] = sub i32 6, [[ARG]] +; CHECK-NEXT: [[T1:%.*]] = add i32 [[T0:%.*]], -2 ; CHECK-NEXT: ret i32 [[T1]] ; %t0 = sub i32 8, %arg @@ -449,7 +463,7 @@ ; CHECK-LABEL: @vec_const_sub_sub_const_extrause( ; CHECK-NEXT: [[T0:%.*]] = sub <4 x i32> , [[ARG:%.*]] ; CHECK-NEXT: call void @vec_use(<4 x i32> [[T0]]) -; CHECK-NEXT: [[T1:%.*]] = sub <4 x i32> , [[ARG]] +; CHECK-NEXT: [[T1:%.*]] = add <4 x i32> [[T0:%.*]], ; CHECK-NEXT: ret <4 x i32> [[T1]] ; %t0 = sub <4 x i32> , %arg @@ -485,7 +499,7 @@ ; CHECK-LABEL: @const_sub_const_sub_extrause( ; CHECK-NEXT: [[T0:%.*]] = sub i32 8, [[ARG:%.*]] ; CHECK-NEXT: call void @use(i32 [[T0]]) -; CHECK-NEXT: [[T1:%.*]] = add i32 [[ARG]], -6 +; CHECK-NEXT: [[T1:%.*]] = sub i32 2, [[T0:%.*]] ; CHECK-NEXT: ret i32 [[T1]] ; %t0 = sub i32 8, %arg @@ -508,7 +522,7 @@ ; CHECK-LABEL: @vec_const_sub_const_sub_extrause( ; CHECK-NEXT: [[T0:%.*]] = sub <4 x i32> , [[ARG:%.*]] ; CHECK-NEXT: call void @vec_use(<4 x i32> [[T0]]) -; CHECK-NEXT: [[T1:%.*]] = add <4 x i32> [[ARG]], +; CHECK-NEXT: [[T1:%.*]] = sub <4 x i32> , [[T0:%.*]] ; CHECK-NEXT: ret <4 x i32> [[T1]] ; %t0 = sub <4 x i32> , %arg