Index: llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2452,6 +2452,32 @@ return nullptr; } +// Transform +// ~(x ^ y) +// into: +// (~x) ^ y +// or into +// x ^ (~y) +static Instruction *sinkNotIntoXor(BinaryOperator &I, + InstCombiner::BuilderTy &Builder) { + Value *X, *Y; + // FIXME: one-use check is not needed in general, but currently we are unable + // to fold 'not' into 'icmp', if that 'icmp' has multiple uses. (D35182) + if (!match(&I, m_Not(m_OneUse(m_Xor(m_Value(X), m_Value(Y)))))) + return nullptr; + + // We only want to do the transform if it is free to do. + if (IsFreeToInvert(X, X->hasOneUse())) { + // Ok, good. + } else if (IsFreeToInvert(Y, Y->hasOneUse())) { + std::swap(X, Y); + } else + return nullptr; + + Value *NotX = Builder.CreateNot(X, X->getName() + ".not"); + return BinaryOperator::CreateXor(NotX, Y, I.getName() + ".demorgan"); +} + // FIXME: We use commutative matchers (m_c_*) for some, but not all, matches // here. We should standardize that construct where it is needed or choose some // other way to ensure that commutated variants of patterns are not missed. @@ -2777,5 +2803,8 @@ } } + if (Instruction *NewXor = sinkNotIntoXor(I, Builder)) + return NewXor; + return nullptr; } Index: llvm/trunk/test/Transforms/InstCombine/demorgan-sink-not-into-xor.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/demorgan-sink-not-into-xor.ll +++ llvm/trunk/test/Transforms/InstCombine/demorgan-sink-not-into-xor.ll @@ -23,9 +23,8 @@ define i1 @positive_easyinvert(i16 %x, i8 %y) { ; CHECK-LABEL: @positive_easyinvert( ; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i16 [[X:%.*]], 0 -; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i8 [[Y:%.*]], 0 -; CHECK-NEXT: [[TMP3:%.*]] = xor i1 [[TMP2]], [[TMP1]] -; CHECK-NEXT: [[TMP4:%.*]] = xor i1 [[TMP3]], true +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i8 [[Y:%.*]], -1 +; CHECK-NEXT: [[TMP4:%.*]] = xor i1 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i1 [[TMP4]] ; %tmp1 = icmp slt i16 %x, 0 @@ -38,9 +37,8 @@ define i1 @positive_easyinvert0(i8 %y) { ; CHECK-LABEL: @positive_easyinvert0( ; CHECK-NEXT: [[TMP1:%.*]] = call i1 @gen1() -; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i8 [[Y:%.*]], 0 -; CHECK-NEXT: [[TMP3:%.*]] = xor i1 [[TMP2]], [[TMP1]] -; CHECK-NEXT: [[TMP4:%.*]] = xor i1 [[TMP3]], true +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i8 [[Y:%.*]], -1 +; CHECK-NEXT: [[TMP4:%.*]] = xor i1 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i1 [[TMP4]] ; %tmp1 = call i1 @gen1() @@ -53,9 +51,8 @@ define i1 @positive_easyinvert1(i8 %y) { ; CHECK-LABEL: @positive_easyinvert1( ; CHECK-NEXT: [[TMP1:%.*]] = call i1 @gen1() -; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i8 [[Y:%.*]], 0 -; CHECK-NEXT: [[TMP3:%.*]] = xor i1 [[TMP1]], [[TMP2]] -; CHECK-NEXT: [[TMP4:%.*]] = xor i1 [[TMP3]], true +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i8 [[Y:%.*]], -1 +; CHECK-NEXT: [[TMP4:%.*]] = xor i1 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i1 [[TMP4]] ; %tmp1 = call i1 @gen1()