blob: 81344b52f6ed076595590ad27e17a8e65fe4ff62 [file] [log] [blame]
xueliang.zhongc239a2b2017-04-27 15:31:37 +01001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "load_store_analysis.h"
18#include "nodes.h"
19#include "optimizing_unit_test.h"
20
21#include "gtest/gtest.h"
22
23namespace art {
24
25class LoadStoreAnalysisTest : public CommonCompilerTest {
26 public:
27 LoadStoreAnalysisTest() : pool_(), allocator_(&pool_) {
28 graph_ = CreateGraph(&allocator_);
29 }
30
31 ArenaPool pool_;
32 ArenaAllocator allocator_;
33 HGraph* graph_;
34};
35
36TEST_F(LoadStoreAnalysisTest, ArrayHeapLocations) {
37 HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
38 graph_->AddBlock(entry);
39 graph_->SetEntryBlock(entry);
40
41 // entry:
42 // array ParameterValue
43 // index ParameterValue
44 // c1 IntConstant
45 // c2 IntConstant
46 // c3 IntConstant
47 // array_get1 ArrayGet [array, c1]
48 // array_get2 ArrayGet [array, c2]
49 // array_set1 ArraySet [array, c1, c3]
50 // array_set2 ArraySet [array, index, c3]
51 HInstruction* array = new (&allocator_) HParameterValue(
52 graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
53 HInstruction* index = new (&allocator_) HParameterValue(
54 graph_->GetDexFile(), dex::TypeIndex(1), 1, Primitive::kPrimInt);
55 HInstruction* c1 = graph_->GetIntConstant(1);
56 HInstruction* c2 = graph_->GetIntConstant(2);
57 HInstruction* c3 = graph_->GetIntConstant(3);
58 HInstruction* array_get1 = new (&allocator_) HArrayGet(array, c1, Primitive::kPrimInt, 0);
59 HInstruction* array_get2 = new (&allocator_) HArrayGet(array, c2, Primitive::kPrimInt, 0);
60 HInstruction* array_set1 = new (&allocator_) HArraySet(array, c1, c3, Primitive::kPrimInt, 0);
61 HInstruction* array_set2 = new (&allocator_) HArraySet(array, index, c3, Primitive::kPrimInt, 0);
62 entry->AddInstruction(array);
63 entry->AddInstruction(index);
64 entry->AddInstruction(array_get1);
65 entry->AddInstruction(array_get2);
66 entry->AddInstruction(array_set1);
67 entry->AddInstruction(array_set2);
68
69 // Test HeapLocationCollector initialization.
70 // Should be no heap locations, no operations on the heap.
71 HeapLocationCollector heap_location_collector(graph_);
72 ASSERT_EQ(heap_location_collector.GetNumberOfHeapLocations(), 0U);
73 ASSERT_FALSE(heap_location_collector.HasHeapStores());
74
75 // Test that after visiting the graph_, it must see following heap locations
76 // array[c1], array[c2], array[index]; and it should see heap stores.
77 heap_location_collector.VisitBasicBlock(entry);
78 ASSERT_EQ(heap_location_collector.GetNumberOfHeapLocations(), 3U);
79 ASSERT_TRUE(heap_location_collector.HasHeapStores());
80
81 // Test queries on HeapLocationCollector's ref info and index records.
82 ReferenceInfo* ref = heap_location_collector.FindReferenceInfoOf(array);
83 size_t field_off = HeapLocation::kInvalidFieldOffset;
84 size_t class_def = HeapLocation::kDeclaringClassDefIndexForArrays;
85 size_t loc1 = heap_location_collector.FindHeapLocationIndex(ref, field_off, c1, class_def);
86 size_t loc2 = heap_location_collector.FindHeapLocationIndex(ref, field_off, c2, class_def);
87 size_t loc3 = heap_location_collector.FindHeapLocationIndex(ref, field_off, index, class_def);
88 // must find this reference info for array in HeapLocationCollector.
89 ASSERT_TRUE(ref != nullptr);
90 // must find these heap locations;
91 // and array[1], array[2], array[3] should be different heap locations.
92 ASSERT_TRUE(loc1 != HeapLocationCollector::kHeapLocationNotFound);
93 ASSERT_TRUE(loc2 != HeapLocationCollector::kHeapLocationNotFound);
94 ASSERT_TRUE(loc3 != HeapLocationCollector::kHeapLocationNotFound);
95 ASSERT_TRUE(loc1 != loc2);
96 ASSERT_TRUE(loc2 != loc3);
97 ASSERT_TRUE(loc1 != loc3);
98
99 // Test alias relationships after building aliasing matrix.
100 // array[1] and array[2] clearly should not alias;
101 // array[index] should alias with the others, because index is an unknow value.
102 heap_location_collector.BuildAliasingMatrix();
103 ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
104 ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc3));
105 ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc3));
106}
107
108TEST_F(LoadStoreAnalysisTest, FieldHeapLocations) {
109 HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
110 graph_->AddBlock(entry);
111 graph_->SetEntryBlock(entry);
112
113 // entry:
114 // object ParameterValue
115 // c1 IntConstant
116 // set_field10 InstanceFieldSet [object, c1, 10]
117 // get_field10 InstanceFieldGet [object, 10]
118 // get_field20 InstanceFieldGet [object, 20]
119
120 HInstruction* c1 = graph_->GetIntConstant(1);
121 HInstruction* object = new (&allocator_) HParameterValue(graph_->GetDexFile(),
122 dex::TypeIndex(0),
123 0,
124 Primitive::kPrimNot);
125 HInstanceFieldSet* set_field10 = new (&allocator_) HInstanceFieldSet(object,
126 c1,
127 nullptr,
128 Primitive::kPrimInt,
129 MemberOffset(10),
130 false,
131 kUnknownFieldIndex,
132 kUnknownClassDefIndex,
133 graph_->GetDexFile(),
134 0);
135 HInstanceFieldGet* get_field10 = new (&allocator_) HInstanceFieldGet(object,
136 nullptr,
137 Primitive::kPrimInt,
138 MemberOffset(10),
139 false,
140 kUnknownFieldIndex,
141 kUnknownClassDefIndex,
142 graph_->GetDexFile(),
143 0);
144 HInstanceFieldGet* get_field20 = new (&allocator_) HInstanceFieldGet(object,
145 nullptr,
146 Primitive::kPrimInt,
147 MemberOffset(20),
148 false,
149 kUnknownFieldIndex,
150 kUnknownClassDefIndex,
151 graph_->GetDexFile(),
152 0);
153 entry->AddInstruction(object);
154 entry->AddInstruction(set_field10);
155 entry->AddInstruction(get_field10);
156 entry->AddInstruction(get_field20);
157
158 // Test HeapLocationCollector initialization.
159 // Should be no heap locations, no operations on the heap.
160 HeapLocationCollector heap_location_collector(graph_);
161 ASSERT_EQ(heap_location_collector.GetNumberOfHeapLocations(), 0U);
162 ASSERT_FALSE(heap_location_collector.HasHeapStores());
163
164 // Test that after visiting the graph, it must see following heap locations
165 // object.field10, object.field20 and it should see heap stores.
166 heap_location_collector.VisitBasicBlock(entry);
167 ASSERT_EQ(heap_location_collector.GetNumberOfHeapLocations(), 2U);
168 ASSERT_TRUE(heap_location_collector.HasHeapStores());
169
170 // Test queries on HeapLocationCollector's ref info and index records.
171 ReferenceInfo* ref = heap_location_collector.FindReferenceInfoOf(object);
172 size_t loc1 = heap_location_collector.FindHeapLocationIndex(
173 ref, 10, nullptr, kUnknownClassDefIndex);
174 size_t loc2 = heap_location_collector.FindHeapLocationIndex(
175 ref, 20, nullptr, kUnknownClassDefIndex);
176 // must find references info for object and in HeapLocationCollector.
177 ASSERT_TRUE(ref != nullptr);
178 // must find these heap locations.
179 ASSERT_TRUE(loc1 != HeapLocationCollector::kHeapLocationNotFound);
180 ASSERT_TRUE(loc2 != HeapLocationCollector::kHeapLocationNotFound);
181 // different fields of same object.
182 ASSERT_TRUE(loc1 != loc2);
183 // accesses to different fields of the same object should not alias.
184 ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
185}
186
xueliang.zhong016c0f12017-05-12 18:16:31 +0100187TEST_F(LoadStoreAnalysisTest, ArrayIndexAliasingTest) {
188 HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
189 graph_->AddBlock(entry);
190 graph_->SetEntryBlock(entry);
191 graph_->BuildDominatorTree();
192
193 HInstruction* array = new (&allocator_) HParameterValue(
194 graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
195 HInstruction* index = new (&allocator_) HParameterValue(
196 graph_->GetDexFile(), dex::TypeIndex(1), 1, Primitive::kPrimInt);
197 HInstruction* c0 = graph_->GetIntConstant(0);
198 HInstruction* c1 = graph_->GetIntConstant(1);
199 HInstruction* c_neg1 = graph_->GetIntConstant(-1);
200 HInstruction* add0 = new (&allocator_) HAdd(Primitive::kPrimInt, index, c0);
201 HInstruction* add1 = new (&allocator_) HAdd(Primitive::kPrimInt, index, c1);
202 HInstruction* sub0 = new (&allocator_) HSub(Primitive::kPrimInt, index, c0);
203 HInstruction* sub1 = new (&allocator_) HSub(Primitive::kPrimInt, index, c1);
204 HInstruction* sub_neg1 = new (&allocator_) HSub(Primitive::kPrimInt, index, c_neg1);
205 HInstruction* rev_sub1 = new (&allocator_) HSub(Primitive::kPrimInt, c1, index);
206 HInstruction* arr_set1 = new (&allocator_) HArraySet(array, c0, c0, Primitive::kPrimInt, 0);
207 HInstruction* arr_set2 = new (&allocator_) HArraySet(array, c1, c0, Primitive::kPrimInt, 0);
208 HInstruction* arr_set3 = new (&allocator_) HArraySet(array, add0, c0, Primitive::kPrimInt, 0);
209 HInstruction* arr_set4 = new (&allocator_) HArraySet(array, add1, c0, Primitive::kPrimInt, 0);
210 HInstruction* arr_set5 = new (&allocator_) HArraySet(array, sub0, c0, Primitive::kPrimInt, 0);
211 HInstruction* arr_set6 = new (&allocator_) HArraySet(array, sub1, c0, Primitive::kPrimInt, 0);
212 HInstruction* arr_set7 = new (&allocator_) HArraySet(array, rev_sub1, c0, Primitive::kPrimInt, 0);
213 HInstruction* arr_set8 = new (&allocator_) HArraySet(array, sub_neg1, c0, Primitive::kPrimInt, 0);
214
215 entry->AddInstruction(array);
216 entry->AddInstruction(index);
217 entry->AddInstruction(add0);
218 entry->AddInstruction(add1);
219 entry->AddInstruction(sub0);
220 entry->AddInstruction(sub1);
221 entry->AddInstruction(sub_neg1);
222 entry->AddInstruction(rev_sub1);
223
224 entry->AddInstruction(arr_set1); // array[0] = c0
225 entry->AddInstruction(arr_set2); // array[1] = c0
226 entry->AddInstruction(arr_set3); // array[i+0] = c0
227 entry->AddInstruction(arr_set4); // array[i+1] = c0
228 entry->AddInstruction(arr_set5); // array[i-0] = c0
229 entry->AddInstruction(arr_set6); // array[i-1] = c0
230 entry->AddInstruction(arr_set7); // array[1-i] = c0
231 entry->AddInstruction(arr_set8); // array[i-(-1)] = c0
232
233 LoadStoreAnalysis lsa(graph_);
234 lsa.Run();
235 const HeapLocationCollector& heap_location_collector = lsa.GetHeapLocationCollector();
236
237 // LSA/HeapLocationCollector should see those ArrayGet instructions.
238 ASSERT_EQ(heap_location_collector.GetNumberOfHeapLocations(), 8U);
239 ASSERT_TRUE(heap_location_collector.HasHeapStores());
240
241 // Test queries on HeapLocationCollector's aliasing matrix after load store analysis.
242 size_t loc1 = HeapLocationCollector::kHeapLocationNotFound;
243 size_t loc2 = HeapLocationCollector::kHeapLocationNotFound;
244
245 // Test alias: array[0] and array[1]
246 loc1 = heap_location_collector.GetArrayAccessHeapLocation(array, c0);
247 loc2 = heap_location_collector.GetArrayAccessHeapLocation(array, c1);
248 ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
249
250 // Test alias: array[i+0] and array[i-0]
251 loc1 = heap_location_collector.GetArrayAccessHeapLocation(array, add0);
252 loc2 = heap_location_collector.GetArrayAccessHeapLocation(array, sub0);
253 ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
254
255 // Test alias: array[i+1] and array[i-1]
256 loc1 = heap_location_collector.GetArrayAccessHeapLocation(array, add1);
257 loc2 = heap_location_collector.GetArrayAccessHeapLocation(array, sub1);
258 ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
259
260 // Test alias: array[i+1] and array[1-i]
261 loc1 = heap_location_collector.GetArrayAccessHeapLocation(array, add1);
262 loc2 = heap_location_collector.GetArrayAccessHeapLocation(array, rev_sub1);
263 ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
264
265 // Test alias: array[i+1] and array[i-(-1)]
266 loc1 = heap_location_collector.GetArrayAccessHeapLocation(array, add1);
267 loc2 = heap_location_collector.GetArrayAccessHeapLocation(array, sub_neg1);
268 ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
269}
270
271TEST_F(LoadStoreAnalysisTest, ArrayIndexCalculationOverflowTest) {
272 HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
273 graph_->AddBlock(entry);
274 graph_->SetEntryBlock(entry);
275 graph_->BuildDominatorTree();
276
277 HInstruction* array = new (&allocator_) HParameterValue(
278 graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
279 HInstruction* index = new (&allocator_) HParameterValue(
280 graph_->GetDexFile(), dex::TypeIndex(1), 1, Primitive::kPrimInt);
281
282 HInstruction* c0 = graph_->GetIntConstant(0);
283 HInstruction* c_0x80000000 = graph_->GetIntConstant(0x80000000);
284 HInstruction* c_0x10 = graph_->GetIntConstant(0x10);
285 HInstruction* c_0xFFFFFFF0 = graph_->GetIntConstant(0xFFFFFFF0);
286 HInstruction* c_0x7FFFFFFF = graph_->GetIntConstant(0x7FFFFFFF);
287 HInstruction* c_0x80000001 = graph_->GetIntConstant(0x80000001);
288
289 // `index+0x80000000` and `index-0x80000000` array indices MAY alias.
290 HInstruction* add_0x80000000 = new (&allocator_) HAdd(Primitive::kPrimInt, index, c_0x80000000);
291 HInstruction* sub_0x80000000 = new (&allocator_) HSub(Primitive::kPrimInt, index, c_0x80000000);
292 HInstruction* arr_set_1 = new (&allocator_) HArraySet(
293 array, add_0x80000000, c0, Primitive::kPrimInt, 0);
294 HInstruction* arr_set_2 = new (&allocator_) HArraySet(
295 array, sub_0x80000000, c0, Primitive::kPrimInt, 0);
296
297 // `index+0x10` and `index-0xFFFFFFF0` array indices MAY alias.
298 HInstruction* add_0x10 = new (&allocator_) HAdd(Primitive::kPrimInt, index, c_0x10);
299 HInstruction* sub_0xFFFFFFF0 = new (&allocator_) HSub(Primitive::kPrimInt, index, c_0xFFFFFFF0);
300 HInstruction* arr_set_3 = new (&allocator_) HArraySet(
301 array, add_0x10, c0, Primitive::kPrimInt, 0);
302 HInstruction* arr_set_4 = new (&allocator_) HArraySet(
303 array, sub_0xFFFFFFF0, c0, Primitive::kPrimInt, 0);
304
305 // `index+0x7FFFFFFF` and `index-0x80000001` array indices MAY alias.
306 HInstruction* add_0x7FFFFFFF = new (&allocator_) HAdd(Primitive::kPrimInt, index, c_0x7FFFFFFF);
307 HInstruction* sub_0x80000001 = new (&allocator_) HSub(Primitive::kPrimInt, index, c_0x80000001);
308 HInstruction* arr_set_5 = new (&allocator_) HArraySet(
309 array, add_0x7FFFFFFF, c0, Primitive::kPrimInt, 0);
310 HInstruction* arr_set_6 = new (&allocator_) HArraySet(
311 array, sub_0x80000001, c0, Primitive::kPrimInt, 0);
312
313 // `index+0` and `index-0` array indices MAY alias.
314 HInstruction* add_0 = new (&allocator_) HAdd(Primitive::kPrimInt, index, c0);
315 HInstruction* sub_0 = new (&allocator_) HSub(Primitive::kPrimInt, index, c0);
316 HInstruction* arr_set_7 = new (&allocator_) HArraySet(array, add_0, c0, Primitive::kPrimInt, 0);
317 HInstruction* arr_set_8 = new (&allocator_) HArraySet(array, sub_0, c0, Primitive::kPrimInt, 0);
318
319 entry->AddInstruction(array);
320 entry->AddInstruction(index);
321 entry->AddInstruction(add_0x80000000);
322 entry->AddInstruction(sub_0x80000000);
323 entry->AddInstruction(add_0x10);
324 entry->AddInstruction(sub_0xFFFFFFF0);
325 entry->AddInstruction(add_0x7FFFFFFF);
326 entry->AddInstruction(sub_0x80000001);
327 entry->AddInstruction(add_0);
328 entry->AddInstruction(sub_0);
329 entry->AddInstruction(arr_set_1);
330 entry->AddInstruction(arr_set_2);
331 entry->AddInstruction(arr_set_3);
332 entry->AddInstruction(arr_set_4);
333 entry->AddInstruction(arr_set_5);
334 entry->AddInstruction(arr_set_6);
335 entry->AddInstruction(arr_set_7);
336 entry->AddInstruction(arr_set_8);
337
338 LoadStoreAnalysis lsa(graph_);
339 lsa.Run();
340 const HeapLocationCollector& heap_location_collector = lsa.GetHeapLocationCollector();
341
342 // LSA/HeapLocationCollector should see those ArrayGet instructions.
343 ASSERT_EQ(heap_location_collector.GetNumberOfHeapLocations(), 8U);
344 ASSERT_TRUE(heap_location_collector.HasHeapStores());
345
346 // Test queries on HeapLocationCollector's aliasing matrix after load store analysis.
347 size_t loc1 = HeapLocationCollector::kHeapLocationNotFound;
348 size_t loc2 = HeapLocationCollector::kHeapLocationNotFound;
349
350 // Test alias: array[i+0x80000000] and array[i-0x80000000]
351 loc1 = heap_location_collector.GetArrayAccessHeapLocation(array, add_0x80000000);
352 loc2 = heap_location_collector.GetArrayAccessHeapLocation(array, sub_0x80000000);
353 ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
354
355 // Test alias: array[i+0x10] and array[i-0xFFFFFFF0]
356 loc1 = heap_location_collector.GetArrayAccessHeapLocation(array, add_0x10);
357 loc2 = heap_location_collector.GetArrayAccessHeapLocation(array, sub_0xFFFFFFF0);
358 ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
359
360 // Test alias: array[i+0x7FFFFFFF] and array[i-0x80000001]
361 loc1 = heap_location_collector.GetArrayAccessHeapLocation(array, add_0x7FFFFFFF);
362 loc2 = heap_location_collector.GetArrayAccessHeapLocation(array, sub_0x80000001);
363 ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
364
365 // Test alias: array[i+0] and array[i-0]
366 loc1 = heap_location_collector.GetArrayAccessHeapLocation(array, add_0);
367 loc2 = heap_location_collector.GetArrayAccessHeapLocation(array, sub_0);
368 ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
369
370 // Should not alias:
371 loc1 = heap_location_collector.GetArrayAccessHeapLocation(array, sub_0x80000000);
372 loc2 = heap_location_collector.GetArrayAccessHeapLocation(array, sub_0x80000001);
373 ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
374
375 // Should not alias:
376 loc1 = heap_location_collector.GetArrayAccessHeapLocation(array, add_0);
377 loc2 = heap_location_collector.GetArrayAccessHeapLocation(array, sub_0x80000000);
378 ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
379}
380
xueliang.zhongc239a2b2017-04-27 15:31:37 +0100381} // namespace art