Chromium Code Reviews| 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 16 matching lines...) Expand all Loading... | |
| 27 case IrOpcode::kCheckedFloat64ToInt32: | 27 case IrOpcode::kCheckedFloat64ToInt32: |
| 28 case IrOpcode::kCheckedInt32Add: | 28 case IrOpcode::kCheckedInt32Add: |
| 29 case IrOpcode::kCheckedInt32Sub: | 29 case IrOpcode::kCheckedInt32Sub: |
| 30 case IrOpcode::kCheckedInt32Div: | 30 case IrOpcode::kCheckedInt32Div: |
| 31 case IrOpcode::kCheckedInt32Mod: | 31 case IrOpcode::kCheckedInt32Mod: |
| 32 case IrOpcode::kCheckedInt32Mul: | 32 case IrOpcode::kCheckedInt32Mul: |
| 33 case IrOpcode::kCheckedTaggedToFloat64: | 33 case IrOpcode::kCheckedTaggedToFloat64: |
| 34 case IrOpcode::kCheckedTaggedToInt32: | 34 case IrOpcode::kCheckedTaggedToInt32: |
| 35 case IrOpcode::kCheckedUint32ToInt32: | 35 case IrOpcode::kCheckedUint32ToInt32: |
| 36 return ReduceCheckNode(node); | 36 return ReduceCheckNode(node); |
| 37 case IrOpcode::kSpeculativeNumberAdd: | |
| 38 case IrOpcode::kSpeculativeNumberSubtract: | |
| 39 case IrOpcode::kSpeculativeNumberMultiply: | |
| 40 case IrOpcode::kSpeculativeNumberModulus: | |
| 41 case IrOpcode::kSpeculativeNumberDivide: | |
| 42 case IrOpcode::kSpeculativeNumberShiftLeft: | |
| 43 case IrOpcode::kSpeculativeNumberEqual: | |
| 44 case IrOpcode::kSpeculativeNumberLessThan: | |
| 45 case IrOpcode::kSpeculativeNumberLessThanOrEqual: | |
| 46 return ReduceSpeculativeNode(node); | |
| 37 case IrOpcode::kEffectPhi: | 47 case IrOpcode::kEffectPhi: |
| 38 return ReduceEffectPhi(node); | 48 return ReduceEffectPhi(node); |
| 39 case IrOpcode::kDead: | 49 case IrOpcode::kDead: |
| 40 break; | 50 break; |
| 41 case IrOpcode::kStart: | 51 case IrOpcode::kStart: |
| 42 return ReduceStart(node); | 52 return ReduceStart(node); |
| 43 default: | 53 default: |
| 44 return ReduceOtherNode(node); | 54 return ReduceOtherNode(node); |
| 45 } | 55 } |
| 46 return NoChange(); | 56 return NoChange(); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 112 namespace { | 122 namespace { |
| 113 | 123 |
| 114 bool IsCompatibleCheck(Node const* a, Node const* b) { | 124 bool IsCompatibleCheck(Node const* a, Node const* b) { |
| 115 if (a->op() != b->op()) return false; | 125 if (a->op() != b->op()) return false; |
| 116 for (int i = a->op()->ValueInputCount(); --i >= 0;) { | 126 for (int i = a->op()->ValueInputCount(); --i >= 0;) { |
| 117 if (a->InputAt(i) != b->InputAt(i)) return false; | 127 if (a->InputAt(i) != b->InputAt(i)) return false; |
| 118 } | 128 } |
| 119 return true; | 129 return true; |
| 120 } | 130 } |
| 121 | 131 |
| 132 bool IsCompatibleSpeculative(Node const* a, Node const* b) { | |
| 133 if (a->opcode() != b->opcode()) return false; | |
| 134 DCHECK_EQ(a->InputCount(), b->InputCount()); | |
| 135 for (int i = a->op()->ValueInputCount(); --i >= 0;) { | |
| 136 if (a->InputAt(i) != b->InputAt(i)) return false; | |
| 137 } | |
| 138 return true; | |
| 139 } | |
| 140 | |
| 122 } // namespace | 141 } // namespace |
| 123 | 142 |
| 124 Node* RedundancyElimination::EffectPathChecks::LookupCheck(Node* node) const { | 143 template <typename Predicate> |
|
Jarin
2016/07/26 09:39:21
Do we really need to have templates for this? How
| |
| 144 Node* RedundancyElimination::EffectPathChecks::LookupCheck( | |
| 145 Node* node, Predicate predicate) const { | |
| 125 for (Check const* check = head_; check != nullptr; check = check->next) { | 146 for (Check const* check = head_; check != nullptr; check = check->next) { |
| 126 if (IsCompatibleCheck(check->node, node)) { | 147 if (predicate(check->node, node)) { |
| 127 DCHECK(!check->node->IsDead()); | 148 DCHECK(!check->node->IsDead()); |
| 128 return check->node; | 149 return check->node; |
| 129 } | 150 } |
| 130 } | 151 } |
| 131 return nullptr; | 152 return nullptr; |
| 132 } | 153 } |
| 133 | 154 |
| 134 RedundancyElimination::EffectPathChecks const* | 155 RedundancyElimination::EffectPathChecks const* |
| 135 RedundancyElimination::PathChecksForEffectNodes::Get(Node* node) const { | 156 RedundancyElimination::PathChecksForEffectNodes::Get(Node* node) const { |
| 136 size_t const id = node->id(); | 157 size_t const id = node->id(); |
| 137 if (id < info_for_node_.size()) return info_for_node_[id]; | 158 if (id < info_for_node_.size()) return info_for_node_[id]; |
| 138 return nullptr; | 159 return nullptr; |
| 139 } | 160 } |
| 140 | 161 |
| 141 void RedundancyElimination::PathChecksForEffectNodes::Set( | 162 void RedundancyElimination::PathChecksForEffectNodes::Set( |
| 142 Node* node, EffectPathChecks const* checks) { | 163 Node* node, EffectPathChecks const* checks) { |
| 143 size_t const id = node->id(); | 164 size_t const id = node->id(); |
| 144 if (id >= info_for_node_.size()) info_for_node_.resize(id + 1, nullptr); | 165 if (id >= info_for_node_.size()) info_for_node_.resize(id + 1, nullptr); |
| 145 info_for_node_[id] = checks; | 166 info_for_node_[id] = checks; |
| 146 } | 167 } |
| 147 | 168 |
| 148 Reduction RedundancyElimination::ReduceCheckNode(Node* node) { | 169 Reduction RedundancyElimination::ReduceCheckNode(Node* node) { |
| 149 Node* const effect = NodeProperties::GetEffectInput(node); | 170 Node* const effect = NodeProperties::GetEffectInput(node); |
| 150 EffectPathChecks const* checks = node_checks_.Get(effect); | 171 EffectPathChecks const* checks = node_checks_.Get(effect); |
| 151 // If we do not know anything about the predecessor, do not propagate just yet | 172 // If we do not know anything about the predecessor, do not propagate just yet |
| 152 // because we will have to recompute anyway once we compute the predecessor. | 173 // because we will have to recompute anyway once we compute the predecessor. |
| 153 if (checks == nullptr) return NoChange(); | 174 if (checks == nullptr) return NoChange(); |
| 154 // See if we have another check that dominates us. | 175 // See if we have another check that dominates us. |
| 155 if (Node* check = checks->LookupCheck(node)) { | 176 if (Node* check = checks->LookupCheck(node, IsCompatibleCheck)) { |
| 156 ReplaceWithValue(node, check); | 177 ReplaceWithValue(node, check); |
| 157 return Replace(check); | 178 return Replace(check); |
| 158 } | 179 } |
| 159 // Learn from this check. | 180 // Learn from this check. |
| 160 return UpdateChecks(node, checks->AddCheck(zone(), node)); | 181 return UpdateChecks(node, checks->AddCheck(zone(), node)); |
| 161 } | 182 } |
| 162 | 183 |
| 184 Reduction RedundancyElimination::ReduceSpeculativeNode(Node* node) { | |
| 185 Node* const effect = NodeProperties::GetEffectInput(node); | |
| 186 EffectPathChecks const* checks = node_checks_.Get(effect); | |
| 187 // If we do not know anything about the predecessor, do not propagate just yet | |
| 188 // because we will have to recompute anyway once we compute the predecessor. | |
| 189 if (checks == nullptr) return NoChange(); | |
| 190 // See if we have another speculative {node} that dominates us. | |
| 191 if (Node* check = checks->LookupCheck(node, IsCompatibleSpeculative)) { | |
| 192 ReplaceWithValue(node, check); | |
| 193 return Replace(check); | |
| 194 } | |
| 195 // Learn from this speculative {node}. | |
| 196 return UpdateChecks(node, checks->AddCheck(zone(), node)); | |
| 197 } | |
| 198 | |
| 163 Reduction RedundancyElimination::ReduceEffectPhi(Node* node) { | 199 Reduction RedundancyElimination::ReduceEffectPhi(Node* node) { |
| 164 Node* const control = NodeProperties::GetControlInput(node); | 200 Node* const control = NodeProperties::GetControlInput(node); |
| 165 if (control->opcode() == IrOpcode::kLoop) { | 201 if (control->opcode() == IrOpcode::kLoop) { |
| 166 // Here we rely on having only reducible loops: | 202 // Here we rely on having only reducible loops: |
| 167 // The loop entry edge always dominates the header, so we can just use | 203 // The loop entry edge always dominates the header, so we can just use |
| 168 // the information from the loop entry edge. | 204 // the information from the loop entry edge. |
| 169 return TakeChecksFromFirstEffect(node); | 205 return TakeChecksFromFirstEffect(node); |
| 170 } | 206 } |
| 171 DCHECK_EQ(IrOpcode::kMerge, control->opcode()); | 207 DCHECK_EQ(IrOpcode::kMerge, control->opcode()); |
| 172 | 208 |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 228 node_checks_.Set(node, checks); | 264 node_checks_.Set(node, checks); |
| 229 return Changed(node); | 265 return Changed(node); |
| 230 } | 266 } |
| 231 } | 267 } |
| 232 return NoChange(); | 268 return NoChange(); |
| 233 } | 269 } |
| 234 | 270 |
| 235 } // namespace compiler | 271 } // namespace compiler |
| 236 } // namespace internal | 272 } // namespace internal |
| 237 } // namespace v8 | 273 } // namespace v8 |
| OLD | NEW |