1 /*
2 * Copyright (C) 2015 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_elimination.h"
18
19 #include "base/array_ref.h"
20 #include "base/scoped_arena_allocator.h"
21 #include "base/scoped_arena_containers.h"
22 #include "escape.h"
23 #include "load_store_analysis.h"
24 #include "side_effects_analysis.h"
25
26 /**
27 * The general algorithm of load-store elimination (LSE).
28 * Load-store analysis in the previous pass collects a list of heap locations
29 * and does alias analysis of those heap locations.
30 * LSE keeps track of a list of heap values corresponding to the heap
31 * locations. It visits basic blocks in reverse post order and for
32 * each basic block, visits instructions sequentially, and processes
33 * instructions as follows:
34 * - If the instruction is a load, and the heap location for that load has a
35 * valid heap value, the load can be eliminated. In order to maintain the
36 * validity of all heap locations during the optimization phase, the real
37 * elimination is delayed till the end of LSE.
38 * - If the instruction is a store, it updates the heap value for the heap
39 * location of the store with the store instruction. The real heap value
40 * can be fetched from the store instruction. Heap values are invalidated
41 * for heap locations that may alias with the store instruction's heap
42 * location. The store instruction can be eliminated unless the value stored
43 * is later needed e.g. by a load from the same/aliased heap location or
44 * the heap location persists at method return/deoptimization.
45 * The store instruction is also needed if it's not used to track the heap
46 * value anymore, e.g. when it fails to merge with the heap values from other
47 * predecessors.
48 * - A store that stores the same value as the heap value is eliminated.
49 * - The list of heap values are merged at basic block entry from the basic
50 * block's predecessors. The algorithm is single-pass, so loop side-effects is
51 * used as best effort to decide if a heap location is stored inside the loop.
52 * - A special type of objects called singletons are instantiated in the method
53 * and have a single name, i.e. no aliases. Singletons have exclusive heap
54 * locations since they have no aliases. Singletons are helpful in narrowing
55 * down the life span of a heap location such that they do not always
56 * need to participate in merging heap values. Allocation of a singleton
57 * can be eliminated if that singleton is not used and does not persist
58 * at method return/deoptimization.
59 * - For newly instantiated instances, their heap values are initialized to
60 * language defined default values.
61 * - Some instructions such as invokes are treated as loading and invalidating
62 * all the heap values, depending on the instruction's side effects.
63 * - Finalizable objects are considered as persisting at method
64 * return/deoptimization.
65 * - SIMD graphs (with VecLoad and VecStore instructions) are also handled. Any
66 * partial overlap access among ArrayGet/ArraySet/VecLoad/Store is seen as
67 * alias and no load/store is eliminated in such case.
68 * - Currently this LSE algorithm doesn't handle graph with try-catch, due to
69 * the special block merging structure.
70 */
71
72 namespace art {
73
74 // An unknown heap value. Loads with such a value in the heap location cannot be eliminated.
75 // A heap location can be set to kUnknownHeapValue when:
76 // - initially set a value.
77 // - killed due to aliasing, merging, invocation, or loop side effects.
78 static HInstruction* const kUnknownHeapValue =
79 reinterpret_cast<HInstruction*>(static_cast<uintptr_t>(-1));
80
81 // Default heap value after an allocation.
82 // A heap location can be set to that value right after an allocation.
83 static HInstruction* const kDefaultHeapValue =
84 reinterpret_cast<HInstruction*>(static_cast<uintptr_t>(-2));
85
86 // Use HGraphDelegateVisitor for which all VisitInvokeXXX() delegate to VisitInvoke().
87 class LSEVisitor : public HGraphDelegateVisitor {
88 public:
LSEVisitor(HGraph * graph,const HeapLocationCollector & heap_locations_collector,const SideEffectsAnalysis & side_effects,OptimizingCompilerStats * stats)89 LSEVisitor(HGraph* graph,
90 const HeapLocationCollector& heap_locations_collector,
91 const SideEffectsAnalysis& side_effects,
92 OptimizingCompilerStats* stats)
93 : HGraphDelegateVisitor(graph, stats),
94 heap_location_collector_(heap_locations_collector),
95 side_effects_(side_effects),
96 allocator_(graph->GetArenaStack()),
97 heap_values_for_(graph->GetBlocks().size(),
98 ScopedArenaVector<HInstruction*>(heap_locations_collector.
99 GetNumberOfHeapLocations(),
100 kUnknownHeapValue,
101 allocator_.Adapter(kArenaAllocLSE)),
102 allocator_.Adapter(kArenaAllocLSE)),
103 removed_loads_(allocator_.Adapter(kArenaAllocLSE)),
104 substitute_instructions_for_loads_(allocator_.Adapter(kArenaAllocLSE)),
105 possibly_removed_stores_(allocator_.Adapter(kArenaAllocLSE)),
106 singleton_new_instances_(allocator_.Adapter(kArenaAllocLSE)) {
107 }
108
VisitBasicBlock(HBasicBlock * block)109 void VisitBasicBlock(HBasicBlock* block) override {
110 // Populate the heap_values array for this block.
111 // TODO: try to reuse the heap_values array from one predecessor if possible.
112 if (block->IsLoopHeader()) {
113 HandleLoopSideEffects(block);
114 } else {
115 MergePredecessorValues(block);
116 }
117 HGraphVisitor::VisitBasicBlock(block);
118 }
119
AddTypeConversionIfNecessary(HInstruction * instruction,HInstruction * value,DataType::Type expected_type)120 HTypeConversion* AddTypeConversionIfNecessary(HInstruction* instruction,
121 HInstruction* value,
122 DataType::Type expected_type) {
123 HTypeConversion* type_conversion = nullptr;
124 // Should never add type conversion into boolean value.
125 if (expected_type != DataType::Type::kBool &&
126 !DataType::IsTypeConversionImplicit(value->GetType(), expected_type)) {
127 type_conversion = new (GetGraph()->GetAllocator()) HTypeConversion(
128 expected_type, value, instruction->GetDexPc());
129 instruction->GetBlock()->InsertInstructionBefore(type_conversion, instruction);
130 }
131 return type_conversion;
132 }
133
134 // Find an instruction's substitute if it's a removed load.
135 // Return the same instruction if it should not be removed.
FindSubstitute(HInstruction * instruction)136 HInstruction* FindSubstitute(HInstruction* instruction) {
137 if (!IsLoad(instruction)) {
138 return instruction;
139 }
140 size_t size = removed_loads_.size();
141 for (size_t i = 0; i < size; i++) {
142 if (removed_loads_[i] == instruction) {
143 HInstruction* substitute = substitute_instructions_for_loads_[i];
144 // The substitute list is a flat hierarchy.
145 DCHECK_EQ(FindSubstitute(substitute), substitute);
146 return substitute;
147 }
148 }
149 return instruction;
150 }
151
AddRemovedLoad(HInstruction * load,HInstruction * heap_value)152 void AddRemovedLoad(HInstruction* load, HInstruction* heap_value) {
153 DCHECK(IsLoad(load));
154 DCHECK_EQ(FindSubstitute(heap_value), heap_value) <<
155 "Unexpected heap_value that has a substitute " << heap_value->DebugName();
156 removed_loads_.push_back(load);
157 substitute_instructions_for_loads_.push_back(heap_value);
158 }
159
160 // Scan the list of removed loads to see if we can reuse `type_conversion`, if
161 // the other removed load has the same substitute and type and is dominated
162 // by `type_conversion`.
TryToReuseTypeConversion(HInstruction * type_conversion,size_t index)163 void TryToReuseTypeConversion(HInstruction* type_conversion, size_t index) {
164 size_t size = removed_loads_.size();
165 HInstruction* load = removed_loads_[index];
166 HInstruction* substitute = substitute_instructions_for_loads_[index];
167 for (size_t j = index + 1; j < size; j++) {
168 HInstruction* load2 = removed_loads_[j];
169 HInstruction* substitute2 = substitute_instructions_for_loads_[j];
170 if (load2 == nullptr) {
171 DCHECK(substitute2->IsTypeConversion());
172 continue;
173 }
174 DCHECK(IsLoad(load2));
175 DCHECK(substitute2 != nullptr);
176 if (substitute2 == substitute &&
177 load2->GetType() == load->GetType() &&
178 type_conversion->GetBlock()->Dominates(load2->GetBlock()) &&
179 // Don't share across irreducible loop headers.
180 // TODO: can be more fine-grained than this by testing each dominator.
181 (load2->GetBlock() == type_conversion->GetBlock() ||
182 !GetGraph()->HasIrreducibleLoops())) {
183 // The removed_loads_ are added in reverse post order.
184 DCHECK(type_conversion->StrictlyDominates(load2));
185 load2->ReplaceWith(type_conversion);
186 load2->GetBlock()->RemoveInstruction(load2);
187 removed_loads_[j] = nullptr;
188 substitute_instructions_for_loads_[j] = type_conversion;
189 }
190 }
191 }
192
193 // Remove recorded instructions that should be eliminated.
RemoveInstructions()194 void RemoveInstructions() {
195 size_t size = removed_loads_.size();
196 DCHECK_EQ(size, substitute_instructions_for_loads_.size());
197 for (size_t i = 0; i < size; i++) {
198 HInstruction* load = removed_loads_[i];
199 if (load == nullptr) {
200 // The load has been handled in the scan for type conversion below.
201 DCHECK(substitute_instructions_for_loads_[i]->IsTypeConversion());
202 continue;
203 }
204 DCHECK(IsLoad(load));
205 HInstruction* substitute = substitute_instructions_for_loads_[i];
206 DCHECK(substitute != nullptr);
207 // We proactively retrieve the substitute for a removed load, so
208 // a load that has a substitute should not be observed as a heap
209 // location value.
210 DCHECK_EQ(FindSubstitute(substitute), substitute);
211
212 // The load expects to load the heap value as type load->GetType().
213 // However the tracked heap value may not be of that type. An explicit
214 // type conversion may be needed.
215 // There are actually three types involved here:
216 // (1) tracked heap value's type (type A)
217 // (2) heap location (field or element)'s type (type B)
218 // (3) load's type (type C)
219 // We guarantee that type A stored as type B and then fetched out as
220 // type C is the same as casting from type A to type C directly, since
221 // type B and type C will have the same size which is guarenteed in
222 // HInstanceFieldGet/HStaticFieldGet/HArrayGet/HVecLoad's SetType().
223 // So we only need one type conversion from type A to type C.
224 HTypeConversion* type_conversion = AddTypeConversionIfNecessary(
225 load, substitute, load->GetType());
226 if (type_conversion != nullptr) {
227 TryToReuseTypeConversion(type_conversion, i);
228 load->ReplaceWith(type_conversion);
229 substitute_instructions_for_loads_[i] = type_conversion;
230 } else {
231 load->ReplaceWith(substitute);
232 }
233 load->GetBlock()->RemoveInstruction(load);
234 }
235
236 // At this point, stores in possibly_removed_stores_ can be safely removed.
237 for (HInstruction* store : possibly_removed_stores_) {
238 DCHECK(IsStore(store));
239 store->GetBlock()->RemoveInstruction(store);
240 }
241
242 // Eliminate singleton-classified instructions:
243 // * - Constructor fences (they never escape this thread).
244 // * - Allocations (if they are unused).
245 for (HInstruction* new_instance : singleton_new_instances_) {
246 size_t removed = HConstructorFence::RemoveConstructorFences(new_instance);
247 MaybeRecordStat(stats_,
248 MethodCompilationStat::kConstructorFenceRemovedLSE,
249 removed);
250
251 if (!new_instance->HasNonEnvironmentUses()) {
252 new_instance->RemoveEnvironmentUsers();
253 new_instance->GetBlock()->RemoveInstruction(new_instance);
254 }
255 }
256 }
257
258 private:
IsLoad(const HInstruction * instruction)259 static bool IsLoad(const HInstruction* instruction) {
260 if (instruction == kUnknownHeapValue || instruction == kDefaultHeapValue) {
261 return false;
262 }
263 // Unresolved load is not treated as a load.
264 return instruction->IsInstanceFieldGet() ||
265 instruction->IsStaticFieldGet() ||
266 instruction->IsVecLoad() ||
267 instruction->IsArrayGet();
268 }
269
IsStore(const HInstruction * instruction)270 static bool IsStore(const HInstruction* instruction) {
271 if (instruction == kUnknownHeapValue || instruction == kDefaultHeapValue) {
272 return false;
273 }
274 // Unresolved store is not treated as a store.
275 return instruction->IsInstanceFieldSet() ||
276 instruction->IsArraySet() ||
277 instruction->IsVecStore() ||
278 instruction->IsStaticFieldSet();
279 }
280
281 // Check if it is allowed to use default values for the specified load.
IsDefaultAllowedForLoad(const HInstruction * load)282 static bool IsDefaultAllowedForLoad(const HInstruction* load) {
283 DCHECK(IsLoad(load));
284 // Using defaults for VecLoads requires to create additional vector operations.
285 // As there are some issues with scheduling vector operations it is better to avoid creating
286 // them.
287 return !load->IsVecOperation();
288 }
289
290 // Returns the real heap value by finding its substitute or by "peeling"
291 // a store instruction.
GetRealHeapValue(HInstruction * heap_value)292 HInstruction* GetRealHeapValue(HInstruction* heap_value) {
293 if (IsLoad(heap_value)) {
294 return FindSubstitute(heap_value);
295 }
296 if (!IsStore(heap_value)) {
297 return heap_value;
298 }
299
300 // We keep track of store instructions as the heap values which might be
301 // eliminated if the stores are later found not necessary. The real stored
302 // value needs to be fetched from the store instruction.
303 if (heap_value->IsInstanceFieldSet()) {
304 heap_value = heap_value->AsInstanceFieldSet()->GetValue();
305 } else if (heap_value->IsStaticFieldSet()) {
306 heap_value = heap_value->AsStaticFieldSet()->GetValue();
307 } else if (heap_value->IsVecStore()) {
308 heap_value = heap_value->AsVecStore()->GetValue();
309 } else {
310 DCHECK(heap_value->IsArraySet());
311 heap_value = heap_value->AsArraySet()->GetValue();
312 }
313 // heap_value may already be a removed load.
314 return FindSubstitute(heap_value);
315 }
316
317 // If heap_value is a store, need to keep the store.
318 // This is necessary if a heap value is killed or replaced by another value,
319 // so that the store is no longer used to track heap value.
KeepIfIsStore(HInstruction * heap_value)320 void KeepIfIsStore(HInstruction* heap_value) {
321 if (!IsStore(heap_value)) {
322 return;
323 }
324 auto idx = std::find(possibly_removed_stores_.begin(),
325 possibly_removed_stores_.end(), heap_value);
326 if (idx != possibly_removed_stores_.end()) {
327 // Make sure the store is kept.
328 possibly_removed_stores_.erase(idx);
329 }
330 }
331
332 // If a heap location X may alias with heap location at `loc_index`
333 // and heap_values of that heap location X holds a store, keep that store.
334 // It's needed for a dependent load that's not eliminated since any store
335 // that may put value into the load's heap location needs to be kept.
KeepStoresIfAliasedToLocation(ScopedArenaVector<HInstruction * > & heap_values,size_t loc_index)336 void KeepStoresIfAliasedToLocation(ScopedArenaVector<HInstruction*>& heap_values,
337 size_t loc_index) {
338 for (size_t i = 0; i < heap_values.size(); i++) {
339 if ((i == loc_index) || heap_location_collector_.MayAlias(i, loc_index)) {
340 KeepIfIsStore(heap_values[i]);
341 }
342 }
343 }
344
HandleLoopSideEffects(HBasicBlock * block)345 void HandleLoopSideEffects(HBasicBlock* block) {
346 DCHECK(block->IsLoopHeader());
347 int block_id = block->GetBlockId();
348 ScopedArenaVector<HInstruction*>& heap_values = heap_values_for_[block_id];
349 HBasicBlock* pre_header = block->GetLoopInformation()->GetPreHeader();
350 ScopedArenaVector<HInstruction*>& pre_header_heap_values =
351 heap_values_for_[pre_header->GetBlockId()];
352
353 // Don't eliminate loads in irreducible loops.
354 // Also keep the stores before the loop.
355 if (block->GetLoopInformation()->IsIrreducible()) {
356 if (kIsDebugBuild) {
357 for (size_t i = 0; i < heap_values.size(); i++) {
358 DCHECK_EQ(heap_values[i], kUnknownHeapValue);
359 }
360 }
361 for (size_t i = 0; i < heap_values.size(); i++) {
362 KeepIfIsStore(pre_header_heap_values[i]);
363 }
364 return;
365 }
366
367 // Inherit the values from pre-header.
368 for (size_t i = 0; i < heap_values.size(); i++) {
369 heap_values[i] = pre_header_heap_values[i];
370 }
371
372 // We do a single pass in reverse post order. For loops, use the side effects as a hint
373 // to see if the heap values should be killed.
374 if (side_effects_.GetLoopEffects(block).DoesAnyWrite()) {
375 for (size_t i = 0; i < heap_values.size(); i++) {
376 HeapLocation* location = heap_location_collector_.GetHeapLocation(i);
377 ReferenceInfo* ref_info = location->GetReferenceInfo();
378 if (ref_info->IsSingleton() && !location->IsValueKilledByLoopSideEffects()) {
379 // A singleton's field that's not stored into inside a loop is
380 // invariant throughout the loop. Nothing to do.
381 } else {
382 // heap value is killed by loop side effects.
383 KeepIfIsStore(pre_header_heap_values[i]);
384 heap_values[i] = kUnknownHeapValue;
385 }
386 }
387 } else {
388 // The loop doesn't kill any value.
389 }
390 }
391
MergePredecessorValues(HBasicBlock * block)392 void MergePredecessorValues(HBasicBlock* block) {
393 ArrayRef<HBasicBlock* const> predecessors(block->GetPredecessors());
394 if (predecessors.size() == 0) {
395 return;
396 }
397 if (block->IsExitBlock()) {
398 // Exit block doesn't really merge values since the control flow ends in
399 // its predecessors. Each predecessor needs to make sure stores are kept
400 // if necessary.
401 return;
402 }
403
404 ScopedArenaVector<HInstruction*>& heap_values = heap_values_for_[block->GetBlockId()];
405 for (size_t i = 0; i < heap_values.size(); i++) {
406 HInstruction* merged_value = nullptr;
407 // If we can merge the store itself from the predecessors, we keep
408 // the store as the heap value as long as possible. In case we cannot
409 // merge the store, we try to merge the values of the stores.
410 HInstruction* merged_store_value = nullptr;
411 // Whether merged_value is a result that's merged from all predecessors.
412 bool from_all_predecessors = true;
413 ReferenceInfo* ref_info = heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo();
414 HInstruction* ref = ref_info->GetReference();
415 HInstruction* singleton_ref = nullptr;
416 if (ref_info->IsSingleton()) {
417 // We do more analysis based on singleton's liveness when merging
418 // heap values for such cases.
419 singleton_ref = ref;
420 }
421
422 for (HBasicBlock* predecessor : predecessors) {
423 HInstruction* pred_value = heap_values_for_[predecessor->GetBlockId()][i];
424 if (!IsStore(pred_value)) {
425 pred_value = FindSubstitute(pred_value);
426 }
427 DCHECK(pred_value != nullptr);
428 HInstruction* pred_store_value = GetRealHeapValue(pred_value);
429 if ((singleton_ref != nullptr) &&
430 !singleton_ref->GetBlock()->Dominates(predecessor)) {
431 // singleton_ref is not live in this predecessor. No need to merge
432 // since singleton_ref is not live at the beginning of this block.
433 DCHECK_EQ(pred_value, kUnknownHeapValue);
434 from_all_predecessors = false;
435 break;
436 }
437 if (merged_value == nullptr) {
438 // First seen heap value.
439 DCHECK(pred_value != nullptr);
440 merged_value = pred_value;
441 } else if (pred_value != merged_value) {
442 // There are conflicting values.
443 merged_value = kUnknownHeapValue;
444 // We may still be able to merge store values.
445 }
446
447 // Conflicting stores may be storing the same value. We do another merge
448 // of real stored values.
449 if (merged_store_value == nullptr) {
450 // First seen store value.
451 DCHECK(pred_store_value != nullptr);
452 merged_store_value = pred_store_value;
453 } else if (pred_store_value != merged_store_value) {
454 // There are conflicting store values.
455 merged_store_value = kUnknownHeapValue;
456 // There must be conflicting stores also.
457 DCHECK_EQ(merged_value, kUnknownHeapValue);
458 // No need to merge anymore.
459 break;
460 }
461 }
462
463 if (merged_value == nullptr) {
464 DCHECK(!from_all_predecessors);
465 DCHECK(singleton_ref != nullptr);
466 }
467 if (from_all_predecessors) {
468 if (ref_info->IsSingletonAndRemovable() &&
469 (block->IsSingleReturnOrReturnVoidAllowingPhis() ||
470 (block->EndsWithReturn() && (merged_value != kUnknownHeapValue ||
471 merged_store_value != kUnknownHeapValue)))) {
472 // Values in the singleton are not needed anymore:
473 // (1) if this block consists of a sole return, or
474 // (2) if this block returns and a usable merged value is obtained
475 // (loads prior to the return will always use that value).
476 } else if (!IsStore(merged_value)) {
477 // We don't track merged value as a store anymore. We have to
478 // hold the stores in predecessors live here.
479 for (HBasicBlock* predecessor : predecessors) {
480 ScopedArenaVector<HInstruction*>& pred_values =
481 heap_values_for_[predecessor->GetBlockId()];
482 KeepIfIsStore(pred_values[i]);
483 }
484 }
485 } else {
486 DCHECK(singleton_ref != nullptr);
487 // singleton_ref is non-existing at the beginning of the block. There is
488 // no need to keep the stores.
489 }
490
491 if (!from_all_predecessors) {
492 DCHECK(singleton_ref != nullptr);
493 DCHECK((singleton_ref->GetBlock() == block) ||
494 !singleton_ref->GetBlock()->Dominates(block))
495 << "method: " << GetGraph()->GetMethodName();
496 // singleton_ref is not defined before block or defined only in some of its
497 // predecessors, so block doesn't really have the location at its entry.
498 heap_values[i] = kUnknownHeapValue;
499 } else if (predecessors.size() == 1) {
500 // Inherit heap value from the single predecessor.
501 DCHECK_EQ(heap_values_for_[predecessors[0]->GetBlockId()][i], merged_value);
502 heap_values[i] = merged_value;
503 } else {
504 DCHECK(merged_value == kUnknownHeapValue ||
505 merged_value == kDefaultHeapValue ||
506 merged_value->GetBlock()->Dominates(block));
507 if (merged_value != kUnknownHeapValue) {
508 heap_values[i] = merged_value;
509 } else {
510 // Stores in different predecessors may be storing the same value.
511 heap_values[i] = merged_store_value;
512 }
513 }
514 }
515 }
516
517 // `instruction` is being removed. Try to see if the null check on it
518 // can be removed. This can happen if the same value is set in two branches
519 // but not in dominators. Such as:
520 // int[] a = foo();
521 // if () {
522 // a[0] = 2;
523 // } else {
524 // a[0] = 2;
525 // }
526 // // a[0] can now be replaced with constant 2, and the null check on it can be removed.
TryRemovingNullCheck(HInstruction * instruction)527 void TryRemovingNullCheck(HInstruction* instruction) {
528 HInstruction* prev = instruction->GetPrevious();
529 if ((prev != nullptr) && prev->IsNullCheck() && (prev == instruction->InputAt(0))) {
530 // Previous instruction is a null check for this instruction. Remove the null check.
531 prev->ReplaceWith(prev->InputAt(0));
532 prev->GetBlock()->RemoveInstruction(prev);
533 }
534 }
535
GetDefaultValue(DataType::Type type)536 HInstruction* GetDefaultValue(DataType::Type type) {
537 switch (type) {
538 case DataType::Type::kReference:
539 return GetGraph()->GetNullConstant();
540 case DataType::Type::kBool:
541 case DataType::Type::kUint8:
542 case DataType::Type::kInt8:
543 case DataType::Type::kUint16:
544 case DataType::Type::kInt16:
545 case DataType::Type::kInt32:
546 return GetGraph()->GetIntConstant(0);
547 case DataType::Type::kInt64:
548 return GetGraph()->GetLongConstant(0);
549 case DataType::Type::kFloat32:
550 return GetGraph()->GetFloatConstant(0);
551 case DataType::Type::kFloat64:
552 return GetGraph()->GetDoubleConstant(0);
553 default:
554 UNREACHABLE();
555 }
556 }
557
VisitGetLocation(HInstruction * instruction,size_t idx)558 void VisitGetLocation(HInstruction* instruction, size_t idx) {
559 DCHECK_NE(idx, HeapLocationCollector::kHeapLocationNotFound);
560 ScopedArenaVector<HInstruction*>& heap_values =
561 heap_values_for_[instruction->GetBlock()->GetBlockId()];
562 HInstruction* heap_value = heap_values[idx];
563 if (heap_value == kDefaultHeapValue) {
564 if (IsDefaultAllowedForLoad(instruction)) {
565 HInstruction* constant = GetDefaultValue(instruction->GetType());
566 AddRemovedLoad(instruction, constant);
567 heap_values[idx] = constant;
568 return;
569 } else {
570 heap_values[idx] = kUnknownHeapValue;
571 heap_value = kUnknownHeapValue;
572 }
573 }
574 heap_value = GetRealHeapValue(heap_value);
575 if (heap_value == kUnknownHeapValue) {
576 // Load isn't eliminated. Put the load as the value into the HeapLocation.
577 // This acts like GVN but with better aliasing analysis.
578 heap_values[idx] = instruction;
579 KeepStoresIfAliasedToLocation(heap_values, idx);
580 } else {
581 // Load is eliminated.
582 AddRemovedLoad(instruction, heap_value);
583 TryRemovingNullCheck(instruction);
584 }
585 }
586
Equal(HInstruction * heap_value,HInstruction * value)587 bool Equal(HInstruction* heap_value, HInstruction* value) {
588 DCHECK(!IsStore(value)) << value->DebugName();
589 if (heap_value == kUnknownHeapValue) {
590 // Don't compare kUnknownHeapValue with other values.
591 return false;
592 }
593 if (heap_value == value) {
594 return true;
595 }
596 if (heap_value == kDefaultHeapValue && GetDefaultValue(value->GetType()) == value) {
597 return true;
598 }
599 HInstruction* real_heap_value = GetRealHeapValue(heap_value);
600 if (real_heap_value != heap_value) {
601 return Equal(real_heap_value, value);
602 }
603 return false;
604 }
605
CanValueBeKeptIfSameAsNew(HInstruction * value,HInstruction * new_value,HInstruction * new_value_set_instr)606 bool CanValueBeKeptIfSameAsNew(HInstruction* value,
607 HInstruction* new_value,
608 HInstruction* new_value_set_instr) {
609 // For field/array set location operations, if the value is the same as the new_value
610 // it can be kept even if aliasing happens. All aliased operations will access the same memory
611 // range.
612 // For vector values, this is not true. For example:
613 // packed_data = [0xA, 0xB, 0xC, 0xD]; <-- Different values in each lane.
614 // VecStore array[i ,i+1,i+2,i+3] = packed_data;
615 // VecStore array[i+1,i+2,i+3,i+4] = packed_data; <-- We are here (partial overlap).
616 // VecLoad vx = array[i,i+1,i+2,i+3]; <-- Cannot be eliminated because the value
617 // here is not packed_data anymore.
618 //
619 // TODO: to allow such 'same value' optimization on vector data,
620 // LSA needs to report more fine-grain MAY alias information:
621 // (1) May alias due to two vector data partial overlap.
622 // e.g. a[i..i+3] and a[i+1,..,i+4].
623 // (2) May alias due to two vector data may complete overlap each other.
624 // e.g. a[i..i+3] and b[i..i+3].
625 // (3) May alias but the exact relationship between two locations is unknown.
626 // e.g. a[i..i+3] and b[j..j+3], where values of a,b,i,j are all unknown.
627 // This 'same value' optimization can apply only on case (2).
628 if (new_value_set_instr->IsVecOperation()) {
629 return false;
630 }
631
632 return Equal(value, new_value);
633 }
634
VisitSetLocation(HInstruction * instruction,size_t idx,HInstruction * value)635 void VisitSetLocation(HInstruction* instruction, size_t idx, HInstruction* value) {
636 DCHECK_NE(idx, HeapLocationCollector::kHeapLocationNotFound);
637 DCHECK(!IsStore(value)) << value->DebugName();
638 // value may already have a substitute.
639 value = FindSubstitute(value);
640 ScopedArenaVector<HInstruction*>& heap_values =
641 heap_values_for_[instruction->GetBlock()->GetBlockId()];
642 HInstruction* heap_value = heap_values[idx];
643 bool possibly_redundant = false;
644
645 if (Equal(heap_value, value)) {
646 // Store into the heap location with the same value.
647 // This store can be eliminated right away.
648 instruction->GetBlock()->RemoveInstruction(instruction);
649 return;
650 } else {
651 HLoopInformation* loop_info = instruction->GetBlock()->GetLoopInformation();
652 if (loop_info == nullptr) {
653 // Store is not in a loop. We try to precisely track the heap value by
654 // the store.
655 possibly_redundant = true;
656 } else if (!loop_info->IsIrreducible()) {
657 // instruction is a store in the loop so the loop must do write.
658 DCHECK(side_effects_.GetLoopEffects(loop_info->GetHeader()).DoesAnyWrite());
659 ReferenceInfo* ref_info = heap_location_collector_.GetHeapLocation(idx)->GetReferenceInfo();
660 if (ref_info->IsSingleton() && !loop_info->IsDefinedOutOfTheLoop(ref_info->GetReference())) {
661 // original_ref is created inside the loop. Value stored to it isn't needed at
662 // the loop header. This is true for outer loops also.
663 possibly_redundant = true;
664 } else {
665 // Keep the store since its value may be needed at the loop header.
666 }
667 } else {
668 // Keep the store inside irreducible loops.
669 }
670 }
671 if (possibly_redundant) {
672 possibly_removed_stores_.push_back(instruction);
673 }
674
675 // Put the store as the heap value. If the value is loaded or needed after
676 // return/deoptimization later, this store isn't really redundant.
677 heap_values[idx] = instruction;
678
679 // This store may kill values in other heap locations due to aliasing.
680 for (size_t i = 0; i < heap_values.size(); i++) {
681 if (i == idx ||
682 heap_values[i] == kUnknownHeapValue ||
683 CanValueBeKeptIfSameAsNew(heap_values[i], value, instruction) ||
684 !heap_location_collector_.MayAlias(i, idx)) {
685 continue;
686 }
687 // Kill heap locations that may alias and as a result if the heap value
688 // is a store, the store needs to be kept.
689 KeepIfIsStore(heap_values[i]);
690 heap_values[i] = kUnknownHeapValue;
691 }
692 }
693
VisitInstanceFieldGet(HInstanceFieldGet * instruction)694 void VisitInstanceFieldGet(HInstanceFieldGet* instruction) override {
695 HInstruction* object = instruction->InputAt(0);
696 const FieldInfo& field = instruction->GetFieldInfo();
697 VisitGetLocation(instruction, heap_location_collector_.GetFieldHeapLocation(object, &field));
698 }
699
VisitInstanceFieldSet(HInstanceFieldSet * instruction)700 void VisitInstanceFieldSet(HInstanceFieldSet* instruction) override {
701 HInstruction* object = instruction->InputAt(0);
702 const FieldInfo& field = instruction->GetFieldInfo();
703 HInstruction* value = instruction->InputAt(1);
704 size_t idx = heap_location_collector_.GetFieldHeapLocation(object, &field);
705 VisitSetLocation(instruction, idx, value);
706 }
707
VisitStaticFieldGet(HStaticFieldGet * instruction)708 void VisitStaticFieldGet(HStaticFieldGet* instruction) override {
709 HInstruction* cls = instruction->InputAt(0);
710 const FieldInfo& field = instruction->GetFieldInfo();
711 VisitGetLocation(instruction, heap_location_collector_.GetFieldHeapLocation(cls, &field));
712 }
713
VisitStaticFieldSet(HStaticFieldSet * instruction)714 void VisitStaticFieldSet(HStaticFieldSet* instruction) override {
715 HInstruction* cls = instruction->InputAt(0);
716 const FieldInfo& field = instruction->GetFieldInfo();
717 size_t idx = heap_location_collector_.GetFieldHeapLocation(cls, &field);
718 VisitSetLocation(instruction, idx, instruction->InputAt(1));
719 }
720
VisitArrayGet(HArrayGet * instruction)721 void VisitArrayGet(HArrayGet* instruction) override {
722 VisitGetLocation(instruction, heap_location_collector_.GetArrayHeapLocation(instruction));
723 }
724
VisitArraySet(HArraySet * instruction)725 void VisitArraySet(HArraySet* instruction) override {
726 size_t idx = heap_location_collector_.GetArrayHeapLocation(instruction);
727 VisitSetLocation(instruction, idx, instruction->GetValue());
728 }
729
VisitVecLoad(HVecLoad * instruction)730 void VisitVecLoad(HVecLoad* instruction) override {
731 VisitGetLocation(instruction, heap_location_collector_.GetArrayHeapLocation(instruction));
732 }
733
VisitVecStore(HVecStore * instruction)734 void VisitVecStore(HVecStore* instruction) override {
735 size_t idx = heap_location_collector_.GetArrayHeapLocation(instruction);
736 VisitSetLocation(instruction, idx, instruction->GetValue());
737 }
738
VisitDeoptimize(HDeoptimize * instruction)739 void VisitDeoptimize(HDeoptimize* instruction) override {
740 const ScopedArenaVector<HInstruction*>& heap_values =
741 heap_values_for_[instruction->GetBlock()->GetBlockId()];
742 for (HInstruction* heap_value : heap_values) {
743 // A store is kept as the heap value for possibly removed stores.
744 // That value stored is generally observeable after deoptimization, except
745 // for singletons that don't escape after deoptimization.
746 if (IsStore(heap_value)) {
747 if (heap_value->IsStaticFieldSet()) {
748 KeepIfIsStore(heap_value);
749 continue;
750 }
751 HInstruction* reference = heap_value->InputAt(0);
752 if (heap_location_collector_.FindReferenceInfoOf(reference)->IsSingleton()) {
753 if (reference->IsNewInstance() && reference->AsNewInstance()->IsFinalizable()) {
754 // Finalizable objects alway escape.
755 KeepIfIsStore(heap_value);
756 continue;
757 }
758 // Check whether the reference for a store is used by an environment local of
759 // HDeoptimize. If not, the singleton is not observed after
760 // deoptimizion.
761 for (const HUseListNode<HEnvironment*>& use : reference->GetEnvUses()) {
762 HEnvironment* user = use.GetUser();
763 if (user->GetHolder() == instruction) {
764 // The singleton for the store is visible at this deoptimization
765 // point. Need to keep the store so that the heap value is
766 // seen by the interpreter.
767 KeepIfIsStore(heap_value);
768 }
769 }
770 } else {
771 KeepIfIsStore(heap_value);
772 }
773 }
774 }
775 }
776
777 // Keep necessary stores before exiting a method via return/throw.
HandleExit(HBasicBlock * block)778 void HandleExit(HBasicBlock* block) {
779 const ScopedArenaVector<HInstruction*>& heap_values =
780 heap_values_for_[block->GetBlockId()];
781 for (size_t i = 0; i < heap_values.size(); i++) {
782 HInstruction* heap_value = heap_values[i];
783 ReferenceInfo* ref_info = heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo();
784 if (!ref_info->IsSingletonAndRemovable()) {
785 KeepIfIsStore(heap_value);
786 }
787 }
788 }
789
VisitReturn(HReturn * instruction)790 void VisitReturn(HReturn* instruction) override {
791 HandleExit(instruction->GetBlock());
792 }
793
VisitReturnVoid(HReturnVoid * return_void)794 void VisitReturnVoid(HReturnVoid* return_void) override {
795 HandleExit(return_void->GetBlock());
796 }
797
VisitThrow(HThrow * throw_instruction)798 void VisitThrow(HThrow* throw_instruction) override {
799 HandleExit(throw_instruction->GetBlock());
800 }
801
HandleInvoke(HInstruction * instruction)802 void HandleInvoke(HInstruction* instruction) {
803 SideEffects side_effects = instruction->GetSideEffects();
804 ScopedArenaVector<HInstruction*>& heap_values =
805 heap_values_for_[instruction->GetBlock()->GetBlockId()];
806 for (size_t i = 0; i < heap_values.size(); i++) {
807 ReferenceInfo* ref_info = heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo();
808 if (ref_info->IsSingleton()) {
809 // Singleton references cannot be seen by the callee.
810 } else {
811 if (side_effects.DoesAnyRead()) {
812 // Invocation may read the heap value.
813 KeepIfIsStore(heap_values[i]);
814 }
815 if (side_effects.DoesAnyWrite()) {
816 // Keep the store since it's not used to track the heap value anymore.
817 KeepIfIsStore(heap_values[i]);
818 heap_values[i] = kUnknownHeapValue;
819 }
820 }
821 }
822 }
823
VisitInvoke(HInvoke * invoke)824 void VisitInvoke(HInvoke* invoke) override {
825 HandleInvoke(invoke);
826 }
827
VisitClinitCheck(HClinitCheck * clinit)828 void VisitClinitCheck(HClinitCheck* clinit) override {
829 HandleInvoke(clinit);
830 }
831
VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet * instruction)832 void VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* instruction) override {
833 // Conservatively treat it as an invocation.
834 HandleInvoke(instruction);
835 }
836
VisitUnresolvedInstanceFieldSet(HUnresolvedInstanceFieldSet * instruction)837 void VisitUnresolvedInstanceFieldSet(HUnresolvedInstanceFieldSet* instruction) override {
838 // Conservatively treat it as an invocation.
839 HandleInvoke(instruction);
840 }
841
VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet * instruction)842 void VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet* instruction) override {
843 // Conservatively treat it as an invocation.
844 HandleInvoke(instruction);
845 }
846
VisitUnresolvedStaticFieldSet(HUnresolvedStaticFieldSet * instruction)847 void VisitUnresolvedStaticFieldSet(HUnresolvedStaticFieldSet* instruction) override {
848 // Conservatively treat it as an invocation.
849 HandleInvoke(instruction);
850 }
851
VisitNewInstance(HNewInstance * new_instance)852 void VisitNewInstance(HNewInstance* new_instance) override {
853 ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf(new_instance);
854 if (ref_info == nullptr) {
855 // new_instance isn't used for field accesses. No need to process it.
856 return;
857 }
858 if (ref_info->IsSingletonAndRemovable() && !new_instance->NeedsChecks()) {
859 DCHECK(!new_instance->IsFinalizable());
860 // new_instance can potentially be eliminated.
861 singleton_new_instances_.push_back(new_instance);
862 }
863 ScopedArenaVector<HInstruction*>& heap_values =
864 heap_values_for_[new_instance->GetBlock()->GetBlockId()];
865 for (size_t i = 0; i < heap_values.size(); i++) {
866 HInstruction* ref =
867 heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo()->GetReference();
868 size_t offset = heap_location_collector_.GetHeapLocation(i)->GetOffset();
869 if (ref == new_instance && offset >= mirror::kObjectHeaderSize) {
870 // Instance fields except the header fields are set to default heap values.
871 heap_values[i] = kDefaultHeapValue;
872 }
873 }
874 }
875
VisitNewArray(HNewArray * new_array)876 void VisitNewArray(HNewArray* new_array) override {
877 ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf(new_array);
878 if (ref_info == nullptr) {
879 // new_array isn't used for array accesses. No need to process it.
880 return;
881 }
882 if (ref_info->IsSingletonAndRemovable()) {
883 if (new_array->GetLength()->IsIntConstant() &&
884 new_array->GetLength()->AsIntConstant()->GetValue() >= 0) {
885 // new_array can potentially be eliminated.
886 singleton_new_instances_.push_back(new_array);
887 } else {
888 // new_array may throw NegativeArraySizeException. Keep it.
889 }
890 }
891 ScopedArenaVector<HInstruction*>& heap_values =
892 heap_values_for_[new_array->GetBlock()->GetBlockId()];
893 for (size_t i = 0; i < heap_values.size(); i++) {
894 HeapLocation* location = heap_location_collector_.GetHeapLocation(i);
895 HInstruction* ref = location->GetReferenceInfo()->GetReference();
896 if (ref == new_array && location->GetIndex() != nullptr) {
897 // Array elements are set to default heap values.
898 heap_values[i] = kDefaultHeapValue;
899 }
900 }
901 }
902
903 const HeapLocationCollector& heap_location_collector_;
904 const SideEffectsAnalysis& side_effects_;
905
906 // Use local allocator for allocating memory.
907 ScopedArenaAllocator allocator_;
908
909 // One array of heap values for each block.
910 ScopedArenaVector<ScopedArenaVector<HInstruction*>> heap_values_for_;
911
912 // We record the instructions that should be eliminated but may be
913 // used by heap locations. They'll be removed in the end.
914 ScopedArenaVector<HInstruction*> removed_loads_;
915 ScopedArenaVector<HInstruction*> substitute_instructions_for_loads_;
916
917 // Stores in this list may be removed from the list later when it's
918 // found that the store cannot be eliminated.
919 ScopedArenaVector<HInstruction*> possibly_removed_stores_;
920
921 ScopedArenaVector<HInstruction*> singleton_new_instances_;
922
923 DISALLOW_COPY_AND_ASSIGN(LSEVisitor);
924 };
925
Run()926 bool LoadStoreElimination::Run() {
927 if (graph_->IsDebuggable() || graph_->HasTryCatch()) {
928 // Debugger may set heap values or trigger deoptimization of callers.
929 // Try/catch support not implemented yet.
930 // Skip this optimization.
931 return false;
932 }
933 const HeapLocationCollector& heap_location_collector = lsa_.GetHeapLocationCollector();
934 if (heap_location_collector.GetNumberOfHeapLocations() == 0) {
935 // No HeapLocation information from LSA, skip this optimization.
936 return false;
937 }
938
939 LSEVisitor lse_visitor(graph_, heap_location_collector, side_effects_, stats_);
940 for (HBasicBlock* block : graph_->GetReversePostOrder()) {
941 lse_visitor.VisitBasicBlock(block);
942 }
943 lse_visitor.RemoveInstructions();
944
945 return true;
946 }
947
948 } // namespace art
949