1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/hydrogen-dehoist.h"
6 #include "src/base/safe_math.h"
7 
8 namespace v8 {
9 namespace internal {
10 
DehoistArrayIndex(ArrayInstructionInterface * array_operation)11 static void DehoistArrayIndex(ArrayInstructionInterface* array_operation) {
12   HValue* index = array_operation->GetKey()->ActualValue();
13   if (!index->representation().IsSmiOrInteger32()) return;
14   if (!index->IsAdd() && !index->IsSub()) return;
15 
16   HConstant* constant;
17   HValue* subexpression;
18   HBinaryOperation* binary_operation = HBinaryOperation::cast(index);
19   if (binary_operation->left()->IsConstant() && index->IsAdd()) {
20     subexpression = binary_operation->right();
21     constant = HConstant::cast(binary_operation->left());
22   } else if (binary_operation->right()->IsConstant()) {
23     subexpression = binary_operation->left();
24     constant = HConstant::cast(binary_operation->right());
25   } else {
26     return;
27   }
28 
29   if (!constant->HasInteger32Value()) return;
30   int32_t sign = binary_operation->IsSub() ? -1 : 1;
31   int32_t value = constant->Integer32Value() * sign;
32   if (value < 0) return;
33 
34   // Multiply value by elements size, bailing out on overflow.
35   int32_t elements_kind_size =
36       1 << ElementsKindToShiftSize(array_operation->elements_kind());
37   v8::base::internal::CheckedNumeric<int32_t> multiply_result = value;
38   multiply_result = multiply_result * elements_kind_size;
39   if (!multiply_result.IsValid()) return;
40   value = multiply_result.ValueOrDie();
41 
42   // Ensure that the array operation can add value to existing base offset
43   // without overflowing.
44   if (!array_operation->TryIncreaseBaseOffset(value)) return;
45 
46   array_operation->SetKey(subexpression);
47   if (binary_operation->HasNoUses()) {
48     binary_operation->DeleteAndReplaceWith(NULL);
49   }
50 
51   array_operation->SetDehoisted(true);
52 }
53 
54 
Run()55 void HDehoistIndexComputationsPhase::Run() {
56   const ZoneList<HBasicBlock*>* blocks(graph()->blocks());
57   for (int i = 0; i < blocks->length(); ++i) {
58     for (HInstructionIterator it(blocks->at(i)); !it.Done(); it.Advance()) {
59       HInstruction* instr = it.Current();
60       if (instr->IsLoadKeyed()) {
61         DehoistArrayIndex(HLoadKeyed::cast(instr));
62       } else if (instr->IsStoreKeyed()) {
63         DehoistArrayIndex(HStoreKeyed::cast(instr));
64       }
65     }
66   }
67 }
68 
69 } }  // namespace v8::internal
70