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 =================================================================== --- /dev/null +++ llvm/test/Transforms/InstCombine/not-add.ll @@ -0,0 +1,128 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; 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: [[NOTA:%.*]] = sub i8 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i8 [[NOTA]] +; + %notx = xor i8 %x, -1 + %a = add i8 %notx, %y + %nota = xor i8 %a, -1 + ret i8 %nota +} + +define i8 @basic_com_add(i8 %x, i8 %y) { +; CHECK-LABEL: @basic_com_add( +; CHECK-NEXT: [[NOTA:%.*]] = sub i8 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: ret i8 [[NOTA]] +; + %noty = xor i8 %y, -1 + %a = add i8 %x, %noty + %nota = xor i8 %a, -1 + ret i8 %nota +} + +define i8 @basic_use_xor(i8 %x, i8 %y) { +; CHECK-LABEL: @basic_use_xor( +; CHECK-NEXT: [[NOTX:%.*]] = xor i8 [[X:%.*]], -1 +; CHECK-NEXT: call void @use(i8 [[NOTX]]) +; CHECK-NEXT: [[NOTA:%.*]] = sub i8 [[X]], [[Y:%.*]] +; CHECK-NEXT: ret i8 [[NOTA]] +; + %notx = xor i8 %x, -1 + call void @use(i8 %notx) + %a = add i8 %notx, %y + %nota = xor i8 %a, -1 + ret i8 %nota +} + +define i8 @basic_use_add(i8 %x, i8 %y) { +; CHECK-LABEL: @basic_use_add( +; CHECK-NEXT: [[NOTX:%.*]] = xor i8 [[X:%.*]], -1 +; CHECK-NEXT: [[A:%.*]] = add i8 [[NOTX]], [[Y:%.*]] +; CHECK-NEXT: call void @use(i8 [[A]]) +; CHECK-NEXT: [[NOTA:%.*]] = sub i8 [[X]], [[Y]] +; CHECK-NEXT: ret i8 [[NOTA]] +; + %notx = xor i8 %x, -1 + %a = add i8 %notx, %y + call void @use(i8 %a) + %nota = xor i8 %a, -1 + ret i8 %nota +} + +define i8 @basic_use_both(i8 %x, i8 %y) { +; CHECK-LABEL: @basic_use_both( +; CHECK-NEXT: [[NOTX:%.*]] = xor i8 [[X:%.*]], -1 +; CHECK-NEXT: call void @use(i8 [[NOTX]]) +; CHECK-NEXT: [[A:%.*]] = add i8 [[NOTX]], [[Y:%.*]] +; CHECK-NEXT: call void @use(i8 [[A]]) +; CHECK-NEXT: [[NOTA:%.*]] = sub i8 [[X]], [[Y]] +; CHECK-NEXT: ret i8 [[NOTA]] +; + %notx = xor i8 %x, -1 + call void @use(i8 %notx) + %a = add i8 %notx, %y + call void @use(i8 %a) + %nota = xor i8 %a, -1 + ret i8 %nota +} + +define i8 @basic_preserve_nsw(i8 %x, i8 %y) { +; CHECK-LABEL: @basic_preserve_nsw( +; CHECK-NEXT: [[NOTA:%.*]] = sub nsw i8 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i8 [[NOTA]] +; + %notx = xor i8 %x, -1 + %a = add nsw i8 %notx, %y + %nota = xor i8 %a, -1 + ret i8 %nota +} + +define i8 @basic_preserve_nuw(i8 %x, i8 %y) { +; CHECK-LABEL: @basic_preserve_nuw( +; CHECK-NEXT: [[NOTA:%.*]] = sub nuw i8 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i8 [[NOTA]] +; + %notx = xor i8 %x, -1 + %a = add nuw i8 %notx, %y + %nota = xor i8 %a, -1 + ret i8 %nota +} + +define i8 @basic_preserve_nuw_nsw(i8 %x, i8 %y) { +; CHECK-LABEL: @basic_preserve_nuw_nsw( +; CHECK-NEXT: [[NOTA:%.*]] = sub nuw nsw i8 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i8 [[NOTA]] +; + %notx = xor i8 %x, -1 + %a = add nuw nsw i8 %notx, %y + %nota = xor i8 %a, -1 + ret i8 %nota +} + +define <4 x i32> @vector_test(<4 x i32> %x, <4 x i32> %y) { +; CHECK-LABEL: @vector_test( +; CHECK-NEXT: [[NOTA:%.*]] = sub <4 x i32> [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret <4 x i32> [[NOTA]] +; + %notx = xor <4 x i32> %x, + %a = add <4 x i32> %notx, %y + %nota = xor <4 x i32> %a, + ret <4 x i32> %nota +} + +define <4 x i32> @vector_test_undef(<4 x i32> %x, <4 x i32> %y) { +; CHECK-LABEL: @vector_test_undef( +; CHECK-NEXT: [[NOTA:%.*]] = sub <4 x i32> [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret <4 x i32> [[NOTA]] +; + %notx = xor <4 x i32> %x, + %a = add <4 x i32> %notx, %y + %nota = xor <4 x i32> %a, + ret <4 x i32> %nota +}