summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'llvm')
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp29
-rw-r--r--llvm/test/Transforms/InstCombine/demorgan-sink-not-into-xor.ll15
2 files changed, 35 insertions, 9 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 3d758e2fe7c..8bca658ce43 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -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;
}
diff --git a/llvm/test/Transforms/InstCombine/demorgan-sink-not-into-xor.ll b/llvm/test/Transforms/InstCombine/demorgan-sink-not-into-xor.ll
index 50d46019dae..c378033eef7 100644
--- a/llvm/test/Transforms/InstCombine/demorgan-sink-not-into-xor.ll
+++ b/llvm/test/Transforms/InstCombine/demorgan-sink-not-into-xor.ll
@@ -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()
OpenPOWER on IntegriCloud