xref: /llvm-project/llvm/test/Transforms/InstCombine/add-mask-neg.ll (revision 38fffa630ee80163dc65e759392ad29798905679)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -S -passes=instcombine | FileCheck %s
3
4;
5; Canonicalize ((X & -X) - 1) --> ((X - 1) & ~X)
6;
7
8define i32 @dec_mask_neg_i32(i32 %X) {
9; CHECK-LABEL: @dec_mask_neg_i32(
10; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[X:%.*]], -1
11; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[X]], -1
12; CHECK-NEXT:    [[DEC:%.*]] = and i32 [[TMP1]], [[TMP2]]
13; CHECK-NEXT:    ret i32 [[DEC]]
14;
15  %neg = sub i32 0, %X
16  %mask = and i32 %neg, %X
17  %dec = add i32 %mask, -1
18  ret i32 %dec
19}
20
21define i32 @dec_mask_commute_neg_i32(i32 %A) {
22; CHECK-LABEL: @dec_mask_commute_neg_i32(
23; CHECK-NEXT:    [[X:%.*]] = sdiv i32 42, [[A:%.*]]
24; CHECK-NEXT:    [[TMP1:%.*]] = add nsw i32 [[X]], -1
25; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[X]], -1
26; CHECK-NEXT:    [[DEC:%.*]] = and i32 [[TMP1]], [[TMP2]]
27; CHECK-NEXT:    ret i32 [[DEC]]
28;
29  %X = sdiv i32 42, %A ; thwart complexity-based canonicalization
30  %neg = sub i32 0, %X
31  %mask = and i32 %X, %neg
32  %dec = add i32 %mask, -1
33  ret i32 %dec
34}
35
36define i32 @dec_commute_mask_neg_i32(i32 %X) {
37; CHECK-LABEL: @dec_commute_mask_neg_i32(
38; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[X:%.*]], -1
39; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[X]], -1
40; CHECK-NEXT:    [[DEC:%.*]] = and i32 [[TMP1]], [[TMP2]]
41; CHECK-NEXT:    ret i32 [[DEC]]
42;
43  %neg = sub i32 0, %X
44  %mask = and i32 %neg, %X
45  %dec = add i32 -1, %mask
46  ret i32 %dec
47}
48
49define i32 @dec_mask_neg_multiuse_i32(i32 %X) {
50; CHECK-LABEL: @dec_mask_neg_multiuse_i32(
51; CHECK-NEXT:    [[NEG:%.*]] = sub i32 0, [[X:%.*]]
52; CHECK-NEXT:    [[MASK:%.*]] = and i32 [[X]], [[NEG]]
53; CHECK-NEXT:    [[DEC:%.*]] = add i32 [[MASK]], -1
54; CHECK-NEXT:    call void @use(i32 [[NEG]])
55; CHECK-NEXT:    ret i32 [[DEC]]
56;
57  %neg = sub i32 0, %X
58  %mask = and i32 %neg, %X
59  %dec = add i32 %mask, -1
60  call void @use(i32 %neg)
61  ret i32 %dec
62}
63
64define i32 @dec_mask_multiuse_neg_i32(i32 %X) {
65; CHECK-LABEL: @dec_mask_multiuse_neg_i32(
66; CHECK-NEXT:    [[NEG:%.*]] = sub i32 0, [[X:%.*]]
67; CHECK-NEXT:    [[MASK:%.*]] = and i32 [[X]], [[NEG]]
68; CHECK-NEXT:    [[DEC:%.*]] = add i32 [[MASK]], -1
69; CHECK-NEXT:    call void @use(i32 [[MASK]])
70; CHECK-NEXT:    ret i32 [[DEC]]
71;
72  %neg = sub i32 0, %X
73  %mask = and i32 %neg, %X
74  %dec = add i32 %mask, -1
75  call void @use(i32 %mask)
76  ret i32 %dec
77}
78
79define <2 x i32> @dec_mask_neg_v2i32(<2 x i32> %X) {
80; CHECK-LABEL: @dec_mask_neg_v2i32(
81; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i32> [[X:%.*]], splat (i32 -1)
82; CHECK-NEXT:    [[TMP2:%.*]] = xor <2 x i32> [[X]], splat (i32 -1)
83; CHECK-NEXT:    [[DEC:%.*]] = and <2 x i32> [[TMP1]], [[TMP2]]
84; CHECK-NEXT:    ret <2 x i32> [[DEC]]
85;
86  %neg = sub <2 x i32> zeroinitializer, %X
87  %mask = and <2 x i32> %neg, %X
88  %dec = add <2 x i32> %mask, <i32 -1, i32 -1>
89  ret <2 x i32> %dec
90}
91
92define <2 x i32> @dec_mask_neg_v2i32_poison(<2 x i32> %X) {
93; CHECK-LABEL: @dec_mask_neg_v2i32_poison(
94; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i32> [[X:%.*]], splat (i32 -1)
95; CHECK-NEXT:    [[TMP2:%.*]] = xor <2 x i32> [[X]], splat (i32 -1)
96; CHECK-NEXT:    [[DEC:%.*]] = and <2 x i32> [[TMP1]], [[TMP2]]
97; CHECK-NEXT:    ret <2 x i32> [[DEC]]
98;
99  %neg = sub <2 x i32> zeroinitializer, %X
100  %mask = and <2 x i32> %neg, %X
101  %dec = add <2 x i32> %mask, <i32 -1, i32 poison>
102  ret <2 x i32> %dec
103}
104
105define <2 x i32> @dec_mask_multiuse_neg_multiuse_v2i32(<2 x i32> %X) {
106; CHECK-LABEL: @dec_mask_multiuse_neg_multiuse_v2i32(
107; CHECK-NEXT:    [[NEG:%.*]] = sub <2 x i32> zeroinitializer, [[X:%.*]]
108; CHECK-NEXT:    [[MASK:%.*]] = and <2 x i32> [[X]], [[NEG]]
109; CHECK-NEXT:    [[DEC:%.*]] = add <2 x i32> [[MASK]], splat (i32 -1)
110; CHECK-NEXT:    call void @usev(<2 x i32> [[NEG]])
111; CHECK-NEXT:    call void @usev(<2 x i32> [[MASK]])
112; CHECK-NEXT:    ret <2 x i32> [[DEC]]
113;
114  %neg = sub <2 x i32> zeroinitializer, %X
115  %mask = and <2 x i32> %neg, %X
116  %dec = add <2 x i32> %mask, <i32 -1, i32 -1>
117  call void @usev(<2 x i32> %neg)
118  call void @usev(<2 x i32> %mask)
119  ret <2 x i32> %dec
120}
121
122declare void @use(i32)
123declare void @usev(<2 x i32>)
124