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