[InstCombine] De Morgan: sink 'not' into 'xor' (PR38446)

Summary:
https://rise4fun.com/Alive/IT3

Comes up in the [most ugliest]  `signed int` -> `signed char`  case of
`-fsanitize=implicit-conversion` (https://reviews.llvm.org/D50250)
Previously, we were stuck with `not`: {F6867736}
But now we are able to completely get rid of it: {F6867737}
(FIXME: why are we loosing the metadata? that seems wrong/strange.)

Here, we only want to do that it we will be able to completely
get rid of that 'not'.

Reviewers: spatel, craig.topper

Reviewed By: spatel

Subscribers: vsk, erichkeane, llvm-commits

Differential Revision: https://reviews.llvm.org/D50301

llvm-svn: 339243
This commit is contained in:
Roman Lebedev 2018-08-08 13:31:19 +00:00
parent f8c394f0f5
commit a677651a5a
2 changed files with 35 additions and 9 deletions

View File

@ -2452,6 +2452,32 @@ static Instruction *visitMaskedMerge(BinaryOperator &I,
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 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) {
}
}
if (Instruction *NewXor = sinkNotIntoXor(I, Builder))
return NewXor;
return nullptr;
}

View File

@ -23,9 +23,8 @@ declare i1 @gen1()
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_easyinvert(i16 %x, i8 %y) {
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_easyinvert0(i8 %y) {
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()