Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -3219,6 +3219,11 @@ // ~(X + C) --> -(C + 1) - X if (match(Op0, m_Add(m_Value(X), m_Constant(C)))) return BinaryOperator::CreateSub(ConstantExpr::getNeg(AddOne(C)), X); + + // ~(~X + Y) --> X - Y + if (match(NotVal, m_c_Add(m_Not(m_Value(X)), m_Value(Y)))) + return BinaryOperator::CreateWithCopiedFlags(Instruction::Sub, X, Y, + NotVal); } // Use DeMorgan and reassociation to eliminate a 'not' op. Index: llvm/test/Transforms/InstCombine/not-add.ll =================================================================== --- llvm/test/Transforms/InstCombine/not-add.ll +++ llvm/test/Transforms/InstCombine/not-add.ll @@ -2,13 +2,10 @@ ; RUN: opt -instcombine -S < %s | FileCheck %s declare void @use(i8) -declare i8 @get() define i8 @basic(i8 %x, i8 %y) { ; CHECK-LABEL: @basic( -; CHECK-NEXT: [[NOTX:%.*]] = xor i8 [[X:%.*]], -1 -; CHECK-NEXT: [[A:%.*]] = add i8 [[NOTX]], [[Y:%.*]] -; CHECK-NEXT: [[NOTA:%.*]] = xor i8 [[A]], -1 +; CHECK-NEXT: [[NOTA:%.*]] = sub i8 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: ret i8 [[NOTA]] ; %notx = xor i8 %x, -1 @@ -19,9 +16,7 @@ define i8 @basic_com_add(i8 %x, i8 %y) { ; CHECK-LABEL: @basic_com_add( -; CHECK-NEXT: [[NOTY:%.*]] = xor i8 [[Y:%.*]], -1 -; CHECK-NEXT: [[A:%.*]] = add i8 [[NOTY]], [[X:%.*]] -; CHECK-NEXT: [[NOTA:%.*]] = xor i8 [[A]], -1 +; CHECK-NEXT: [[NOTA:%.*]] = sub i8 [[Y:%.*]], [[X:%.*]] ; CHECK-NEXT: ret i8 [[NOTA]] ; %noty = xor i8 %y, -1 @@ -34,8 +29,7 @@ ; CHECK-LABEL: @basic_use_xor( ; CHECK-NEXT: [[NOTX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: call void @use(i8 [[NOTX]]) -; CHECK-NEXT: [[A:%.*]] = add i8 [[NOTX]], [[Y:%.*]] -; CHECK-NEXT: [[NOTA:%.*]] = xor i8 [[A]], -1 +; CHECK-NEXT: [[NOTA:%.*]] = sub i8 [[X]], [[Y:%.*]] ; CHECK-NEXT: ret i8 [[NOTA]] ; %notx = xor i8 %x, -1 @@ -50,7 +44,7 @@ ; CHECK-NEXT: [[NOTX:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: [[A:%.*]] = add i8 [[NOTX]], [[Y:%.*]] ; CHECK-NEXT: call void @use(i8 [[A]]) -; CHECK-NEXT: [[NOTA:%.*]] = xor i8 [[A]], -1 +; CHECK-NEXT: [[NOTA:%.*]] = sub i8 [[X]], [[Y]] ; CHECK-NEXT: ret i8 [[NOTA]] ; %notx = xor i8 %x, -1 @@ -66,7 +60,7 @@ ; CHECK-NEXT: call void @use(i8 [[NOTX]]) ; CHECK-NEXT: [[A:%.*]] = add i8 [[NOTX]], [[Y:%.*]] ; CHECK-NEXT: call void @use(i8 [[A]]) -; CHECK-NEXT: [[NOTA:%.*]] = xor i8 [[A]], -1 +; CHECK-NEXT: [[NOTA:%.*]] = sub i8 [[X]], [[Y]] ; CHECK-NEXT: ret i8 [[NOTA]] ; %notx = xor i8 %x, -1 @@ -79,9 +73,7 @@ define i8 @basic_preserve_nsw(i8 %x, i8 %y) { ; CHECK-LABEL: @basic_preserve_nsw( -; CHECK-NEXT: [[NOTX:%.*]] = xor i8 [[X:%.*]], -1 -; CHECK-NEXT: [[A:%.*]] = add nsw i8 [[NOTX]], [[Y:%.*]] -; CHECK-NEXT: [[NOTA:%.*]] = xor i8 [[A]], -1 +; CHECK-NEXT: [[NOTA:%.*]] = sub nsw i8 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: ret i8 [[NOTA]] ; %notx = xor i8 %x, -1 @@ -92,9 +84,7 @@ define i8 @basic_preserve_nuw(i8 %x, i8 %y) { ; CHECK-LABEL: @basic_preserve_nuw( -; CHECK-NEXT: [[NOTX:%.*]] = xor i8 [[X:%.*]], -1 -; CHECK-NEXT: [[A:%.*]] = add nuw i8 [[NOTX]], [[Y:%.*]] -; CHECK-NEXT: [[NOTA:%.*]] = xor i8 [[A]], -1 +; CHECK-NEXT: [[NOTA:%.*]] = sub nuw i8 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: ret i8 [[NOTA]] ; %notx = xor i8 %x, -1 @@ -105,9 +95,7 @@ define i8 @basic_preserve_nuw_nsw(i8 %x, i8 %y) { ; CHECK-LABEL: @basic_preserve_nuw_nsw( -; CHECK-NEXT: [[NOTX:%.*]] = xor i8 [[X:%.*]], -1 -; CHECK-NEXT: [[A:%.*]] = add nuw nsw i8 [[NOTX]], [[Y:%.*]] -; CHECK-NEXT: [[NOTA:%.*]] = xor i8 [[A]], -1 +; CHECK-NEXT: [[NOTA:%.*]] = sub nuw nsw i8 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: ret i8 [[NOTA]] ; %notx = xor i8 %x, -1 @@ -118,9 +106,7 @@ define <4 x i32> @vector_test(<4 x i32> %x, <4 x i32> %y) { ; CHECK-LABEL: @vector_test( -; CHECK-NEXT: [[NOTX:%.*]] = xor <4 x i32> [[X:%.*]], -; CHECK-NEXT: [[A:%.*]] = add <4 x i32> [[NOTX]], [[Y:%.*]] -; CHECK-NEXT: [[NOTA:%.*]] = xor <4 x i32> [[A]], +; CHECK-NEXT: [[NOTA:%.*]] = sub <4 x i32> [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: ret <4 x i32> [[NOTA]] ; %notx = xor <4 x i32> %x, @@ -131,9 +117,7 @@ define <4 x i32> @vector_test_undef(<4 x i32> %x, <4 x i32> %y) { ; CHECK-LABEL: @vector_test_undef( -; CHECK-NEXT: [[NOTX:%.*]] = xor <4 x i32> [[X:%.*]], -; CHECK-NEXT: [[A:%.*]] = add <4 x i32> [[NOTX]], [[Y:%.*]] -; CHECK-NEXT: [[NOTA:%.*]] = xor <4 x i32> [[A]], +; CHECK-NEXT: [[NOTA:%.*]] = sub <4 x i32> [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: ret <4 x i32> [[NOTA]] ; %notx = xor <4 x i32> %x, @@ -145,9 +129,7 @@ define <4 x i32> @vector_test_undef_nsw_nuw(<4 x i32> %x, <4 x i32> %y) { ; CHECK-LABEL: @vector_test_undef_nsw_nuw( -; CHECK-NEXT: [[NOTX:%.*]] = xor <4 x i32> [[X:%.*]], -; CHECK-NEXT: [[A:%.*]] = add nuw nsw <4 x i32> [[NOTX]], [[Y:%.*]] -; CHECK-NEXT: [[NOTA:%.*]] = xor <4 x i32> [[A]], +; CHECK-NEXT: [[NOTA:%.*]] = sub nuw nsw <4 x i32> [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: ret <4 x i32> [[NOTA]] ; %notx = xor <4 x i32> %x,