1+ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
12; RUN: opt -instcombine -S < %s | FileCheck %s
23
34@gp = global i32* null , align 8
45
56declare i8* @malloc (i64 ) #1
67
78define i1 @compare_global_trivialeq () {
9+ ; CHECK-LABEL: @compare_global_trivialeq(
10+ ; CHECK-NEXT: ret i1 false
11+ ;
812 %m = call i8* @malloc (i64 4 )
913 %bc = bitcast i8* %m to i32*
1014 %lgp = load i32* , i32** @gp , align 8
1115 %cmp = icmp eq i32* %bc , %lgp
1216 ret i1 %cmp
13- ; CHECK-LABEL: compare_global_trivialeq
14- ; CHECK: ret i1 false
1517}
1618
1719define i1 @compare_global_trivialne () {
20+ ; CHECK-LABEL: @compare_global_trivialne(
21+ ; CHECK-NEXT: ret i1 true
22+ ;
1823 %m = call i8* @malloc (i64 4 )
1924 %bc = bitcast i8* %m to i32*
2025 %lgp = load i32* , i32** @gp , align 8
2126 %cmp = icmp ne i32* %bc , %lgp
2227 ret i1 %cmp
23- ; CHECK-LABEL: compare_global_trivialne
24- ; CHECK: ret i1 true
2528}
2629
2730
@@ -30,102 +33,143 @@ define i1 @compare_global_trivialne() {
3033; The comparison should fold to false irrespective of whether the call to malloc can be elided or not
3134declare void @f ()
3235define i1 @compare_and_call_with_deopt () {
33- ; CHECK-LABEL: compare_and_call_with_deopt
36+ ; CHECK-LABEL: @compare_and_call_with_deopt(
37+ ; CHECK-NEXT: [[M:%.*]] = call dereferenceable_or_null(24) i8* @malloc(i64 24)
38+ ; CHECK-NEXT: tail call void @f() [ "deopt"(i8* [[M]]) ]
39+ ; CHECK-NEXT: ret i1 false
40+ ;
3441 %m = call i8* @malloc (i64 24 )
3542 %bc = bitcast i8* %m to i32*
3643 %lgp = load i32* , i32** @gp , align 8 , !nonnull !0
3744 %cmp = icmp eq i32* %lgp , %bc
3845 tail call void @f () [ "deopt" (i8* %m ) ]
3946 ret i1 %cmp
40- ; CHECK: ret i1 false
4147}
4248
4349; Same functon as above with deopt operand in function f, but comparison is NE
4450define i1 @compare_ne_and_call_with_deopt () {
45- ; CHECK-LABEL: compare_ne_and_call_with_deopt
51+ ; CHECK-LABEL: @compare_ne_and_call_with_deopt(
52+ ; CHECK-NEXT: [[M:%.*]] = call dereferenceable_or_null(24) i8* @malloc(i64 24)
53+ ; CHECK-NEXT: tail call void @f() [ "deopt"(i8* [[M]]) ]
54+ ; CHECK-NEXT: ret i1 true
55+ ;
4656 %m = call i8* @malloc (i64 24 )
4757 %bc = bitcast i8* %m to i32*
4858 %lgp = load i32* , i32** @gp , align 8 , !nonnull !0
4959 %cmp = icmp ne i32* %lgp , %bc
5060 tail call void @f () [ "deopt" (i8* %m ) ]
5161 ret i1 %cmp
52- ; CHECK: ret i1 true
5362}
5463
5564; Same function as above, but global not marked nonnull, and we cannot fold the comparison
5665define i1 @compare_ne_global_maybe_null () {
57- ; CHECK-LABEL: compare_ne_global_maybe_null
66+ ; CHECK-LABEL: @compare_ne_global_maybe_null(
67+ ; CHECK-NEXT: [[M:%.*]] = call dereferenceable_or_null(24) i8* @malloc(i64 24)
68+ ; CHECK-NEXT: [[BC:%.*]] = bitcast i8* [[M]] to i32*
69+ ; CHECK-NEXT: [[LGP:%.*]] = load i32*, i32** @gp, align 8
70+ ; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32* [[LGP]], [[BC]]
71+ ; CHECK-NEXT: tail call void @f() [ "deopt"(i8* [[M]]) ]
72+ ; CHECK-NEXT: ret i1 [[CMP]]
73+ ;
5874 %m = call i8* @malloc (i64 24 )
5975 %bc = bitcast i8* %m to i32*
6076 %lgp = load i32* , i32** @gp
6177 %cmp = icmp ne i32* %lgp , %bc
6278 tail call void @f () [ "deopt" (i8* %m ) ]
6379 ret i1 %cmp
64- ; CHECK: ret i1 %cmp
6580}
6681
6782; FIXME: The comparison should fold to false since %m escapes (call to function escape)
6883; after the comparison.
6984declare void @escape (i8* )
7085define i1 @compare_and_call_after () {
71- ; CHECK-LABEL: compare_and_call_after
86+ ; CHECK-LABEL: @compare_and_call_after(
87+ ; CHECK-NEXT: [[M:%.*]] = call dereferenceable_or_null(24) i8* @malloc(i64 24)
88+ ; CHECK-NEXT: [[BC:%.*]] = bitcast i8* [[M]] to i32*
89+ ; CHECK-NEXT: [[LGP:%.*]] = load i32*, i32** @gp, align 8, !nonnull !0
90+ ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32* [[LGP]], [[BC]]
91+ ; CHECK-NEXT: br i1 [[CMP]], label [[ESCAPE_CALL:%.*]], label [[JUST_RETURN:%.*]]
92+ ; CHECK: escape_call:
93+ ; CHECK-NEXT: call void @escape(i8* [[M]])
94+ ; CHECK-NEXT: ret i1 true
95+ ; CHECK: just_return:
96+ ; CHECK-NEXT: ret i1 [[CMP]]
97+ ;
7298 %m = call i8* @malloc (i64 24 )
7399 %bc = bitcast i8* %m to i32*
74100 %lgp = load i32* , i32** @gp , align 8 , !nonnull !0
75101 %cmp = icmp eq i32* %bc , %lgp
76102 br i1 %cmp , label %escape_call , label %just_return
77103
78104escape_call:
79- call void @escape (i8* %m )
80- ret i1 true
105+ call void @escape (i8* %m )
106+ ret i1 true
81107
82108just_return:
83- ret i1 %cmp
109+ ret i1 %cmp
84110}
85111
86112define i1 @compare_distinct_mallocs () {
113+ ; CHECK-LABEL: @compare_distinct_mallocs(
114+ ; CHECK-NEXT: ret i1 false
115+ ;
87116 %m = call i8* @malloc (i64 4 )
88117 %n = call i8* @malloc (i64 4 )
89118 %cmp = icmp eq i8* %m , %n
90119 ret i1 %cmp
91- ; CHECK-LABEL: compare_distinct_mallocs
92- ; CHECK: ret i1 false
93120}
94121
95- ; the compare is folded to true since the folding compare looks through bitcasts.
96- ; call to malloc and the bitcast instructions are elided after that since there are no uses of the malloc
122+ ; the compare is folded to true since the folding compare looks through bitcasts.
123+ ; call to malloc and the bitcast instructions are elided after that since there are no uses of the malloc
97124define i1 @compare_samepointer_under_bitcast () {
125+ ; CHECK-LABEL: @compare_samepointer_under_bitcast(
126+ ; CHECK-NEXT: ret i1 true
127+ ;
98128 %m = call i8* @malloc (i64 4 )
99129 %bc = bitcast i8* %m to i32*
100130 %bcback = bitcast i32* %bc to i8*
101131 %cmp = icmp eq i8* %m , %bcback
102132 ret i1 %cmp
103- ; CHECK-LABEL: compare_samepointer_under_bitcast
104- ; CHECK: ret i1 true
105133}
106134
107- ; the compare is folded to true since the folding compare looks through bitcasts.
135+ ; the compare is folded to true since the folding compare looks through bitcasts.
108136; The malloc call for %m cannot be elided since it is used in the call to function f.
109137define i1 @compare_samepointer_escaped () {
138+ ; CHECK-LABEL: @compare_samepointer_escaped(
139+ ; CHECK-NEXT: [[M:%.*]] = call dereferenceable_or_null(4) i8* @malloc(i64 4)
140+ ; CHECK-NEXT: call void @f() [ "deopt"(i8* [[M]]) ]
141+ ; CHECK-NEXT: ret i1 true
142+ ;
110143 %m = call i8* @malloc (i64 4 )
111144 %bc = bitcast i8* %m to i32*
112145 %bcback = bitcast i32* %bc to i8*
113146 %cmp = icmp eq i8* %m , %bcback
114147 call void @f () [ "deopt" (i8* %m ) ]
115148 ret i1 %cmp
116- ; CHECK-LABEL: compare_samepointer_escaped
117- ; CHECK-NEXT: %m = call i8* @malloc(i64 4)
118- ; CHECK-NEXT: call void @f() [ "deopt"(i8* %m) ]
119- ; CHECK: ret i1 true
120149}
121150
122151; Technically, we can fold the %cmp2 comparison, even though %m escapes through
123152; the ret statement since `ret` terminates the function and we cannot reach from
124- ; the ret to cmp.
153+ ; the ret to cmp.
125154; FIXME: Folding this %cmp2 when %m escapes through ret could be an issue with
126155; cross-threading data dependencies since we do not make the distinction between
127156; atomic and non-atomic loads in capture tracking.
128157define i8* @compare_ret_escape (i8* %c ) {
158+ ; CHECK-LABEL: @compare_ret_escape(
159+ ; CHECK-NEXT: [[M:%.*]] = call dereferenceable_or_null(4) i8* @malloc(i64 4)
160+ ; CHECK-NEXT: [[N:%.*]] = call dereferenceable_or_null(4) i8* @malloc(i64 4)
161+ ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8* [[N]], [[C:%.*]]
162+ ; CHECK-NEXT: br i1 [[CMP]], label [[RETST:%.*]], label [[CHK:%.*]]
163+ ; CHECK: retst:
164+ ; CHECK-NEXT: ret i8* [[M]]
165+ ; CHECK: chk:
166+ ; CHECK-NEXT: [[BC:%.*]] = bitcast i8* [[M]] to i32*
167+ ; CHECK-NEXT: [[LGP:%.*]] = load i32*, i32** @gp, align 8, !nonnull !0
168+ ; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32* [[LGP]], [[BC]]
169+ ; CHECK-NEXT: br i1 [[CMP2]], label [[RETST]], label [[CHK2:%.*]]
170+ ; CHECK: chk2:
171+ ; CHECK-NEXT: ret i8* [[N]]
172+ ;
129173 %m = call i8* @malloc (i64 4 )
130174 %n = call i8* @malloc (i64 4 )
131175 %cmp = icmp eq i8* %n , %c
@@ -142,23 +186,21 @@ chk:
142186
143187chk2:
144188 ret i8* %n
145- ; CHECK-LABEL: compare_ret_escape
146- ; CHECK: %cmp = icmp eq i8* %n, %c
147- ; CHECK: %cmp2 = icmp eq i32* %lgp, %bc
148189}
149190
150191; The malloc call for %m cannot be elided since it is used in the call to function f.
151192; However, the cmp can be folded to true as %n doesnt escape and %m, %n are distinct allocations
152193define i1 @compare_distinct_pointer_escape () {
194+ ; CHECK-LABEL: @compare_distinct_pointer_escape(
195+ ; CHECK-NEXT: [[M:%.*]] = call dereferenceable_or_null(4) i8* @malloc(i64 4)
196+ ; CHECK-NEXT: tail call void @f() [ "deopt"(i8* [[M]]) ]
197+ ; CHECK-NEXT: ret i1 true
198+ ;
153199 %m = call i8* @malloc (i64 4 )
154200 %n = call i8* @malloc (i64 4 )
155201 tail call void @f () [ "deopt" (i8* %m ) ]
156202 %cmp = icmp ne i8* %m , %n
157203 ret i1 %cmp
158- ; CHECK-LABEL: compare_distinct_pointer_escape
159- ; CHECK-NEXT: %m = call i8* @malloc(i64 4)
160- ; CHECK-NEXT: tail call void @f() [ "deopt"(i8* %m) ]
161- ; CHECK-NEXT: ret i1 true
162204}
163205
164206!0 = !{}
0 commit comments