5 #include "src/compiler/redundancy-elimination.h" 7 #include "src/compiler/node-properties.h" 8 #include "src/compiler/simplified-operator.h" 14 RedundancyElimination::RedundancyElimination(Editor* editor, Zone* zone)
15 : AdvancedReducer(editor), node_checks_(zone), zone_(zone) {}
17 RedundancyElimination::~RedundancyElimination() =
default;
19 Reduction RedundancyElimination::Reduce(Node* node) {
20 if (node_checks_.Get(node))
return NoChange();
21 switch (node->opcode()) {
22 case IrOpcode::kCheckBounds:
23 case IrOpcode::kCheckEqualsInternalizedString:
24 case IrOpcode::kCheckEqualsSymbol:
25 case IrOpcode::kCheckFloat64Hole:
26 case IrOpcode::kCheckHeapObject:
27 case IrOpcode::kCheckIf:
28 case IrOpcode::kCheckInternalizedString:
29 case IrOpcode::kCheckNotTaggedHole:
30 case IrOpcode::kCheckNumber:
31 case IrOpcode::kCheckReceiver:
32 case IrOpcode::kCheckReceiverOrNullOrUndefined:
33 case IrOpcode::kCheckSmi:
34 case IrOpcode::kCheckString:
35 case IrOpcode::kCheckSymbol:
36 #define SIMPLIFIED_CHECKED_OP(Opcode) case IrOpcode::k##Opcode: 37 SIMPLIFIED_CHECKED_OP_LIST(SIMPLIFIED_CHECKED_OP)
38 #undef SIMPLIFIED_CHECKED_OP 39 return ReduceCheckNode(node);
40 case IrOpcode::kSpeculativeNumberEqual:
41 case IrOpcode::kSpeculativeNumberLessThan:
42 case IrOpcode::kSpeculativeNumberLessThanOrEqual:
43 return ReduceSpeculativeNumberComparison(node);
44 case IrOpcode::kSpeculativeNumberAdd:
45 case IrOpcode::kSpeculativeNumberSubtract:
46 case IrOpcode::kSpeculativeSafeIntegerAdd:
47 case IrOpcode::kSpeculativeSafeIntegerSubtract:
48 case IrOpcode::kSpeculativeToNumber:
49 return ReduceSpeculativeNumberOperation(node);
50 case IrOpcode::kEffectPhi:
51 return ReduceEffectPhi(node);
54 case IrOpcode::kStart:
55 return ReduceStart(node);
57 return ReduceOtherNode(node);
63 RedundancyElimination::EffectPathChecks*
64 RedundancyElimination::EffectPathChecks::Copy(Zone* zone,
65 EffectPathChecks
const* checks) {
66 return new (zone->New(
sizeof(EffectPathChecks))) EffectPathChecks(*checks);
70 RedundancyElimination::EffectPathChecks
const*
71 RedundancyElimination::EffectPathChecks::Empty(Zone* zone) {
72 return new (zone->New(
sizeof(EffectPathChecks))) EffectPathChecks(
nullptr, 0);
75 bool RedundancyElimination::EffectPathChecks::Equals(
76 EffectPathChecks
const* that)
const {
77 if (this->size_ != that->size_)
return false;
78 Check* this_head = this->head_;
79 Check* that_head = that->head_;
80 while (this_head != that_head) {
81 if (this_head->node != that_head->node)
return false;
82 this_head = this_head->next;
83 that_head = that_head->next;
88 void RedundancyElimination::EffectPathChecks::Merge(
89 EffectPathChecks
const* that) {
95 Check* that_head = that->head_;
96 size_t that_size = that->size_;
97 while (that_size > size_) {
98 that_head = that_head->next;
101 while (size_ > that_size) {
108 while (head_ != that_head) {
109 DCHECK_LT(0u, size_);
110 DCHECK_NOT_NULL(head_);
113 that_head = that_head->next;
117 RedundancyElimination::EffectPathChecks
const*
118 RedundancyElimination::EffectPathChecks::AddCheck(Zone* zone,
120 Check* head =
new (zone->New(
sizeof(Check))) Check(node, head_);
121 return new (zone->New(
sizeof(EffectPathChecks)))
122 EffectPathChecks(head, size_ + 1);
128 bool CheckSubsumes(Node
const* a, Node
const* b) {
129 if (a->op() != b->op()) {
130 if (a->opcode() == IrOpcode::kCheckInternalizedString &&
131 b->opcode() == IrOpcode::kCheckString) {
133 }
else if (a->opcode() == IrOpcode::kCheckSmi &&
134 b->opcode() == IrOpcode::kCheckNumber) {
136 }
else if (a->opcode() == IrOpcode::kCheckedTaggedSignedToInt32 &&
137 b->opcode() == IrOpcode::kCheckedTaggedToInt32) {
139 }
else if (a->opcode() == IrOpcode::kCheckReceiver &&
140 b->opcode() == IrOpcode::kCheckReceiverOrNullOrUndefined) {
142 }
else if (a->opcode() != b->opcode()) {
145 switch (a->opcode()) {
146 case IrOpcode::kCheckBounds:
147 case IrOpcode::kCheckSmi:
148 case IrOpcode::kCheckString:
149 case IrOpcode::kCheckNumber:
151 case IrOpcode::kCheckedInt32ToTaggedSigned:
152 case IrOpcode::kCheckedInt64ToInt32:
153 case IrOpcode::kCheckedInt64ToTaggedSigned:
154 case IrOpcode::kCheckedTaggedSignedToInt32:
155 case IrOpcode::kCheckedTaggedToTaggedPointer:
156 case IrOpcode::kCheckedTaggedToTaggedSigned:
157 case IrOpcode::kCheckedUint32Bounds:
158 case IrOpcode::kCheckedUint32ToInt32:
159 case IrOpcode::kCheckedUint32ToTaggedSigned:
160 case IrOpcode::kCheckedUint64Bounds:
161 case IrOpcode::kCheckedUint64ToInt32:
162 case IrOpcode::kCheckedUint64ToTaggedSigned:
164 case IrOpcode::kCheckedFloat64ToInt32:
165 case IrOpcode::kCheckedFloat64ToInt64:
166 case IrOpcode::kCheckedTaggedToInt32:
167 case IrOpcode::kCheckedTaggedToInt64: {
168 const CheckMinusZeroParameters& ap =
169 CheckMinusZeroParametersOf(a->op());
170 const CheckMinusZeroParameters& bp =
171 CheckMinusZeroParametersOf(b->op());
172 if (ap.mode() != bp.mode()) {
177 case IrOpcode::kCheckedTaggedToFloat64:
178 case IrOpcode::kCheckedTruncateTaggedToWord32: {
179 CheckTaggedInputParameters
const& ap =
180 CheckTaggedInputParametersOf(a->op());
181 CheckTaggedInputParameters
const& bp =
182 CheckTaggedInputParametersOf(b->op());
185 if (ap.mode() != bp.mode() &&
186 ap.mode() != CheckTaggedInputMode::kNumber) {
192 DCHECK(!IsCheckedWithFeedback(a->op()));
197 for (
int i = a->op()->ValueInputCount(); --
i >= 0;) {
198 if (a->InputAt(
i) != b->InputAt(
i))
return false;
205 Node* RedundancyElimination::EffectPathChecks::LookupCheck(Node* node)
const {
206 for (Check
const* check = head_; check !=
nullptr; check = check->next) {
207 if (CheckSubsumes(check->node, node)) {
208 DCHECK(!check->node->IsDead());
215 Node* RedundancyElimination::EffectPathChecks::LookupBoundsCheckFor(
217 for (Check
const* check = head_; check !=
nullptr; check = check->next) {
218 if (check->node->opcode() == IrOpcode::kCheckBounds &&
219 check->node->InputAt(0) == node) {
226 RedundancyElimination::EffectPathChecks
const*
227 RedundancyElimination::PathChecksForEffectNodes::Get(Node* node)
const {
228 size_t const id = node->id();
229 if (
id < info_for_node_.size())
return info_for_node_[
id];
233 void RedundancyElimination::PathChecksForEffectNodes::Set(
234 Node* node, EffectPathChecks
const* checks) {
235 size_t const id = node->id();
236 if (
id >= info_for_node_.size()) info_for_node_.resize(
id + 1,
nullptr);
237 info_for_node_[id] = checks;
240 Reduction RedundancyElimination::ReduceCheckNode(Node* node) {
241 Node*
const effect = NodeProperties::GetEffectInput(node);
242 EffectPathChecks
const* checks = node_checks_.Get(effect);
245 if (checks ==
nullptr)
return NoChange();
247 if (Node* check = checks->LookupCheck(node)) {
248 ReplaceWithValue(node, check);
249 return Replace(check);
253 return UpdateChecks(node, checks->AddCheck(zone(), node));
256 Reduction RedundancyElimination::ReduceEffectPhi(Node* node) {
257 Node*
const control = NodeProperties::GetControlInput(node);
258 if (control->opcode() == IrOpcode::kLoop) {
262 return TakeChecksFromFirstEffect(node);
264 DCHECK_EQ(IrOpcode::kMerge, control->opcode());
267 int const input_count = node->op()->EffectInputCount();
268 for (
int i = 0;
i < input_count; ++
i) {
269 Node*
const effect = NodeProperties::GetEffectInput(node,
i);
270 if (node_checks_.Get(effect) ==
nullptr)
return NoChange();
275 EffectPathChecks* checks = EffectPathChecks::Copy(
276 zone(), node_checks_.Get(NodeProperties::GetEffectInput(node, 0)));
277 for (
int i = 1;
i < input_count; ++
i) {
278 Node*
const input = NodeProperties::GetEffectInput(node,
i);
279 checks->Merge(node_checks_.Get(input));
281 return UpdateChecks(node, checks);
284 Reduction RedundancyElimination::ReduceSpeculativeNumberComparison(Node* node) {
285 NumberOperationHint
const hint = NumberOperationHintOf(node->op());
286 Node*
const first = NodeProperties::GetValueInput(node, 0);
287 Type const first_type = NodeProperties::GetType(first);
288 Node*
const second = NodeProperties::GetValueInput(node, 1);
289 Type const second_type = NodeProperties::GetType(second);
290 Node*
const effect = NodeProperties::GetEffectInput(node);
291 EffectPathChecks
const* checks = node_checks_.Get(effect);
295 if (checks ==
nullptr)
return NoChange();
301 if (hint == NumberOperationHint::kSignedSmall) {
306 if (!first_type.Is(Type::UnsignedSmall())) {
307 if (Node* check = checks->LookupBoundsCheckFor(first)) {
308 if (!first_type.Is(NodeProperties::GetType(check))) {
313 NodeProperties::ReplaceValueInput(node, check, 0);
314 Reduction
const reduction = ReduceSpeculativeNumberComparison(node);
315 return reduction.Changed() ? reduction : Changed(node);
324 if (!second_type.Is(Type::UnsignedSmall())) {
325 if (Node* check = checks->LookupBoundsCheckFor(second)) {
326 if (!second_type.Is(NodeProperties::GetType(check))) {
331 NodeProperties::ReplaceValueInput(node, check, 1);
332 Reduction
const reduction = ReduceSpeculativeNumberComparison(node);
333 return reduction.Changed() ? reduction : Changed(node);
339 return UpdateChecks(node, checks);
342 Reduction RedundancyElimination::ReduceSpeculativeNumberOperation(Node* node) {
343 DCHECK(node->opcode() == IrOpcode::kSpeculativeNumberAdd ||
344 node->opcode() == IrOpcode::kSpeculativeNumberSubtract ||
345 node->opcode() == IrOpcode::kSpeculativeSafeIntegerAdd ||
346 node->opcode() == IrOpcode::kSpeculativeSafeIntegerSubtract ||
347 node->opcode() == IrOpcode::kSpeculativeToNumber);
348 DCHECK_EQ(1, node->op()->EffectInputCount());
349 DCHECK_EQ(1, node->op()->EffectOutputCount());
351 Node*
const first = NodeProperties::GetValueInput(node, 0);
352 Node*
const effect = NodeProperties::GetEffectInput(node);
353 EffectPathChecks
const* checks = node_checks_.Get(effect);
356 if (checks ==
nullptr)
return NoChange();
362 if (Node* check = checks->LookupBoundsCheckFor(first)) {
367 if (!NodeProperties::GetType(first).Is(NodeProperties::GetType(check))) {
368 NodeProperties::ReplaceValueInput(node, check, 0);
372 return UpdateChecks(node, checks);
375 Reduction RedundancyElimination::ReduceStart(Node* node) {
376 return UpdateChecks(node, EffectPathChecks::Empty(zone()));
379 Reduction RedundancyElimination::ReduceOtherNode(Node* node) {
380 if (node->op()->EffectInputCount() == 1) {
381 if (node->op()->EffectOutputCount() == 1) {
382 return TakeChecksFromFirstEffect(node);
388 DCHECK_EQ(0, node->op()->EffectInputCount());
389 DCHECK_EQ(0, node->op()->EffectOutputCount());
393 Reduction RedundancyElimination::TakeChecksFromFirstEffect(Node* node) {
394 DCHECK_EQ(1, node->op()->EffectOutputCount());
395 Node*
const effect = NodeProperties::GetEffectInput(node);
396 EffectPathChecks
const* checks = node_checks_.Get(effect);
399 if (checks ==
nullptr)
return NoChange();
402 return UpdateChecks(node, checks);
405 Reduction RedundancyElimination::UpdateChecks(Node* node,
406 EffectPathChecks
const* checks) {
407 EffectPathChecks
const* original = node_checks_.Get(node);
410 if (checks != original) {
411 if (original ==
nullptr || !checks->Equals(original)) {
412 node_checks_.Set(node, checks);
413 return Changed(node);