summaryrefslogtreecommitdiff
path: root/test/Transforms/InstCombine
diff options
context:
space:
mode:
Diffstat (limited to 'test/Transforms/InstCombine')
-rw-r--r--test/Transforms/InstCombine/amdgcn-intrinsics.ll6
-rw-r--r--test/Transforms/InstCombine/and-or-not.ll40
-rw-r--r--test/Transforms/InstCombine/and.ll13
-rw-r--r--test/Transforms/InstCombine/apint-and.ll126
-rw-r--r--test/Transforms/InstCombine/apint-and1.ll57
-rw-r--r--test/Transforms/InstCombine/apint-and2.ll82
-rw-r--r--test/Transforms/InstCombine/apint-not.ll25
-rw-r--r--test/Transforms/InstCombine/apint-or.ll23
-rw-r--r--test/Transforms/InstCombine/assume2.ll8
-rw-r--r--test/Transforms/InstCombine/demorgan-zext.ll81
-rw-r--r--test/Transforms/InstCombine/demorgan.ll501
-rw-r--r--test/Transforms/InstCombine/not.ll39
12 files changed, 651 insertions, 350 deletions
diff --git a/test/Transforms/InstCombine/amdgcn-intrinsics.ll b/test/Transforms/InstCombine/amdgcn-intrinsics.ll
index 357085fd31fee..1901997c5521f 100644
--- a/test/Transforms/InstCombine/amdgcn-intrinsics.ll
+++ b/test/Transforms/InstCombine/amdgcn-intrinsics.ll
@@ -1259,7 +1259,7 @@ define i64 @icmp_constant_inputs_false() {
}
; CHECK-LABEL: @icmp_constant_inputs_true(
-; CHECK: %result = call i64 @llvm.read_register.i64(metadata !0) #4
+; CHECK: %result = call i64 @llvm.read_register.i64(metadata !0) #5
define i64 @icmp_constant_inputs_true() {
%result = call i64 @llvm.amdgcn.icmp.i32(i32 9, i32 8, i32 34)
ret i64 %result
@@ -1524,7 +1524,7 @@ define i64 @fcmp_constant_inputs_false() {
}
; CHECK-LABEL: @fcmp_constant_inputs_true(
-; CHECK: %result = call i64 @llvm.read_register.i64(metadata !0) #4
+; CHECK: %result = call i64 @llvm.read_register.i64(metadata !0) #5
define i64 @fcmp_constant_inputs_true() {
%result = call i64 @llvm.amdgcn.fcmp.f32(float 2.0, float 4.0, i32 4)
ret i64 %result
@@ -1537,4 +1537,4 @@ define i64 @fcmp_constant_to_rhs_olt(float %x) {
ret i64 %result
}
-; CHECK: attributes #4 = { convergent }
+; CHECK: attributes #5 = { convergent }
diff --git a/test/Transforms/InstCombine/and-or-not.ll b/test/Transforms/InstCombine/and-or-not.ll
index a2e8a10735fd6..a8e32bd77f7f3 100644
--- a/test/Transforms/InstCombine/and-or-not.ll
+++ b/test/Transforms/InstCombine/and-or-not.ll
@@ -496,31 +496,23 @@ define i32 @xor_to_xor12(float %fa, float %fb) {
ret i32 %xor
}
-; ~(~(a | b) | (a & b)) --> (a | b) & ~(a & b) -> a ^ b
+; https://bugs.llvm.org/show_bug.cgi?id=32830
+; Make sure we're matching operands correctly and not folding things wrongly.
-define i32 @demorgan_plus_and_to_xor(i32 %a, i32 %b) {
-; CHECK-LABEL: @demorgan_plus_and_to_xor(
-; CHECK-NEXT: [[NOT:%.*]] = xor i32 %b, %a
-; CHECK-NEXT: ret i32 [[NOT]]
+define i64 @PR32830(i64 %a, i64 %b, i64 %c) {
+; CHECK-LABEL: @PR32830(
+; CHECK-NEXT: [[NOTA:%.*]] = xor i64 %a, -1
+; CHECK-NEXT: [[NOTB:%.*]] = xor i64 %b, -1
+; CHECK-NEXT: [[OR1:%.*]] = or i64 [[NOTB]], %a
+; CHECK-NEXT: [[OR2:%.*]] = or i64 [[NOTA]], %c
+; CHECK-NEXT: [[AND:%.*]] = and i64 [[OR1]], [[OR2]]
+; CHECK-NEXT: ret i64 [[AND]]
;
- %or = or i32 %b, %a
- %notor = xor i32 %or, -1
- %and = and i32 %b, %a
- %or2 = or i32 %and, %notor
- %not = xor i32 %or2, -1
- ret i32 %not
-}
-
-define <4 x i32> @demorgan_plus_and_to_xor_vec(<4 x i32> %a, <4 x i32> %b) {
-; CHECK-LABEL: @demorgan_plus_and_to_xor_vec(
-; CHECK-NEXT: [[NOT:%.*]] = xor <4 x i32> %a, %b
-; CHECK-NEXT: ret <4 x i32> [[NOT]]
-;
- %or = or <4 x i32> %a, %b
- %notor = xor <4 x i32> %or, < i32 -1, i32 -1, i32 -1, i32 -1 >
- %and = and <4 x i32> %a, %b
- %or2 = or <4 x i32> %and, %notor
- %not = xor <4 x i32> %or2, < i32 -1, i32 -1, i32 -1, i32 -1 >
- ret <4 x i32> %not
+ %nota = xor i64 %a, -1
+ %notb = xor i64 %b, -1
+ %or1 = or i64 %notb, %a
+ %or2 = or i64 %nota, %c
+ %and = and i64 %or1, %or2
+ ret i64 %and
}
diff --git a/test/Transforms/InstCombine/and.ll b/test/Transforms/InstCombine/and.ll
index a2715c12fa88f..8ef7870891f0e 100644
--- a/test/Transforms/InstCombine/and.ll
+++ b/test/Transforms/InstCombine/and.ll
@@ -172,19 +172,6 @@ define i8 @test16(i8 %A) {
ret i8 %C
}
-;; ~(~X & Y) --> (X | ~Y)
-define i8 @test17(i8 %X, i8 %Y) {
-; CHECK-LABEL: @test17(
-; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 %Y, -1
-; CHECK-NEXT: [[D:%.*]] = or i8 [[Y_NOT]], %X
-; CHECK-NEXT: ret i8 [[D]]
-;
- %B = xor i8 %X, -1
- %C = and i8 %B, %Y
- %D = xor i8 %C, -1
- ret i8 %D
-}
-
define i1 @test18(i32 %A) {
; CHECK-LABEL: @test18(
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 %A, 127
diff --git a/test/Transforms/InstCombine/apint-and.ll b/test/Transforms/InstCombine/apint-and.ll
new file mode 100644
index 0000000000000..f0381dfc2845c
--- /dev/null
+++ b/test/Transforms/InstCombine/apint-and.ll
@@ -0,0 +1,126 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; FIXME: Some of these tests belong in InstSimplify.
+
+; Integer BitWidth <= 64 && BitWidth % 8 != 0.
+
+define i39 @test0(i39 %A) {
+; CHECK-LABEL: @test0(
+; CHECK-NEXT: ret i39 0
+;
+ %B = and i39 %A, 0 ; zero result
+ ret i39 %B
+}
+
+define i15 @test2(i15 %x) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT: ret i15 %x
+;
+ %tmp.2 = and i15 %x, -1 ; noop
+ ret i15 %tmp.2
+}
+
+define i23 @test3(i23 %x) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT: ret i23 0
+;
+ %tmp.0 = and i23 %x, 127
+ %tmp.2 = and i23 %tmp.0, 128
+ ret i23 %tmp.2
+}
+
+define i1 @test4(i37 %x) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT: [[B:%.*]] = icmp ugt i37 %x, 2147483647
+; CHECK-NEXT: ret i1 [[B]]
+;
+ %A = and i37 %x, -2147483648
+ %B = icmp ne i37 %A, 0
+ ret i1 %B
+}
+
+define i7 @test5(i7 %A, i7* %P) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT: [[B:%.*]] = or i7 %A, 3
+; CHECK-NEXT: [[C:%.*]] = xor i7 [[B]], 12
+; CHECK-NEXT: store i7 [[C]], i7* %P, align 1
+; CHECK-NEXT: ret i7 3
+;
+ %B = or i7 %A, 3
+ %C = xor i7 %B, 12
+ store i7 %C, i7* %P
+ %r = and i7 %C, 3
+ ret i7 %r
+}
+
+define i47 @test7(i47 %A) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT: [[TMP1:%.*]] = lshr i47 %A, 39
+; CHECK-NEXT: ret i47 [[TMP1]]
+;
+ %X = ashr i47 %A, 39 ;; sign extend
+ %C1 = and i47 %X, 255
+ ret i47 %C1
+}
+
+; Integer BitWidth > 64 && BitWidth <= 1024.
+
+define i999 @test8(i999 %A) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT: ret i999 0
+;
+ %B = and i999 %A, 0 ; zero result
+ ret i999 %B
+}
+
+define i1005 @test9(i1005 %x) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT: ret i1005 %x
+;
+ %tmp.2 = and i1005 %x, -1 ; noop
+ ret i1005 %tmp.2
+}
+
+define i123 @test10(i123 %x) {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT: ret i123 0
+;
+ %tmp.0 = and i123 %x, 127
+ %tmp.2 = and i123 %tmp.0, 128
+ ret i123 %tmp.2
+}
+
+define i1 @test11(i737 %x) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT: [[B:%.*]] = icmp ugt i737 %x, 2147483647
+; CHECK-NEXT: ret i1 [[B]]
+;
+ %A = and i737 %x, -2147483648
+ %B = icmp ne i737 %A, 0
+ ret i1 %B
+}
+
+define i117 @test12(i117 %A, i117* %P) {
+; CHECK-LABEL: @test12(
+; CHECK-NEXT: [[B:%.*]] = or i117 %A, 3
+; CHECK-NEXT: [[C:%.*]] = xor i117 [[B]], 12
+; CHECK-NEXT: store i117 [[C]], i117* %P, align 4
+; CHECK-NEXT: ret i117 3
+;
+ %B = or i117 %A, 3
+ %C = xor i117 %B, 12
+ store i117 %C, i117* %P
+ %r = and i117 %C, 3
+ ret i117 %r
+}
+
+define i1024 @test13(i1024 %A) {
+; CHECK-LABEL: @test13(
+; CHECK-NEXT: [[TMP1:%.*]] = lshr i1024 %A, 1016
+; CHECK-NEXT: ret i1024 [[TMP1]]
+;
+ %X = ashr i1024 %A, 1016 ;; sign extend
+ %C1 = and i1024 %X, 255
+ ret i1024 %C1
+}
+
diff --git a/test/Transforms/InstCombine/apint-and1.ll b/test/Transforms/InstCombine/apint-and1.ll
deleted file mode 100644
index fcd2dcd23ad15..0000000000000
--- a/test/Transforms/InstCombine/apint-and1.ll
+++ /dev/null
@@ -1,57 +0,0 @@
-; This test makes sure that and instructions are properly eliminated.
-; This test is for Integer BitWidth <= 64 && BitWidth % 8 != 0.
-
-; RUN: opt < %s -instcombine -S | not grep "and "
-; END.
-
-define i39 @test0(i39 %A) {
- %B = and i39 %A, 0 ; zero result
- ret i39 %B
-}
-
-define i47 @test1(i47 %A, i47 %B) {
- ;; (~A & ~B) == (~(A | B)) - De Morgan's Law
- %NotA = xor i47 %A, -1
- %NotB = xor i47 %B, -1
- %C1 = and i47 %NotA, %NotB
- ret i47 %C1
-}
-
-define i15 @test2(i15 %x) {
- %tmp.2 = and i15 %x, -1 ; noop
- ret i15 %tmp.2
-}
-
-define i23 @test3(i23 %x) {
- %tmp.0 = and i23 %x, 127
- %tmp.2 = and i23 %tmp.0, 128
- ret i23 %tmp.2
-}
-
-define i1 @test4(i37 %x) {
- %A = and i37 %x, -2147483648
- %B = icmp ne i37 %A, 0
- ret i1 %B
-}
-
-define i7 @test5(i7 %A, i7* %P) {
- %B = or i7 %A, 3
- %C = xor i7 %B, 12
- store i7 %C, i7* %P
- %r = and i7 %C, 3
- ret i7 %r
-}
-
-define i7 @test6(i7 %A, i7 %B) {
- ;; ~(~X & Y) --> (X | ~Y)
- %t0 = xor i7 %A, -1
- %t1 = and i7 %t0, %B
- %r = xor i7 %t1, -1
- ret i7 %r
-}
-
-define i47 @test7(i47 %A) {
- %X = ashr i47 %A, 39 ;; sign extend
- %C1 = and i47 %X, 255
- ret i47 %C1
-}
diff --git a/test/Transforms/InstCombine/apint-and2.ll b/test/Transforms/InstCombine/apint-and2.ll
deleted file mode 100644
index 78dc8f990d08f..0000000000000
--- a/test/Transforms/InstCombine/apint-and2.ll
+++ /dev/null
@@ -1,82 +0,0 @@
-; This test makes sure that and instructions are properly eliminated.
-; This test is for Integer BitWidth > 64 && BitWidth <= 1024.
-
-; RUN: opt < %s -instcombine -S | not grep "and "
-; END.
-
-
-define i999 @test0(i999 %A) {
- %B = and i999 %A, 0 ; zero result
- ret i999 %B
-}
-
-define i477 @test1(i477 %A, i477 %B) {
- ;; (~A & ~B) == (~(A | B)) - De Morgan's Law
- %NotA = xor i477 %A, -1
- %NotB = xor i477 %B, -1
- %C1 = and i477 %NotA, %NotB
- ret i477 %C1
-}
-
-define i129 @tst(i129 %A, i129 %B) {
- ;; (~A & ~B) == (~(A | B)) - De Morgan's Law
- %NotA = xor i129 %A, -1
- %NotB = xor i129 %B, -1
- %C1 = and i129 %NotA, %NotB
- ret i129 %C1
-}
-
-define i65 @test(i65 %A, i65 %B) {
- ;; (~A & ~B) == (~(A | B)) - De Morgan's Law
- %NotA = xor i65 %A, -1
- %NotB = xor i65 -1, %B
- %C1 = and i65 %NotA, %NotB
- ret i65 %C1
-}
-
-define i66 @tes(i66 %A, i66 %B) {
- ;; (~A & ~B) == (~(A | B)) - De Morgan's Law
- %NotA = xor i66 %A, -1
- %NotB = xor i66 %B, -1
- %C1 = and i66 %NotA, %NotB
- ret i66 %C1
-}
-
-define i1005 @test2(i1005 %x) {
- %tmp.2 = and i1005 %x, -1 ; noop
- ret i1005 %tmp.2
-}
-
-define i123 @test3(i123 %x) {
- %tmp.0 = and i123 %x, 127
- %tmp.2 = and i123 %tmp.0, 128
- ret i123 %tmp.2
-}
-
-define i1 @test4(i737 %x) {
- %A = and i737 %x, -2147483648
- %B = icmp ne i737 %A, 0
- ret i1 %B
-}
-
-define i117 @test5(i117 %A, i117* %P) {
- %B = or i117 %A, 3
- %C = xor i117 %B, 12
- store i117 %C, i117* %P
- %r = and i117 %C, 3
- ret i117 %r
-}
-
-define i117 @test6(i117 %A, i117 %B) {
- ;; ~(~X & Y) --> (X | ~Y)
- %t0 = xor i117 %A, -1
- %t1 = and i117 %t0, %B
- %r = xor i117 %t1, -1
- ret i117 %r
-}
-
-define i1024 @test7(i1024 %A) {
- %X = ashr i1024 %A, 1016 ;; sign extend
- %C1 = and i1024 %X, 255
- ret i1024 %C1
-}
diff --git a/test/Transforms/InstCombine/apint-not.ll b/test/Transforms/InstCombine/apint-not.ll
index 488b7f2c98e18..c5b12fd5dee54 100644
--- a/test/Transforms/InstCombine/apint-not.ll
+++ b/test/Transforms/InstCombine/apint-not.ll
@@ -15,28 +15,3 @@ define i1 @test2(i52 %A, i52 %B) {
ret i1 %Ret
}
-; Test that demorgans law can be instcombined
-define i47 @test3(i47 %A, i47 %B) {
- %a = xor i47 %A, -1
- %b = xor i47 %B, -1
- %c = and i47 %a, %b
- %d = xor i47 %c, -1
- ret i47 %d
-}
-
-; Test that demorgens law can work with constants
-define i61 @test4(i61 %A, i61 %B) {
- %a = xor i61 %A, -1
- %c = and i61 %a, 5 ; 5 = ~c2
- %d = xor i61 %c, -1
- ret i61 %d
-}
-
-; test the mirror of demorgans law...
-define i71 @test5(i71 %A, i71 %B) {
- %a = xor i71 %A, -1
- %b = xor i71 %B, -1
- %c = or i71 %a, %b
- %d = xor i71 %c, -1
- ret i71 %d
-}
diff --git a/test/Transforms/InstCombine/apint-or.ll b/test/Transforms/InstCombine/apint-or.ll
index e2312b61f2b9e..33304bf8ad625 100644
--- a/test/Transforms/InstCombine/apint-or.ll
+++ b/test/Transforms/InstCombine/apint-or.ll
@@ -27,18 +27,6 @@ define i39 @test2(i39 %V, i39 %M) {
; CHECK-NEXT: ret i39 %A
}
-define i43 @test3(i43 %A, i43 %B) {
- ;; (~A | ~B) == (~(A & B)) - De Morgan's Law
- %NotA = xor i43 %A, -1
- %NotB = xor i43 %B, -1
- %C1 = or i43 %NotA, %NotB
- ret i43 %C1
-; CHECK-LABEL: @test3
-; CHECK-NEXT: %C1.demorgan = and i43 %A, %B
-; CHECK-NEXT: %C1 = xor i43 %C1.demorgan, -1
-; CHECK-NEXT: ret i43 %C1
-}
-
; These tests are for Integer BitWidth > 64 && BitWidth <= 1024.
define i1023 @test4(i1023 %A) {
;; A | ~A == -1
@@ -66,14 +54,3 @@ define i399 @test5(i399 %V, i399 %M) {
; CHECK-NEXT: ret i399 %A
}
-define i129 @test6(i129 %A, i129 %B) {
- ;; (~A | ~B) == (~(A & B)) - De Morgan's Law
- %NotA = xor i129 %A, -1
- %NotB = xor i129 %B, -1
- %C1 = or i129 %NotA, %NotB
- ret i129 %C1
-; CHECK-LABEL: @test6
-; CHECK-NEXT: %C1.demorgan = and i129 %A, %B
-; CHECK-NEXT: %C1 = xor i129 %C1.demorgan, -1
-; CHECK-NEXT: ret i129 %C1
-}
diff --git a/test/Transforms/InstCombine/assume2.ll b/test/Transforms/InstCombine/assume2.ll
index e8fbc049f41aa..8dc8831fffa5f 100644
--- a/test/Transforms/InstCombine/assume2.ll
+++ b/test/Transforms/InstCombine/assume2.ll
@@ -21,8 +21,8 @@ define i32 @test1(i32 %a) #0 {
define i32 @test2(i32 %a) #0 {
; CHECK-LABEL: @test2(
-; CHECK-NEXT: [[A_NOT:%.*]] = or i32 [[A:%.*]], -16
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A_NOT]], -6
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[A:%.*]], 15
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 10
; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]])
; CHECK-NEXT: ret i32 2
;
@@ -50,8 +50,8 @@ define i32 @test3(i32 %a) #0 {
define i32 @test4(i32 %a) #0 {
; CHECK-LABEL: @test4(
-; CHECK-NEXT: [[A_NOT:%.*]] = and i32 [[A:%.*]], 15
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A_NOT]], 10
+; CHECK-NEXT: [[V:%.*]] = or i32 [[A:%.*]], -16
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[V]], -6
; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]])
; CHECK-NEXT: ret i32 2
;
diff --git a/test/Transforms/InstCombine/demorgan-zext.ll b/test/Transforms/InstCombine/demorgan-zext.ll
deleted file mode 100644
index d537730ba9a63..0000000000000
--- a/test/Transforms/InstCombine/demorgan-zext.ll
+++ /dev/null
@@ -1,81 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -instcombine -S | FileCheck %s
-
-; PR22723: Recognize De Morgan's Laws when obfuscated by zexts.
-
-define i32 @demorgan_or(i1 %X, i1 %Y) {
-; CHECK-LABEL: @demorgan_or(
-; CHECK-NEXT: [[OR1_DEMORGAN:%.*]] = and i1 %X, %Y
-; CHECK-NEXT: [[OR1:%.*]] = xor i1 [[OR1_DEMORGAN]], true
-; CHECK-NEXT: [[OR:%.*]] = zext i1 [[OR:%.*]]1 to i32
-; CHECK-NEXT: ret i32 [[OR]]
-;
- %zextX = zext i1 %X to i32
- %zextY = zext i1 %Y to i32
- %notX = xor i32 %zextX, 1
- %notY = xor i32 %zextY, 1
- %or = or i32 %notX, %notY
- ret i32 %or
-}
-
-define i32 @demorgan_and(i1 %X, i1 %Y) {
-; CHECK-LABEL: @demorgan_and(
-; CHECK-NEXT: [[AND1_DEMORGAN:%.*]] = or i1 %X, %Y
-; CHECK-NEXT: [[AND1:%.*]] = xor i1 [[AND1_DEMORGAN]], true
-; CHECK-NEXT: [[AND:%.*]] = zext i1 [[AND:%.*]]1 to i32
-; CHECK-NEXT: ret i32 [[AND]]
-;
- %zextX = zext i1 %X to i32
- %zextY = zext i1 %Y to i32
- %notX = xor i32 %zextX, 1
- %notY = xor i32 %zextY, 1
- %and = and i32 %notX, %notY
- ret i32 %and
-}
-
-define <2 x i32> @demorgan_or_vec(<2 x i1> %X, <2 x i1> %Y) {
-; CHECK-LABEL: @demorgan_or_vec(
-; CHECK-NEXT: [[OR1_DEMORGAN:%.*]] = and <2 x i1> %X, %Y
-; CHECK-NEXT: [[OR1:%.*]] = xor <2 x i1> [[OR1_DEMORGAN]], <i1 true, i1 true>
-; CHECK-NEXT: [[OR:%.*]] = zext <2 x i1> [[OR:%.*]]1 to <2 x i32>
-; CHECK-NEXT: ret <2 x i32> [[OR]]
-;
- %zextX = zext <2 x i1> %X to <2 x i32>
- %zextY = zext <2 x i1> %Y to <2 x i32>
- %notX = xor <2 x i32> %zextX, <i32 1, i32 1>
- %notY = xor <2 x i32> %zextY, <i32 1, i32 1>
- %or = or <2 x i32> %notX, %notY
- ret <2 x i32> %or
-}
-
-define <2 x i32> @demorgan_and_vec(<2 x i1> %X, <2 x i1> %Y) {
-; CHECK-LABEL: @demorgan_and_vec(
-; CHECK-NEXT: [[AND1_DEMORGAN:%.*]] = or <2 x i1> %X, %Y
-; CHECK-NEXT: [[AND1:%.*]] = xor <2 x i1> [[AND1_DEMORGAN]], <i1 true, i1 true>
-; CHECK-NEXT: [[AND:%.*]] = zext <2 x i1> [[AND:%.*]]1 to <2 x i32>
-; CHECK-NEXT: ret <2 x i32> [[AND]]
-;
- %zextX = zext <2 x i1> %X to <2 x i32>
- %zextY = zext <2 x i1> %Y to <2 x i32>
- %notX = xor <2 x i32> %zextX, <i32 1, i32 1>
- %notY = xor <2 x i32> %zextY, <i32 1, i32 1>
- %and = and <2 x i32> %notX, %notY
- ret <2 x i32> %and
-}
-
-define i32 @PR28476(i32 %x, i32 %y) {
-; CHECK-LABEL: @PR28476(
-; CHECK-NEXT: [[NOTLHS:%.*]] = icmp eq i32 %x, 0
-; CHECK-NEXT: [[NOTRHS:%.*]] = icmp eq i32 %y, 0
-; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[NOTRHS]], [[NOTLHS]]
-; CHECK-NEXT: [[COND:%.*]] = zext i1 [[TMP1]] to i32
-; CHECK-NEXT: ret i32 [[COND]]
-;
- %cmp0 = icmp ne i32 %x, 0
- %cmp1 = icmp ne i32 %y, 0
- %and = and i1 %cmp0, %cmp1
- %zext = zext i1 %and to i32
- %cond = xor i32 %zext, 1
- ret i32 %cond
-}
-
diff --git a/test/Transforms/InstCombine/demorgan.ll b/test/Transforms/InstCombine/demorgan.ll
new file mode 100644
index 0000000000000..26c2270a3fdfe
--- /dev/null
+++ b/test/Transforms/InstCombine/demorgan.ll
@@ -0,0 +1,501 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; (~A | ~B) == ~(A & B)
+
+define i43 @demorgan_or_apint1(i43 %A, i43 %B) {
+; CHECK-LABEL: @demorgan_or_apint1(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = and i43 %A, %B
+; CHECK-NEXT: [[C:%.*]] = xor i43 [[C_DEMORGAN]], -1
+; CHECK-NEXT: ret i43 [[C]]
+;
+ %NotA = xor i43 %A, -1
+ %NotB = xor i43 %B, -1
+ %C = or i43 %NotA, %NotB
+ ret i43 %C
+}
+
+; (~A | ~B) == ~(A & B)
+
+define i129 @demorgan_or_apint2(i129 %A, i129 %B) {
+; CHECK-LABEL: @demorgan_or_apint2(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = and i129 %A, %B
+; CHECK-NEXT: [[C:%.*]] = xor i129 [[C_DEMORGAN]], -1
+; CHECK-NEXT: ret i129 [[C]]
+;
+ %NotA = xor i129 %A, -1
+ %NotB = xor i129 %B, -1
+ %C = or i129 %NotA, %NotB
+ ret i129 %C
+}
+
+; (~A & ~B) == ~(A | B)
+
+define i477 @demorgan_and_apint1(i477 %A, i477 %B) {
+; CHECK-LABEL: @demorgan_and_apint1(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = or i477 %A, %B
+; CHECK-NEXT: [[C:%.*]] = xor i477 [[C_DEMORGAN]], -1
+; CHECK-NEXT: ret i477 [[C]]
+;
+ %NotA = xor i477 %A, -1
+ %NotB = xor i477 %B, -1
+ %C = and i477 %NotA, %NotB
+ ret i477 %C
+}
+
+; (~A & ~B) == ~(A | B)
+
+define i129 @demorgan_and_apint2(i129 %A, i129 %B) {
+; CHECK-LABEL: @demorgan_and_apint2(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = or i129 %A, %B
+; CHECK-NEXT: [[C:%.*]] = xor i129 [[C_DEMORGAN]], -1
+; CHECK-NEXT: ret i129 [[C]]
+;
+ %NotA = xor i129 %A, -1
+ %NotB = xor i129 %B, -1
+ %C = and i129 %NotA, %NotB
+ ret i129 %C
+}
+
+; (~A & ~B) == ~(A | B)
+
+define i65 @demorgan_and_apint3(i65 %A, i65 %B) {
+; CHECK-LABEL: @demorgan_and_apint3(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = or i65 %A, %B
+; CHECK-NEXT: [[C:%.*]] = xor i65 [[C_DEMORGAN]], -1
+; CHECK-NEXT: ret i65 [[C]]
+;
+ %NotA = xor i65 %A, -1
+ %NotB = xor i65 -1, %B
+ %C = and i65 %NotA, %NotB
+ ret i65 %C
+}
+
+; (~A & ~B) == ~(A | B)
+
+define i66 @demorgan_and_apint4(i66 %A, i66 %B) {
+; CHECK-LABEL: @demorgan_and_apint4(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = or i66 %A, %B
+; CHECK-NEXT: [[C:%.*]] = xor i66 [[C_DEMORGAN]], -1
+; CHECK-NEXT: ret i66 [[C]]
+;
+ %NotA = xor i66 %A, -1
+ %NotB = xor i66 %B, -1
+ %C = and i66 %NotA, %NotB
+ ret i66 %C
+}
+
+; (~A & ~B) == ~(A | B)
+
+define i47 @demorgan_and_apint5(i47 %A, i47 %B) {
+; CHECK-LABEL: @demorgan_and_apint5(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = or i47 %A, %B
+; CHECK-NEXT: [[C:%.*]] = xor i47 [[C_DEMORGAN]], -1
+; CHECK-NEXT: ret i47 [[C]]
+;
+ %NotA = xor i47 %A, -1
+ %NotB = xor i47 %B, -1
+ %C = and i47 %NotA, %NotB
+ ret i47 %C
+}
+
+; This is confirming that 2 transforms work together:
+; ~(~A & ~B) --> A | B
+
+define i32 @test3(i32 %A, i32 %B) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = or i32 %A, %B
+; CHECK-NEXT: ret i32 [[C_DEMORGAN]]
+;
+ %nota = xor i32 %A, -1
+ %notb = xor i32 %B, -1
+ %c = and i32 %nota, %notb
+ %notc = xor i32 %c, -1
+ ret i32 %notc
+}
+
+; Invert a constant if needed:
+; ~(~A & 5) --> A | ~5
+
+define i32 @test4(i32 %A) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT: [[NOTC1:%.*]] = or i32 %A, -6
+; CHECK-NEXT: ret i32 [[NOTC1]]
+;
+ %nota = xor i32 %A, -1
+ %c = and i32 %nota, 5
+ %notc = xor i32 %c, -1
+ ret i32 %notc
+}
+
+; Test the mirror of DeMorgan's law with an extra 'not'.
+; ~(~A | ~B) --> A & B
+
+define i32 @test5(i32 %A, i32 %B) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = and i32 %A, %B
+; CHECK-NEXT: ret i32 [[C_DEMORGAN]]
+;
+ %nota = xor i32 %A, -1
+ %notb = xor i32 %B, -1
+ %c = or i32 %nota, %notb
+ %notc = xor i32 %c, -1
+ ret i32 %notc
+}
+
+; Repeat with weird types for extra coverage.
+; ~(~A & ~B) --> A | B
+
+define i47 @test3_apint(i47 %A, i47 %B) {
+; CHECK-LABEL: @test3_apint(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = or i47 %A, %B
+; CHECK-NEXT: ret i47 [[C_DEMORGAN]]
+;
+ %nota = xor i47 %A, -1
+ %notb = xor i47 %B, -1
+ %c = and i47 %nota, %notb
+ %notc = xor i47 %c, -1
+ ret i47 %notc
+}
+
+; ~(~A & 5) --> A | ~5
+
+define i61 @test4_apint(i61 %A) {
+; CHECK-LABEL: @test4_apint(
+; CHECK-NEXT: [[NOTA:%.*]] = and i61 %A, 5
+; CHECK-NEXT: [[C:%.*]] = xor i61 [[NOTA]], 5
+; CHECK-NEXT: ret i61 [[C]]
+;
+ %nota = xor i61 %A, -1
+ %c = and i61 %nota, 5 ; 5 = ~c2
+ %notc = xor i61 %c, -1
+ ret i61 %c
+}
+
+; ~(~A | ~B) --> A & B
+
+define i71 @test5_apint(i71 %A, i71 %B) {
+; CHECK-LABEL: @test5_apint(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = and i71 %A, %B
+; CHECK-NEXT: ret i71 [[C_DEMORGAN]]
+;
+ %nota = xor i71 %A, -1
+ %notb = xor i71 %B, -1
+ %c = or i71 %nota, %notb
+ %notc = xor i71 %c, -1
+ ret i71 %notc
+}
+
+; ~(~A & B) --> (A | ~B)
+
+define i8 @demorgan_nand(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nand(
+; CHECK-NEXT: [[B_NOT:%.*]] = xor i8 %B, -1
+; CHECK-NEXT: [[NOTC:%.*]] = or i8 [[B_NOT]], %A
+; CHECK-NEXT: ret i8 [[NOTC]]
+;
+ %notx = xor i8 %A, -1
+ %c = and i8 %notx, %B
+ %notc = xor i8 %c, -1
+ ret i8 %notc
+}
+
+; ~(~A & B) --> (A | ~B)
+
+define i7 @demorgan_nand_apint1(i7 %A, i7 %B) {
+; CHECK-LABEL: @demorgan_nand_apint1(
+; CHECK-NEXT: [[B_NOT:%.*]] = xor i7 %B, -1
+; CHECK-NEXT: [[NOTC:%.*]] = or i7 [[B_NOT]], %A
+; CHECK-NEXT: ret i7 [[NOTC]]
+;
+ %nota = xor i7 %A, -1
+ %c = and i7 %nota, %B
+ %notc = xor i7 %c, -1
+ ret i7 %notc
+}
+
+; ~(~A & B) --> (A | ~B)
+
+define i117 @demorgan_nand_apint2(i117 %A, i117 %B) {
+; CHECK-LABEL: @demorgan_nand_apint2(
+; CHECK-NEXT: [[B_NOT:%.*]] = xor i117 %B, -1
+; CHECK-NEXT: [[NOTC:%.*]] = or i117 [[B_NOT]], %A
+; CHECK-NEXT: ret i117 [[NOTC]]
+;
+ %nota = xor i117 %A, -1
+ %c = and i117 %nota, %B
+ %notc = xor i117 %c, -1
+ ret i117 %notc
+}
+
+; ~(~A | B) --> (A & ~B)
+
+define i8 @demorgan_nor(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor(
+; CHECK-NEXT: [[B_NOT:%.*]] = xor i8 %B, -1
+; CHECK-NEXT: [[NOTC:%.*]] = and i8 [[B_NOT]], %A
+; CHECK-NEXT: ret i8 [[NOTC]]
+;
+ %notx = xor i8 %A, -1
+ %c = or i8 %notx, %B
+ %notc = xor i8 %c, -1
+ ret i8 %notc
+}
+
+; ~(~A | B) --> (A & ~B) - what if we use one of the intermediate results?
+
+define i8 @demorgan_nor_use2a(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor_use2a(
+; CHECK-NEXT: [[NOTA:%.*]] = xor i8 %A, -1
+; CHECK-NEXT: [[USE2A:%.*]] = mul i8 [[NOTA]], 23
+; CHECK-NEXT: [[B_NOT:%.*]] = xor i8 %B, -1
+; CHECK-NEXT: [[NOTC:%.*]] = and i8 [[B_NOT]], %A
+; CHECK-NEXT: [[R:%.*]] = sdiv i8 [[NOTC]], [[USE2A]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %nota = xor i8 %A, -1
+ %use2a = mul i8 %nota, 23
+ %c = or i8 %nota, %B
+ %notc = xor i8 %c, -1
+ %r = sdiv i8 %notc, %use2a
+ ret i8 %r
+}
+
+; ~(~A | B) --> (A & ~B) - what if we use one of the intermediate results?
+
+define i8 @demorgan_nor_use2b(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor_use2b(
+; CHECK-NEXT: [[USE2B:%.*]] = mul i8 %B, 23
+; CHECK-NEXT: [[B_NOT:%.*]] = xor i8 %B, -1
+; CHECK-NEXT: [[NOTC:%.*]] = and i8 [[B_NOT]], %A
+; CHECK-NEXT: [[R:%.*]] = sdiv i8 [[NOTC]], [[USE2B]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %use2b = mul i8 %B, 23
+ %nota = xor i8 %A, -1
+ %c = or i8 %nota, %B
+ %notc = xor i8 %c, -1
+ %r = sdiv i8 %notc, %use2b
+ ret i8 %r
+}
+
+; ~(~A | B) --> (A & ~B) - what if we use one of the intermediate results?
+
+define i8 @demorgan_nor_use2c(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor_use2c(
+; CHECK-NEXT: [[NOTA:%.*]] = xor i8 %A, -1
+; CHECK-NEXT: [[C:%.*]] = or i8 [[NOTA]], %B
+; CHECK-NEXT: [[USE2C:%.*]] = mul i8 [[C]], 23
+; CHECK-NEXT: [[NOTC:%.*]] = xor i8 [[C]], -1
+; CHECK-NEXT: [[R:%.*]] = sdiv i8 [[NOTC]], [[USE2C]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %nota = xor i8 %A, -1
+ %c = or i8 %nota, %B
+ %use2c = mul i8 %c, 23
+ %notc = xor i8 %c, -1
+ %r = sdiv i8 %notc, %use2c
+ ret i8 %r
+}
+
+; ~(~A | B) --> (A & ~B) - what if we use two of the intermediate results?
+
+define i8 @demorgan_nor_use2ab(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor_use2ab(
+; CHECK-NEXT: [[USE2B:%.*]] = mul i8 %B, 23
+; CHECK-NEXT: [[NOTA:%.*]] = xor i8 %A, -1
+; CHECK-NEXT: [[USE2A:%.*]] = mul i8 [[NOTA]], 17
+; CHECK-NEXT: [[B_NOT:%.*]] = xor i8 %B, -1
+; CHECK-NEXT: [[NOTC:%.*]] = and i8 [[B_NOT]], %A
+; CHECK-NEXT: [[R1:%.*]] = sdiv i8 [[NOTC]], [[USE2B]]
+; CHECK-NEXT: [[R2:%.*]] = sdiv i8 [[R1]], [[USE2A]]
+; CHECK-NEXT: ret i8 [[R2]]
+;
+ %use2b = mul i8 %B, 23
+ %nota = xor i8 %A, -1
+ %use2a = mul i8 %nota, 17
+ %c = or i8 %nota, %B
+ %notc = xor i8 %c, -1
+ %r1 = sdiv i8 %notc, %use2b
+ %r2 = sdiv i8 %r1, %use2a
+ ret i8 %r2
+}
+
+; ~(~A | B) --> (A & ~B) - what if we use two of the intermediate results?
+
+define i8 @demorgan_nor_use2ac(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor_use2ac(
+; CHECK-NEXT: [[NOTA:%.*]] = xor i8 %A, -1
+; CHECK-NEXT: [[USE2A:%.*]] = mul i8 [[NOTA]], 17
+; CHECK-NEXT: [[C:%.*]] = or i8 [[NOTA]], %B
+; CHECK-NEXT: [[USE2C:%.*]] = mul i8 [[C]], 23
+; CHECK-NEXT: [[NOTC:%.*]] = xor i8 [[C]], -1
+; CHECK-NEXT: [[R1:%.*]] = sdiv i8 [[NOTC]], [[USE2C]]
+; CHECK-NEXT: [[R2:%.*]] = sdiv i8 [[R1]], [[USE2A]]
+; CHECK-NEXT: ret i8 [[R2]]
+;
+ %nota = xor i8 %A, -1
+ %use2a = mul i8 %nota, 17
+ %c = or i8 %nota, %B
+ %use2c = mul i8 %c, 23
+ %notc = xor i8 %c, -1
+ %r1 = sdiv i8 %notc, %use2c
+ %r2 = sdiv i8 %r1, %use2a
+ ret i8 %r2
+}
+
+; ~(~A | B) --> (A & ~B) - what if we use two of the intermediate results?
+
+define i8 @demorgan_nor_use2bc(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor_use2bc(
+; CHECK-NEXT: [[USE2B:%.*]] = mul i8 %B, 23
+; CHECK-NEXT: [[NOTA:%.*]] = xor i8 %A, -1
+; CHECK-NEXT: [[C:%.*]] = or i8 [[NOTA]], %B
+; CHECK-NEXT: [[USE2C:%.*]] = mul i8 [[C]], 23
+; CHECK-NEXT: [[NOTC:%.*]] = xor i8 [[C]], -1
+; CHECK-NEXT: [[R1:%.*]] = sdiv i8 [[NOTC]], [[USE2C]]
+; CHECK-NEXT: [[R2:%.*]] = sdiv i8 [[R1]], [[USE2B]]
+; CHECK-NEXT: ret i8 [[R2]]
+;
+ %use2b = mul i8 %B, 23
+ %nota = xor i8 %A, -1
+ %c = or i8 %nota, %B
+ %use2c = mul i8 %c, 23
+ %notc = xor i8 %c, -1
+ %r1 = sdiv i8 %notc, %use2c
+ %r2 = sdiv i8 %r1, %use2b
+ ret i8 %r2
+}
+
+; Do not apply DeMorgan's Law to constants. We prefer 'not' ops.
+
+define i32 @demorganize_constant1(i32 %a) {
+; CHECK-LABEL: @demorganize_constant1(
+; CHECK-NEXT: [[AND:%.*]] = and i32 %a, 15
+; CHECK-NEXT: [[AND1:%.*]] = xor i32 [[AND]], -1
+; CHECK-NEXT: ret i32 [[AND1]]
+;
+ %and = and i32 %a, 15
+ %and1 = xor i32 %and, -1
+ ret i32 %and1
+}
+
+; Do not apply DeMorgan's Law to constants. We prefer 'not' ops.
+
+define i32 @demorganize_constant2(i32 %a) {
+; CHECK-LABEL: @demorganize_constant2(
+; CHECK-NEXT: [[AND:%.*]] = or i32 %a, 15
+; CHECK-NEXT: [[AND1:%.*]] = xor i32 [[AND]], -1
+; CHECK-NEXT: ret i32 [[AND1]]
+;
+ %and = or i32 %a, 15
+ %and1 = xor i32 %and, -1
+ ret i32 %and1
+}
+
+; PR22723: Recognize DeMorgan's Laws when obfuscated by zexts.
+
+define i32 @demorgan_or_zext(i1 %X, i1 %Y) {
+; CHECK-LABEL: @demorgan_or_zext(
+; CHECK-NEXT: [[OR1_DEMORGAN:%.*]] = and i1 %X, %Y
+; CHECK-NEXT: [[OR1:%.*]] = xor i1 [[OR1_DEMORGAN]], true
+; CHECK-NEXT: [[OR:%.*]] = zext i1 [[OR:%.*]]1 to i32
+; CHECK-NEXT: ret i32 [[OR]]
+;
+ %zextX = zext i1 %X to i32
+ %zextY = zext i1 %Y to i32
+ %notX = xor i32 %zextX, 1
+ %notY = xor i32 %zextY, 1
+ %or = or i32 %notX, %notY
+ ret i32 %or
+}
+
+define i32 @demorgan_and_zext(i1 %X, i1 %Y) {
+; CHECK-LABEL: @demorgan_and_zext(
+; CHECK-NEXT: [[AND1_DEMORGAN:%.*]] = or i1 %X, %Y
+; CHECK-NEXT: [[AND1:%.*]] = xor i1 [[AND1_DEMORGAN]], true
+; CHECK-NEXT: [[AND:%.*]] = zext i1 [[AND:%.*]]1 to i32
+; CHECK-NEXT: ret i32 [[AND]]
+;
+ %zextX = zext i1 %X to i32
+ %zextY = zext i1 %Y to i32
+ %notX = xor i32 %zextX, 1
+ %notY = xor i32 %zextY, 1
+ %and = and i32 %notX, %notY
+ ret i32 %and
+}
+
+define <2 x i32> @demorgan_or_zext_vec(<2 x i1> %X, <2 x i1> %Y) {
+; CHECK-LABEL: @demorgan_or_zext_vec(
+; CHECK-NEXT: [[OR1_DEMORGAN:%.*]] = and <2 x i1> %X, %Y
+; CHECK-NEXT: [[OR1:%.*]] = xor <2 x i1> [[OR1_DEMORGAN]], <i1 true, i1 true>
+; CHECK-NEXT: [[OR:%.*]] = zext <2 x i1> [[OR:%.*]]1 to <2 x i32>
+; CHECK-NEXT: ret <2 x i32> [[OR]]
+;
+ %zextX = zext <2 x i1> %X to <2 x i32>
+ %zextY = zext <2 x i1> %Y to <2 x i32>
+ %notX = xor <2 x i32> %zextX, <i32 1, i32 1>
+ %notY = xor <2 x i32> %zextY, <i32 1, i32 1>
+ %or = or <2 x i32> %notX, %notY
+ ret <2 x i32> %or
+}
+
+define <2 x i32> @demorgan_and_zext_vec(<2 x i1> %X, <2 x i1> %Y) {
+; CHECK-LABEL: @demorgan_and_zext_vec(
+; CHECK-NEXT: [[AND1_DEMORGAN:%.*]] = or <2 x i1> %X, %Y
+; CHECK-NEXT: [[AND1:%.*]] = xor <2 x i1> [[AND1_DEMORGAN]], <i1 true, i1 true>
+; CHECK-NEXT: [[AND:%.*]] = zext <2 x i1> [[AND:%.*]]1 to <2 x i32>
+; CHECK-NEXT: ret <2 x i32> [[AND]]
+;
+ %zextX = zext <2 x i1> %X to <2 x i32>
+ %zextY = zext <2 x i1> %Y to <2 x i32>
+ %notX = xor <2 x i32> %zextX, <i32 1, i32 1>
+ %notY = xor <2 x i32> %zextY, <i32 1, i32 1>
+ %and = and <2 x i32> %notX, %notY
+ ret <2 x i32> %and
+}
+
+define i32 @PR28476(i32 %x, i32 %y) {
+; CHECK-LABEL: @PR28476(
+; CHECK-NEXT: [[CMP0:%.*]] = icmp eq i32 %x, 0
+; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 %y, 0
+; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[CMP1]], [[CMP0]]
+; CHECK-NEXT: [[COND:%.*]] = zext i1 [[TMP1]] to i32
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %cmp0 = icmp ne i32 %x, 0
+ %cmp1 = icmp ne i32 %y, 0
+ %and = and i1 %cmp0, %cmp1
+ %zext = zext i1 %and to i32
+ %cond = xor i32 %zext, 1
+ ret i32 %cond
+}
+
+; ~(~(a | b) | (a & b)) --> (a | b) & ~(a & b) -> a ^ b
+
+define i32 @demorgan_plus_and_to_xor(i32 %a, i32 %b) {
+; CHECK-LABEL: @demorgan_plus_and_to_xor(
+; CHECK-NEXT: [[NOT:%.*]] = xor i32 %b, %a
+; CHECK-NEXT: ret i32 [[NOT]]
+;
+ %or = or i32 %b, %a
+ %notor = xor i32 %or, -1
+ %and = and i32 %b, %a
+ %or2 = or i32 %and, %notor
+ %not = xor i32 %or2, -1
+ ret i32 %not
+}
+
+define <4 x i32> @demorgan_plus_and_to_xor_vec(<4 x i32> %a, <4 x i32> %b) {
+; CHECK-LABEL: @demorgan_plus_and_to_xor_vec(
+; CHECK-NEXT: [[NOT:%.*]] = xor <4 x i32> %a, %b
+; CHECK-NEXT: ret <4 x i32> [[NOT]]
+;
+ %or = or <4 x i32> %a, %b
+ %notor = xor <4 x i32> %or, < i32 -1, i32 -1, i32 -1, i32 -1 >
+ %and = and <4 x i32> %a, %b
+ %or2 = or <4 x i32> %and, %notor
+ %not = xor <4 x i32> %or2, < i32 -1, i32 -1, i32 -1, i32 -1 >
+ ret <4 x i32> %not
+}
+
diff --git a/test/Transforms/InstCombine/not.ll b/test/Transforms/InstCombine/not.ll
index d0c242f65558c..2760d4ae044df 100644
--- a/test/Transforms/InstCombine/not.ll
+++ b/test/Transforms/InstCombine/not.ll
@@ -31,45 +31,8 @@ define i1 @invert_fcmp(float %X, float %Y) {
ret i1 %not
}
-; Test that De Morgan's law can be instcombined.
-define i32 @test3(i32 %A, i32 %B) {
-; CHECK-LABEL: @test3(
-; CHECK-NEXT: [[C_DEMORGAN:%.*]] = or i32 %A, %B
-; CHECK-NEXT: ret i32 [[C_DEMORGAN]]
-;
- %a = xor i32 %A, -1
- %b = xor i32 %B, -1
- %c = and i32 %a, %b
- %d = xor i32 %c, -1
- ret i32 %d
-}
-
-; Test that De Morgan's law can work with constants.
-define i32 @test4(i32 %A, i32 %B) {
-; CHECK-LABEL: @test4(
-; CHECK-NEXT: [[D1:%.*]] = or i32 %A, -6
-; CHECK-NEXT: ret i32 [[D1]]
-;
- %a = xor i32 %A, -1
- %c = and i32 %a, 5
- %d = xor i32 %c, -1
- ret i32 %d
-}
-
-; Test the mirror of De Morgan's law.
-define i32 @test5(i32 %A, i32 %B) {
-; CHECK-LABEL: @test5(
-; CHECK-NEXT: [[C_DEMORGAN:%.*]] = and i32 %A, %B
-; CHECK-NEXT: ret i32 [[C_DEMORGAN]]
-;
- %a = xor i32 %A, -1
- %b = xor i32 %B, -1
- %c = or i32 %a, %b
- %d = xor i32 %c, -1
- ret i32 %d
-}
-
; PR2298
+
define zeroext i8 @test6(i32 %a, i32 %b) {
; CHECK-LABEL: @test6(
; CHECK-NEXT: [[TMP3:%.*]] = icmp slt i32 %b, %a