llvm.org GIT mirror llvm / ceb0f30
[RewriteStatepointsForGC] All constant should have null base pointer Currently we consider that each constant has itself as a base value. I.e "base(const) = const". This introduces couple of problems when we are trying to avoid reporting constants in statepoint live sets: 1. When querying "base( phi(const1, const2) )" we will get "phi(const1, const2)" as a base pointer. Since it's not a constant we will record it in a stack map. However on practice we don't want this to happen (constant are never relocated). 2. base( phi(const, gc ptr) ) = phi( const, base(gc ptr) ). This particular case imposes challenge on our runtime - we don't expect to see constant base pointers other than null. This problems can be avoided by treating all constant as if they were derived from null pointer base. I.e in a first case we will not include constant pointer in a stack map at all. In a second case we will get "phi(null, base(gc ptr))" as a base pointer which is a lot more convenient. Differential Revision: http://reviews.llvm.org/D20584 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@270993 91177308-0d34-0410-b5e6-96231b3b80d8 Igor Laevsky 3 years ago
5 changed file(s) with 163 addition(s) and 11 deletion(s). Raw diff Collapse all Expand all
342342 return BaseDefiningValueResult(I, true);
343343
344344 if (isa(I))
345 // Constant vectors consist only of constant pointers.
346 return BaseDefiningValueResult(I, true);
345 // Base of constant vector consists only of constant null pointers.
346 // For reasoning see similar case inside 'findBaseDefiningValue' function.
347 return BaseDefiningValueResult(ConstantAggregateZero::get(I->getType()),
348 true);
347349
348350 if (isa(I))
349351 return BaseDefiningValueResult(I, true);
385387 // We should have never reached here if this argument isn't an gc value
386388 return BaseDefiningValueResult(I, true);
387389
388 if (isa(I))
390 if (isa(I)) {
389391 // We assume that objects with a constant base (e.g. a global) can't move
390392 // and don't need to be reported to the collector because they are always
391 // live. All constants have constant bases. Besides global references, all
392 // kinds of constants (e.g. undef, constant expressions, null pointers) can
393 // be introduced by the inliner or the optimizer, especially on dynamically
394 // dead paths. See e.g. test4 in constants.ll.
395 return BaseDefiningValueResult(I, true);
393 // live. Besides global references, all kinds of constants (e.g. undef,
394 // constant expressions, null pointers) can be introduced by the inliner or
395 // the optimizer, especially on dynamically dead paths.
396 // Here we treat all of them as having single null base. By doing this we
397 // trying to avoid problems reporting various conflicts in a form of
398 // "phi (const1, const2)" or "phi (const, regular gc ptr)".
399 // See constant.ll file for relevant test cases.
400
401 return BaseDefiningValueResult(
402 ConstantPointerNull::get(cast(I->getType())), true);
403 }
396404
397405 if (CastInst *CI = dyn_cast(I)) {
398406 Value *Def = CI->stripPointerCasts();
0 ; RUN: opt < %s -rewrite-statepoints-for-gc -spp-print-base-pointers -S 2>&1 | FileCheck %s
11
2 ; CHECK: derived %select base @global
2 ; CHECK: derived %select base null
33
44 @global = external addrspace(1) global i8
55
0 ; RUN: opt < %s -rewrite-statepoints-for-gc -spp-print-base-pointers -S 2>&1 | FileCheck %s
11
2 ; CHECK: derived %derived base @global
2 ; CHECK: derived %derived base null
33
44 @global = external addrspace(1) global i8
55
105105 define void @test6(i1 %cnd, i64 addrspace(1)* %obj, i64 %idx) gc "statepoint-example" {
106106 ; CHECK-LABEL: @test6
107107 ; CHECK: %gep = getelementptr i64, i64 addrspace(1)* %obj, i64 1
108 ; CHECK: %vec.base = insertelement <2 x i64 addrspace(1)*> undef, i64 addrspace(1)* %obj, i32 0, !is_base_value !0
108 ; CHECK: %vec.base = insertelement <2 x i64 addrspace(1)*> zeroinitializer, i64 addrspace(1)* %obj, i32 0, !is_base_value !0
109109 ; CHECK: %vec = insertelement <2 x i64 addrspace(1)*> undef, i64 addrspace(1)* %gep, i32 0
110110 ; CHECK: %bdv.base = extractelement <2 x i64 addrspace(1)*> %vec.base, i64 %idx, !is_base_value !0
111111 ; CHECK: %bdv = extractelement <2 x i64 addrspace(1)*> %vec, i64 %idx
116116 call void @foo() [ "deopt"() ]
117117 ret i8 addrspace(1)* %load_addr
118118 }
119
120 define i8 @test8(i8 addrspace(1)* %p) gc "statepoint-example" {
121 ; Checks that base( phi(gep null, oop) ) = phi(null, base(oop)) and that we
122 ; correctly relocate this value
123 ; CHECK-LABEL: @test8
124 entry:
125 %is_null = icmp eq i8 addrspace(1)* %p, null
126 br i1 %is_null, label %null.crit-edge, label %not-null
127
128 not-null:
129 %load_addr = getelementptr inbounds i8, i8 addrspace(1)* %p, i64 8
130 br label %join
131
132 null.crit-edge:
133 %load_addr.const = getelementptr inbounds i8, i8 addrspace(1)* null, i64 8
134 br label %join
135
136 join:
137 %addr = phi i8 addrspace(1)* [ %load_addr, %not-null ], [%load_addr.const, %null.crit-edge]
138 ; CHECK: %addr.base = phi i8 addrspace(1)*
139 ; CHECK-DAG: [ %p, %not-null ]
140 ; CHECK-DAG: [ null, %null.crit-edge ]
141 ; CHECK: gc.statepoint
142 call void @foo() [ "deopt"() ]
143 ; CHECK-DAG: call {{.*}}gc.relocate{{.*}}(%addr.base, %addr.base)
144 ; CHECK-DAG: call {{.*}}gc.relocate{{.*}}(%addr.base, %addr)
145 br i1 %is_null, label %early-exit, label %use
146
147 early-exit:
148 ret i8 0
149
150 use:
151 %res = load i8, i8 addrspace(1)* %addr, align 1
152 ret i8 %res
153 }
154
155 define i8 @test9(i8 addrspace(1)* %p) gc "statepoint-example" {
156 ; Checks that base( phi(inttoptr, oop) ) = phi(null, base(oop)) and that we
157 ; correctly relocate this value
158 ; CHECK-LABEL: @test9
159 entry:
160 %is_null = icmp eq i8 addrspace(1)* %p, null
161 br i1 %is_null, label %null.crit-edge, label %not-null
162
163 not-null:
164 %load_addr = getelementptr inbounds i8, i8 addrspace(1)* %p, i64 8
165 br label %join
166
167 null.crit-edge:
168 br label %join
169
170 join:
171 %addr = phi i8 addrspace(1)* [ %load_addr, %not-null ], [inttoptr (i64 8 to i8 addrspace(1)*), %null.crit-edge]
172 ; CHECK: %addr.base = phi i8 addrspace(1)*
173 ; CHECK-DAG: [ %p, %not-null ]
174 ; CHECK-DAG: [ null, %null.crit-edge ]
175 ; CHECK: gc.statepoint
176 call void @foo() [ "deopt"() ]
177 ; CHECK-DAG: call {{.*}}gc.relocate{{.*}}(%addr.base, %addr.base)
178 ; CHECK-DAG: call {{.*}}gc.relocate{{.*}}(%addr.base, %addr)
179 br i1 %is_null, label %early-exit, label %use
180
181 early-exit:
182 ret i8 0
183
184 use:
185 %res = load i8, i8 addrspace(1)* %addr, align 1
186 ret i8 %res
187 }
188
189 define i8 @test10(i8 addrspace(1)* %p) gc "statepoint-example" {
190 ; Checks that base( phi(const gep, oop) ) = phi(null, base(oop)) and that we
191 ; correctly relocate this value
192 ; CHECK-LABEL: @test10
193 entry:
194 %is_null = icmp eq i8 addrspace(1)* %p, null
195 br i1 %is_null, label %null.crit-edge, label %not-null
196
197 not-null:
198 %load_addr = getelementptr inbounds i8, i8 addrspace(1)* %p, i64 8
199 br label %join
200
201 null.crit-edge:
202 br label %join
203
204 join:
205 %addr = phi i8 addrspace(1)* [ %load_addr, %not-null ], [getelementptr (i8, i8 addrspace(1)* null, i64 8), %null.crit-edge]
206 ; CHECK: %addr.base = phi i8 addrspace(1)*
207 ; CHECK-DAG: [ %p, %not-null ]
208 ; CHECK-DAG: [ null, %null.crit-edge ]
209 ; CHECK: gc.statepoint
210 call void @foo() [ "deopt"() ]
211 ; CHECK-DAG: call {{.*}}gc.relocate{{.*}}(%addr.base, %addr.base)
212 ; CHECK-DAG: call {{.*}}gc.relocate{{.*}}(%addr.base, %addr)
213 br i1 %is_null, label %early-exit, label %use
214
215 early-exit:
216 ret i8 0
217
218 use:
219 %res = load i8, i8 addrspace(1)* %addr, align 1
220 ret i8 %res
221 }
222
223 define i32 addrspace(1)* @test11(i1 %c) gc "statepoint-example" {
224 ; CHECK-LABEL: @test11
225 ; Checks that base( select(const1, const2) ) == null and that we don't record
226 ; such value in the oop map
227 entry:
228 %val = select i1 %c, i32 addrspace(1)* inttoptr (i64 8 to i32 addrspace(1)*), i32 addrspace(1)* inttoptr (i64 15 to i32 addrspace(1)*)
229 ; CHECK: gc.statepoint
230 ; CHECK-NOT: call {{.*}}gc.relocate
231 call void @foo() [ "deopt"() ]
232 ret i32 addrspace(1)* %val
233 }
234
235
236 define <2 x i32 addrspace(1)*> @test12(i1 %c) gc "statepoint-example" {
237 ; CHECK-LABEL: @test12
238 ; Same as test11 but with vectors
239 entry:
240 %val = select i1 %c, <2 x i32 addrspace(1)*>
241 i32 addrspace(1)* inttoptr (i64 15 to i32 addrspace(1)*)>,
242 <2 x i32 addrspace(1)*>
243 i32 addrspace(1)* inttoptr (i64 60 to i32 addrspace(1)*)>
244 ; CHECK: gc.statepoint
245 ; CHECK-NOT: call {{.*}}gc.relocate
246 call void @foo() [ "deopt"() ]
247 ret <2 x i32 addrspace(1)*> %val
248 }
249
250 define <2 x i32 addrspace(1)*> @test13(i1 %c, <2 x i32 addrspace(1)*> %ptr) gc "statepoint-example" {
251 ; CHECK-LABEL: @test13
252 ; Similar to test8, test9 and test10 but with vectors
253 entry:
254 %val = select i1 %c, <2 x i32 addrspace(1)*> %ptr,
255 <2 x i32 addrspace(1)*>
256 ; CHECK: %val.base = select i1 %c, <2 x i32 addrspace(1)*> %ptr, <2 x i32 addrspace(1)*> zeroinitializer, !is_base_value !0
257 ; CHECK: gc.statepoint
258 call void @foo() [ "deopt"() ]
259 ; CHECK-DAG: call {{.*}}gc.relocate{{.*}}(%val.base, %val.base)
260 ; CHECK-DAG: call {{.*}}gc.relocate{{.*}}(%val.base, %val)
261 ret <2 x i32 addrspace(1)*> %val
262 }