| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/redundancy-elimination.h" | 5 #include "src/compiler/redundancy-elimination.h" |
| 6 | 6 |
| 7 #include "src/compiler/node-properties.h" | 7 #include "src/compiler/node-properties.h" |
| 8 | 8 |
| 9 namespace v8 { | 9 namespace v8 { |
| 10 namespace internal { | 10 namespace internal { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 case IrOpcode::kCheckedInt32Add: | 29 case IrOpcode::kCheckedInt32Add: |
| 30 case IrOpcode::kCheckedInt32Sub: | 30 case IrOpcode::kCheckedInt32Sub: |
| 31 case IrOpcode::kCheckedInt32Div: | 31 case IrOpcode::kCheckedInt32Div: |
| 32 case IrOpcode::kCheckedInt32Mod: | 32 case IrOpcode::kCheckedInt32Mod: |
| 33 case IrOpcode::kCheckedInt32Mul: | 33 case IrOpcode::kCheckedInt32Mul: |
| 34 case IrOpcode::kCheckedTaggedToFloat64: | 34 case IrOpcode::kCheckedTaggedToFloat64: |
| 35 case IrOpcode::kCheckedTaggedSignedToInt32: | 35 case IrOpcode::kCheckedTaggedSignedToInt32: |
| 36 case IrOpcode::kCheckedTaggedToInt32: | 36 case IrOpcode::kCheckedTaggedToInt32: |
| 37 case IrOpcode::kCheckedUint32ToInt32: | 37 case IrOpcode::kCheckedUint32ToInt32: |
| 38 return ReduceCheckNode(node); | 38 return ReduceCheckNode(node); |
| 39 case IrOpcode::kSpeculativeNumberAdd: |
| 40 case IrOpcode::kSpeculativeNumberSubtract: |
| 41 // For increments and decrements by a constant, try to learn from the last |
| 42 // bounds check. |
| 43 return TryReuseBoundsCheckForFirstInput(node); |
| 39 case IrOpcode::kEffectPhi: | 44 case IrOpcode::kEffectPhi: |
| 40 return ReduceEffectPhi(node); | 45 return ReduceEffectPhi(node); |
| 41 case IrOpcode::kDead: | 46 case IrOpcode::kDead: |
| 42 break; | 47 break; |
| 43 case IrOpcode::kStart: | 48 case IrOpcode::kStart: |
| 44 return ReduceStart(node); | 49 return ReduceStart(node); |
| 45 default: | 50 default: |
| 46 return ReduceOtherNode(node); | 51 return ReduceOtherNode(node); |
| 47 } | 52 } |
| 48 return NoChange(); | 53 return NoChange(); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 126 Node* RedundancyElimination::EffectPathChecks::LookupCheck(Node* node) const { | 131 Node* RedundancyElimination::EffectPathChecks::LookupCheck(Node* node) const { |
| 127 for (Check const* check = head_; check != nullptr; check = check->next) { | 132 for (Check const* check = head_; check != nullptr; check = check->next) { |
| 128 if (IsCompatibleCheck(check->node, node)) { | 133 if (IsCompatibleCheck(check->node, node)) { |
| 129 DCHECK(!check->node->IsDead()); | 134 DCHECK(!check->node->IsDead()); |
| 130 return check->node; | 135 return check->node; |
| 131 } | 136 } |
| 132 } | 137 } |
| 133 return nullptr; | 138 return nullptr; |
| 134 } | 139 } |
| 135 | 140 |
| 141 Node* RedundancyElimination::EffectPathChecks::LookupBoundsCheckFor( |
| 142 Node* node) const { |
| 143 for (Check const* check = head_; check != nullptr; check = check->next) { |
| 144 if (check->node->opcode() == IrOpcode::kCheckBounds && |
| 145 check->node->InputAt(0) == node) { |
| 146 return check->node; |
| 147 } |
| 148 } |
| 149 return nullptr; |
| 150 } |
| 151 |
| 136 RedundancyElimination::EffectPathChecks const* | 152 RedundancyElimination::EffectPathChecks const* |
| 137 RedundancyElimination::PathChecksForEffectNodes::Get(Node* node) const { | 153 RedundancyElimination::PathChecksForEffectNodes::Get(Node* node) const { |
| 138 size_t const id = node->id(); | 154 size_t const id = node->id(); |
| 139 if (id < info_for_node_.size()) return info_for_node_[id]; | 155 if (id < info_for_node_.size()) return info_for_node_[id]; |
| 140 return nullptr; | 156 return nullptr; |
| 141 } | 157 } |
| 142 | 158 |
| 143 void RedundancyElimination::PathChecksForEffectNodes::Set( | 159 void RedundancyElimination::PathChecksForEffectNodes::Set( |
| 144 Node* node, EffectPathChecks const* checks) { | 160 Node* node, EffectPathChecks const* checks) { |
| 145 size_t const id = node->id(); | 161 size_t const id = node->id(); |
| 146 if (id >= info_for_node_.size()) info_for_node_.resize(id + 1, nullptr); | 162 if (id >= info_for_node_.size()) info_for_node_.resize(id + 1, nullptr); |
| 147 info_for_node_[id] = checks; | 163 info_for_node_[id] = checks; |
| 148 } | 164 } |
| 149 | 165 |
| 150 Reduction RedundancyElimination::ReduceCheckNode(Node* node) { | 166 Reduction RedundancyElimination::ReduceCheckNode(Node* node) { |
| 151 Node* const effect = NodeProperties::GetEffectInput(node); | 167 Node* const effect = NodeProperties::GetEffectInput(node); |
| 152 EffectPathChecks const* checks = node_checks_.Get(effect); | 168 EffectPathChecks const* checks = node_checks_.Get(effect); |
| 153 // If we do not know anything about the predecessor, do not propagate just yet | 169 // If we do not know anything about the predecessor, do not propagate just yet |
| 154 // because we will have to recompute anyway once we compute the predecessor. | 170 // because we will have to recompute anyway once we compute the predecessor. |
| 155 if (checks == nullptr) return NoChange(); | 171 if (checks == nullptr) return NoChange(); |
| 156 // See if we have another check that dominates us. | 172 // See if we have another check that dominates us. |
| 157 if (Node* check = checks->LookupCheck(node)) { | 173 if (Node* check = checks->LookupCheck(node)) { |
| 158 ReplaceWithValue(node, check); | 174 ReplaceWithValue(node, check); |
| 159 return Replace(check); | 175 return Replace(check); |
| 160 } | 176 } |
| 177 |
| 161 // Learn from this check. | 178 // Learn from this check. |
| 162 return UpdateChecks(node, checks->AddCheck(zone(), node)); | 179 return UpdateChecks(node, checks->AddCheck(zone(), node)); |
| 163 } | 180 } |
| 164 | 181 |
| 182 Reduction RedundancyElimination::TryReuseBoundsCheckForFirstInput(Node* node) { |
| 183 DCHECK(node->opcode() == IrOpcode::kSpeculativeNumberAdd || |
| 184 node->opcode() == IrOpcode::kSpeculativeNumberSubtract); |
| 185 |
| 186 DCHECK_EQ(1, node->op()->EffectInputCount()); |
| 187 DCHECK_EQ(1, node->op()->EffectOutputCount()); |
| 188 |
| 189 Node* const effect = NodeProperties::GetEffectInput(node); |
| 190 EffectPathChecks const* checks = node_checks_.Get(effect); |
| 191 |
| 192 // If we do not know anything about the predecessor, do not propagate just yet |
| 193 // because we will have to recompute anyway once we compute the predecessor. |
| 194 if (checks == nullptr) return NoChange(); |
| 195 |
| 196 Node* left = node->InputAt(0); |
| 197 Node* right = node->InputAt(1); |
| 198 // Only use bounds checks for increments/decrements by a constant. |
| 199 if (right->opcode() == IrOpcode::kNumberConstant) { |
| 200 if (Node* bounds_check = checks->LookupBoundsCheckFor(left)) { |
| 201 // Only use the bounds checked type if it is better. |
| 202 if (NodeProperties::GetType(bounds_check) |
| 203 ->Is(NodeProperties::GetType(left))) { |
| 204 node->ReplaceInput(0, bounds_check); |
| 205 } |
| 206 } |
| 207 } |
| 208 |
| 209 return UpdateChecks(node, checks); |
| 210 } |
| 211 |
| 165 Reduction RedundancyElimination::ReduceEffectPhi(Node* node) { | 212 Reduction RedundancyElimination::ReduceEffectPhi(Node* node) { |
| 166 Node* const control = NodeProperties::GetControlInput(node); | 213 Node* const control = NodeProperties::GetControlInput(node); |
| 167 if (control->opcode() == IrOpcode::kLoop) { | 214 if (control->opcode() == IrOpcode::kLoop) { |
| 168 // Here we rely on having only reducible loops: | 215 // Here we rely on having only reducible loops: |
| 169 // The loop entry edge always dominates the header, so we can just use | 216 // The loop entry edge always dominates the header, so we can just use |
| 170 // the information from the loop entry edge. | 217 // the information from the loop entry edge. |
| 171 return TakeChecksFromFirstEffect(node); | 218 return TakeChecksFromFirstEffect(node); |
| 172 } | 219 } |
| 173 DCHECK_EQ(IrOpcode::kMerge, control->opcode()); | 220 DCHECK_EQ(IrOpcode::kMerge, control->opcode()); |
| 174 | 221 |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 230 node_checks_.Set(node, checks); | 277 node_checks_.Set(node, checks); |
| 231 return Changed(node); | 278 return Changed(node); |
| 232 } | 279 } |
| 233 } | 280 } |
| 234 return NoChange(); | 281 return NoChange(); |
| 235 } | 282 } |
| 236 | 283 |
| 237 } // namespace compiler | 284 } // namespace compiler |
| 238 } // namespace internal | 285 } // namespace internal |
| 239 } // namespace v8 | 286 } // namespace v8 |
| OLD | NEW |