1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -instcombine -S | FileCheck %s
3
4; PR22723: Recognize De Morgan's Laws when obfuscated by zexts.
5
6define i32 @demorgan_or(i1 %X, i1 %Y) {
7; CHECK-LABEL: @demorgan_or(
8; CHECK-NEXT:    [[OR_DEMORGAN:%.*]] = and i1 %X, %Y
9; CHECK-NEXT:    [[TMP1:%.*]] = zext i1 [[OR_DEMORGAN]] to i32
10; CHECK-NEXT:    [[OR:%.*]] = xor i32 [[TMP1]], 1
11; CHECK-NEXT:    ret i32 [[OR]]
12;
13  %zextX = zext i1 %X to i32
14  %zextY = zext i1 %Y to i32
15  %notX  = xor i32 %zextX, 1
16  %notY  = xor i32 %zextY, 1
17  %or    = or i32 %notX, %notY
18  ret i32 %or
19}
20
21define i32 @demorgan_and(i1 %X, i1 %Y) {
22; CHECK-LABEL: @demorgan_and(
23; CHECK-NEXT:    [[AND_DEMORGAN:%.*]] = or i1 %X, %Y
24; CHECK-NEXT:    [[TMP1:%.*]] = zext i1 [[AND_DEMORGAN]] to i32
25; CHECK-NEXT:    [[AND:%.*]] = xor i32 [[TMP1]], 1
26; CHECK-NEXT:    ret i32 [[AND]]
27;
28  %zextX = zext i1 %X to i32
29  %zextY = zext i1 %Y to i32
30  %notX  = xor i32 %zextX, 1
31  %notY  = xor i32 %zextY, 1
32  %and   = and i32 %notX, %notY
33  ret i32 %and
34}
35
36; FIXME: Vectors should get the same transform.
37
38define <2 x i32> @demorgan_or_vec(<2 x i1> %X, <2 x i1> %Y) {
39; CHECK-LABEL: @demorgan_or_vec(
40; CHECK-NEXT:    [[ZEXTX:%.*]] = zext <2 x i1> %X to <2 x i32>
41; CHECK-NEXT:    [[ZEXTY:%.*]] = zext <2 x i1> %Y to <2 x i32>
42; CHECK-NEXT:    [[NOTX:%.*]] = xor <2 x i32> [[ZEXTX]], <i32 1, i32 1>
43; CHECK-NEXT:    [[NOTY:%.*]] = xor <2 x i32> [[ZEXTY]], <i32 1, i32 1>
44; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[NOTX]], [[NOTY]]
45; CHECK-NEXT:    ret <2 x i32> [[OR]]
46;
47  %zextX = zext <2 x i1> %X to <2 x i32>
48  %zextY = zext <2 x i1> %Y to <2 x i32>
49  %notX  = xor <2 x i32> %zextX, <i32 1, i32 1>
50  %notY  = xor <2 x i32> %zextY, <i32 1, i32 1>
51  %or    = or <2 x i32> %notX, %notY
52  ret <2 x i32> %or
53}
54
55define <2 x i32> @demorgan_and_vec(<2 x i1> %X, <2 x i1> %Y) {
56; CHECK-LABEL: @demorgan_and_vec(
57; CHECK-NEXT:    [[ZEXTX:%.*]] = zext <2 x i1> %X to <2 x i32>
58; CHECK-NEXT:    [[ZEXTY:%.*]] = zext <2 x i1> %Y to <2 x i32>
59; CHECK-NEXT:    [[NOTX:%.*]] = xor <2 x i32> [[ZEXTX]], <i32 1, i32 1>
60; CHECK-NEXT:    [[NOTY:%.*]] = xor <2 x i32> [[ZEXTY]], <i32 1, i32 1>
61; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[NOTX]], [[NOTY]]
62; CHECK-NEXT:    ret <2 x i32> [[AND]]
63;
64  %zextX = zext <2 x i1> %X to <2 x i32>
65  %zextY = zext <2 x i1> %Y to <2 x i32>
66  %notX  = xor <2 x i32> %zextX, <i32 1, i32 1>
67  %notY  = xor <2 x i32> %zextY, <i32 1, i32 1>
68  %and   = and <2 x i32> %notX, %notY
69  ret <2 x i32> %and
70}
71
72; FIXME: If the xor was canonicalized to a 'not', then this would simplify.
73
74define i32 @PR28476(i32 %x, i32 %y) {
75; CHECK-LABEL: @PR28476(
76; CHECK-NEXT:    [[CMP0:%.*]] = icmp ne i32 %x, 0
77; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i32 %y, 0
78; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP0]], [[CMP1]]
79; CHECK-NEXT:    [[ZEXT:%.*]] = zext i1 [[AND]] to i32
80; CHECK-NEXT:    [[COND:%.*]] = xor i32 [[ZEXT]], 1
81; CHECK-NEXT:    ret i32 [[COND]]
82;
83  %cmp0 = icmp ne i32 %x, 0
84  %cmp1 = icmp ne i32 %y, 0
85  %and = and i1 %cmp0, %cmp1
86  %zext = zext i1 %and to i32
87  %cond = xor i32 %zext, 1
88  ret i32 %cond
89}
90
91