Line data Source code
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
3 : // found in the LICENSE file.
4 :
5 : #include "src/ic/binary-op-assembler.h"
6 :
7 : #include "src/globals.h"
8 :
9 : namespace v8 {
10 : namespace internal {
11 :
12 : using compiler::Node;
13 :
14 172 : Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
15 : Node* rhs, Node* slot_id,
16 : Node* feedback_vector) {
17 : // Shared entry for floating point addition.
18 344 : Label do_fadd(this), if_lhsisnotnumber(this, Label::kDeferred),
19 172 : check_rhsisoddball(this, Label::kDeferred),
20 172 : call_with_oddball_feedback(this), call_with_any_feedback(this),
21 172 : call_add_stub(this), end(this);
22 344 : VARIABLE(var_fadd_lhs, MachineRepresentation::kFloat64);
23 344 : VARIABLE(var_fadd_rhs, MachineRepresentation::kFloat64);
24 344 : VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned);
25 344 : VARIABLE(var_result, MachineRepresentation::kTagged);
26 :
27 : // Check if the {lhs} is a Smi or a HeapObject.
28 172 : Label if_lhsissmi(this), if_lhsisnotsmi(this);
29 172 : Branch(TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
30 :
31 172 : BIND(&if_lhsissmi);
32 : {
33 : // Check if the {rhs} is also a Smi.
34 172 : Label if_rhsissmi(this), if_rhsisnotsmi(this);
35 172 : Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
36 :
37 172 : BIND(&if_rhsissmi);
38 : {
39 : // Try fast Smi addition first.
40 : Node* pair = IntPtrAddWithOverflow(BitcastTaggedToWord(lhs),
41 172 : BitcastTaggedToWord(rhs));
42 172 : Node* overflow = Projection(1, pair);
43 :
44 : // Check if the Smi additon overflowed.
45 172 : Label if_overflow(this), if_notoverflow(this);
46 172 : Branch(overflow, &if_overflow, &if_notoverflow);
47 :
48 172 : BIND(&if_overflow);
49 : {
50 172 : var_fadd_lhs.Bind(SmiToFloat64(lhs));
51 172 : var_fadd_rhs.Bind(SmiToFloat64(rhs));
52 172 : Goto(&do_fadd);
53 : }
54 :
55 172 : BIND(&if_notoverflow);
56 : {
57 : var_type_feedback.Bind(
58 172 : SmiConstant(BinaryOperationFeedback::kSignedSmall));
59 172 : var_result.Bind(BitcastWordToTaggedSigned(Projection(0, pair)));
60 172 : Goto(&end);
61 172 : }
62 : }
63 :
64 172 : BIND(&if_rhsisnotsmi);
65 : {
66 : // Load the map of {rhs}.
67 172 : Node* rhs_map = LoadMap(rhs);
68 :
69 : // Check if the {rhs} is a HeapNumber.
70 172 : GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball);
71 :
72 172 : var_fadd_lhs.Bind(SmiToFloat64(lhs));
73 172 : var_fadd_rhs.Bind(LoadHeapNumberValue(rhs));
74 172 : Goto(&do_fadd);
75 172 : }
76 : }
77 :
78 172 : BIND(&if_lhsisnotsmi);
79 : {
80 : // Load the map of {lhs}.
81 172 : Node* lhs_map = LoadMap(lhs);
82 :
83 : // Check if {lhs} is a HeapNumber.
84 172 : GotoIfNot(IsHeapNumberMap(lhs_map), &if_lhsisnotnumber);
85 :
86 : // Check if the {rhs} is Smi.
87 172 : Label if_rhsissmi(this), if_rhsisnotsmi(this);
88 172 : Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
89 :
90 172 : BIND(&if_rhsissmi);
91 : {
92 172 : var_fadd_lhs.Bind(LoadHeapNumberValue(lhs));
93 172 : var_fadd_rhs.Bind(SmiToFloat64(rhs));
94 172 : Goto(&do_fadd);
95 : }
96 :
97 172 : BIND(&if_rhsisnotsmi);
98 : {
99 : // Load the map of {rhs}.
100 172 : Node* rhs_map = LoadMap(rhs);
101 :
102 : // Check if the {rhs} is a HeapNumber.
103 172 : GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball);
104 :
105 172 : var_fadd_lhs.Bind(LoadHeapNumberValue(lhs));
106 172 : var_fadd_rhs.Bind(LoadHeapNumberValue(rhs));
107 172 : Goto(&do_fadd);
108 172 : }
109 : }
110 :
111 172 : BIND(&do_fadd);
112 : {
113 172 : var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber));
114 172 : Node* value = Float64Add(var_fadd_lhs.value(), var_fadd_rhs.value());
115 172 : Node* result = AllocateHeapNumberWithValue(value);
116 172 : var_result.Bind(result);
117 172 : Goto(&end);
118 : }
119 :
120 172 : BIND(&if_lhsisnotnumber);
121 : {
122 : // No checks on rhs are done yet. We just know lhs is not a number or Smi.
123 172 : Label if_lhsisoddball(this), if_lhsisnotoddball(this);
124 172 : Node* lhs_instance_type = LoadInstanceType(lhs);
125 : Node* lhs_is_oddball =
126 172 : Word32Equal(lhs_instance_type, Int32Constant(ODDBALL_TYPE));
127 172 : Branch(lhs_is_oddball, &if_lhsisoddball, &if_lhsisnotoddball);
128 :
129 172 : BIND(&if_lhsisoddball);
130 : {
131 172 : GotoIf(TaggedIsSmi(rhs), &call_with_oddball_feedback);
132 :
133 : // Load the map of the {rhs}.
134 172 : Node* rhs_map = LoadMap(rhs);
135 :
136 : // Check if {rhs} is a HeapNumber.
137 : Branch(IsHeapNumberMap(rhs_map), &call_with_oddball_feedback,
138 172 : &check_rhsisoddball);
139 : }
140 :
141 172 : BIND(&if_lhsisnotoddball);
142 : {
143 : // Exit unless {lhs} is a string
144 : GotoIfNot(IsStringInstanceType(lhs_instance_type),
145 172 : &call_with_any_feedback);
146 :
147 : // Check if the {rhs} is a smi, and exit the string check early if it is.
148 172 : GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback);
149 :
150 172 : Node* rhs_instance_type = LoadInstanceType(rhs);
151 :
152 : // Exit unless {rhs} is a string. Since {lhs} is a string we no longer
153 : // need an Oddball check.
154 : GotoIfNot(IsStringInstanceType(rhs_instance_type),
155 172 : &call_with_any_feedback);
156 :
157 172 : var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kString));
158 : Callable callable =
159 172 : CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
160 172 : var_result.Bind(CallStub(callable, context, lhs, rhs));
161 :
162 172 : Goto(&end);
163 172 : }
164 : }
165 :
166 172 : BIND(&check_rhsisoddball);
167 : {
168 : // Check if rhs is an oddball. At this point we know lhs is either a
169 : // Smi or number or oddball and rhs is not a number or Smi.
170 172 : Node* rhs_instance_type = LoadInstanceType(rhs);
171 : Node* rhs_is_oddball =
172 172 : Word32Equal(rhs_instance_type, Int32Constant(ODDBALL_TYPE));
173 : Branch(rhs_is_oddball, &call_with_oddball_feedback,
174 172 : &call_with_any_feedback);
175 : }
176 :
177 172 : BIND(&call_with_oddball_feedback);
178 : {
179 : var_type_feedback.Bind(
180 172 : SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
181 172 : Goto(&call_add_stub);
182 : }
183 :
184 172 : BIND(&call_with_any_feedback);
185 : {
186 172 : var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny));
187 172 : Goto(&call_add_stub);
188 : }
189 :
190 172 : BIND(&call_add_stub);
191 : {
192 172 : Callable callable = CodeFactory::Add(isolate());
193 172 : var_result.Bind(CallStub(callable, context, lhs, rhs));
194 172 : Goto(&end);
195 : }
196 :
197 172 : BIND(&end);
198 172 : UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id);
199 344 : return var_result.value();
200 : }
201 :
202 172 : Node* BinaryOpAssembler::Generate_SubtractWithFeedback(Node* context, Node* lhs,
203 : Node* rhs, Node* slot_id,
204 : Node* feedback_vector) {
205 : // Shared entry for floating point subtraction.
206 344 : Label do_fsub(this), end(this), call_subtract_stub(this),
207 172 : if_lhsisnotnumber(this), check_rhsisoddball(this),
208 172 : call_with_any_feedback(this);
209 344 : VARIABLE(var_fsub_lhs, MachineRepresentation::kFloat64);
210 344 : VARIABLE(var_fsub_rhs, MachineRepresentation::kFloat64);
211 344 : VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned);
212 344 : VARIABLE(var_result, MachineRepresentation::kTagged);
213 :
214 : // Check if the {lhs} is a Smi or a HeapObject.
215 172 : Label if_lhsissmi(this), if_lhsisnotsmi(this);
216 172 : Branch(TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
217 :
218 172 : BIND(&if_lhsissmi);
219 : {
220 : // Check if the {rhs} is also a Smi.
221 172 : Label if_rhsissmi(this), if_rhsisnotsmi(this);
222 172 : Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
223 :
224 172 : BIND(&if_rhsissmi);
225 : {
226 : // Try a fast Smi subtraction first.
227 : Node* pair = IntPtrSubWithOverflow(BitcastTaggedToWord(lhs),
228 172 : BitcastTaggedToWord(rhs));
229 172 : Node* overflow = Projection(1, pair);
230 :
231 : // Check if the Smi subtraction overflowed.
232 172 : Label if_overflow(this), if_notoverflow(this);
233 172 : Branch(overflow, &if_overflow, &if_notoverflow);
234 :
235 172 : BIND(&if_overflow);
236 : {
237 : // lhs, rhs - smi and result - number. combined - number.
238 : // The result doesn't fit into Smi range.
239 172 : var_fsub_lhs.Bind(SmiToFloat64(lhs));
240 172 : var_fsub_rhs.Bind(SmiToFloat64(rhs));
241 172 : Goto(&do_fsub);
242 : }
243 :
244 172 : BIND(&if_notoverflow);
245 : // lhs, rhs, result smi. combined - smi.
246 : var_type_feedback.Bind(
247 172 : SmiConstant(BinaryOperationFeedback::kSignedSmall));
248 172 : var_result.Bind(BitcastWordToTaggedSigned(Projection(0, pair)));
249 344 : Goto(&end);
250 : }
251 :
252 172 : BIND(&if_rhsisnotsmi);
253 : {
254 : // Load the map of the {rhs}.
255 172 : Node* rhs_map = LoadMap(rhs);
256 :
257 : // Check if {rhs} is a HeapNumber.
258 172 : GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball);
259 :
260 : // Perform a floating point subtraction.
261 172 : var_fsub_lhs.Bind(SmiToFloat64(lhs));
262 172 : var_fsub_rhs.Bind(LoadHeapNumberValue(rhs));
263 172 : Goto(&do_fsub);
264 172 : }
265 : }
266 :
267 172 : BIND(&if_lhsisnotsmi);
268 : {
269 : // Load the map of the {lhs}.
270 172 : Node* lhs_map = LoadMap(lhs);
271 :
272 : // Check if the {lhs} is a HeapNumber.
273 172 : GotoIfNot(IsHeapNumberMap(lhs_map), &if_lhsisnotnumber);
274 :
275 : // Check if the {rhs} is a Smi.
276 172 : Label if_rhsissmi(this), if_rhsisnotsmi(this);
277 172 : Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
278 :
279 172 : BIND(&if_rhsissmi);
280 : {
281 : // Perform a floating point subtraction.
282 172 : var_fsub_lhs.Bind(LoadHeapNumberValue(lhs));
283 172 : var_fsub_rhs.Bind(SmiToFloat64(rhs));
284 172 : Goto(&do_fsub);
285 : }
286 :
287 172 : BIND(&if_rhsisnotsmi);
288 : {
289 : // Load the map of the {rhs}.
290 172 : Node* rhs_map = LoadMap(rhs);
291 :
292 : // Check if the {rhs} is a HeapNumber.
293 172 : GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball);
294 :
295 : // Perform a floating point subtraction.
296 172 : var_fsub_lhs.Bind(LoadHeapNumberValue(lhs));
297 172 : var_fsub_rhs.Bind(LoadHeapNumberValue(rhs));
298 172 : Goto(&do_fsub);
299 172 : }
300 : }
301 :
302 172 : BIND(&do_fsub);
303 : {
304 172 : var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber));
305 172 : Node* lhs_value = var_fsub_lhs.value();
306 172 : Node* rhs_value = var_fsub_rhs.value();
307 172 : Node* value = Float64Sub(lhs_value, rhs_value);
308 172 : var_result.Bind(AllocateHeapNumberWithValue(value));
309 172 : Goto(&end);
310 : }
311 :
312 172 : BIND(&if_lhsisnotnumber);
313 : {
314 : // No checks on rhs are done yet. We just know lhs is not a number or Smi.
315 : // Check if lhs is an oddball.
316 172 : Node* lhs_instance_type = LoadInstanceType(lhs);
317 : Node* lhs_is_oddball =
318 172 : Word32Equal(lhs_instance_type, Int32Constant(ODDBALL_TYPE));
319 172 : GotoIfNot(lhs_is_oddball, &call_with_any_feedback);
320 :
321 172 : Label if_rhsissmi(this), if_rhsisnotsmi(this);
322 172 : Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
323 :
324 172 : BIND(&if_rhsissmi);
325 : {
326 : var_type_feedback.Bind(
327 172 : SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
328 172 : Goto(&call_subtract_stub);
329 : }
330 :
331 172 : BIND(&if_rhsisnotsmi);
332 : {
333 : // Load the map of the {rhs}.
334 172 : Node* rhs_map = LoadMap(rhs);
335 :
336 : // Check if {rhs} is a HeapNumber.
337 172 : GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball);
338 :
339 : var_type_feedback.Bind(
340 172 : SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
341 172 : Goto(&call_subtract_stub);
342 172 : }
343 : }
344 :
345 172 : BIND(&check_rhsisoddball);
346 : {
347 : // Check if rhs is an oddball. At this point we know lhs is either a
348 : // Smi or number or oddball and rhs is not a number or Smi.
349 172 : Node* rhs_instance_type = LoadInstanceType(rhs);
350 : Node* rhs_is_oddball =
351 172 : Word32Equal(rhs_instance_type, Int32Constant(ODDBALL_TYPE));
352 172 : GotoIfNot(rhs_is_oddball, &call_with_any_feedback);
353 :
354 : var_type_feedback.Bind(
355 172 : SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
356 172 : Goto(&call_subtract_stub);
357 : }
358 :
359 172 : BIND(&call_with_any_feedback);
360 : {
361 172 : var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny));
362 172 : Goto(&call_subtract_stub);
363 : }
364 :
365 172 : BIND(&call_subtract_stub);
366 : {
367 172 : Callable callable = CodeFactory::Subtract(isolate());
368 172 : var_result.Bind(CallStub(callable, context, lhs, rhs));
369 172 : Goto(&end);
370 : }
371 :
372 172 : BIND(&end);
373 172 : UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id);
374 344 : return var_result.value();
375 : }
376 :
377 172 : Node* BinaryOpAssembler::Generate_MultiplyWithFeedback(Node* context, Node* lhs,
378 : Node* rhs, Node* slot_id,
379 : Node* feedback_vector) {
380 : // Shared entry point for floating point multiplication.
381 344 : Label do_fmul(this), if_lhsisnotnumber(this, Label::kDeferred),
382 172 : check_rhsisoddball(this, Label::kDeferred),
383 172 : call_with_oddball_feedback(this), call_with_any_feedback(this),
384 172 : call_multiply_stub(this), end(this);
385 344 : VARIABLE(var_lhs_float64, MachineRepresentation::kFloat64);
386 344 : VARIABLE(var_rhs_float64, MachineRepresentation::kFloat64);
387 344 : VARIABLE(var_result, MachineRepresentation::kTagged);
388 344 : VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned);
389 :
390 172 : Label lhs_is_smi(this), lhs_is_not_smi(this);
391 172 : Branch(TaggedIsSmi(lhs), &lhs_is_smi, &lhs_is_not_smi);
392 :
393 172 : BIND(&lhs_is_smi);
394 : {
395 172 : Label rhs_is_smi(this), rhs_is_not_smi(this);
396 172 : Branch(TaggedIsSmi(rhs), &rhs_is_smi, &rhs_is_not_smi);
397 :
398 172 : BIND(&rhs_is_smi);
399 : {
400 : // Both {lhs} and {rhs} are Smis. The result is not necessarily a smi,
401 : // in case of overflow.
402 172 : var_result.Bind(SmiMul(lhs, rhs));
403 : var_type_feedback.Bind(
404 : SelectSmiConstant(TaggedIsSmi(var_result.value()),
405 : BinaryOperationFeedback::kSignedSmall,
406 344 : BinaryOperationFeedback::kNumber));
407 172 : Goto(&end);
408 : }
409 :
410 172 : BIND(&rhs_is_not_smi);
411 : {
412 172 : Node* rhs_map = LoadMap(rhs);
413 :
414 : // Check if {rhs} is a HeapNumber.
415 172 : GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball);
416 :
417 : // Convert {lhs} to a double and multiply it with the value of {rhs}.
418 172 : var_lhs_float64.Bind(SmiToFloat64(lhs));
419 172 : var_rhs_float64.Bind(LoadHeapNumberValue(rhs));
420 172 : Goto(&do_fmul);
421 172 : }
422 : }
423 :
424 172 : BIND(&lhs_is_not_smi);
425 : {
426 172 : Node* lhs_map = LoadMap(lhs);
427 :
428 : // Check if {lhs} is a HeapNumber.
429 172 : GotoIfNot(IsHeapNumberMap(lhs_map), &if_lhsisnotnumber);
430 :
431 : // Check if {rhs} is a Smi.
432 172 : Label rhs_is_smi(this), rhs_is_not_smi(this);
433 172 : Branch(TaggedIsSmi(rhs), &rhs_is_smi, &rhs_is_not_smi);
434 :
435 172 : BIND(&rhs_is_smi);
436 : {
437 : // Convert {rhs} to a double and multiply it with the value of {lhs}.
438 172 : var_lhs_float64.Bind(LoadHeapNumberValue(lhs));
439 172 : var_rhs_float64.Bind(SmiToFloat64(rhs));
440 172 : Goto(&do_fmul);
441 : }
442 :
443 172 : BIND(&rhs_is_not_smi);
444 : {
445 172 : Node* rhs_map = LoadMap(rhs);
446 :
447 : // Check if {rhs} is a HeapNumber.
448 172 : GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball);
449 :
450 : // Both {lhs} and {rhs} are HeapNumbers. Load their values and
451 : // multiply them.
452 172 : var_lhs_float64.Bind(LoadHeapNumberValue(lhs));
453 172 : var_rhs_float64.Bind(LoadHeapNumberValue(rhs));
454 172 : Goto(&do_fmul);
455 172 : }
456 : }
457 :
458 172 : BIND(&do_fmul);
459 : {
460 172 : var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber));
461 172 : Node* value = Float64Mul(var_lhs_float64.value(), var_rhs_float64.value());
462 172 : Node* result = AllocateHeapNumberWithValue(value);
463 172 : var_result.Bind(result);
464 172 : Goto(&end);
465 : }
466 :
467 172 : BIND(&if_lhsisnotnumber);
468 : {
469 : // No checks on rhs are done yet. We just know lhs is not a number or Smi.
470 : // Check if lhs is an oddball.
471 172 : Node* lhs_instance_type = LoadInstanceType(lhs);
472 : Node* lhs_is_oddball =
473 172 : Word32Equal(lhs_instance_type, Int32Constant(ODDBALL_TYPE));
474 172 : GotoIfNot(lhs_is_oddball, &call_with_any_feedback);
475 :
476 172 : GotoIf(TaggedIsSmi(rhs), &call_with_oddball_feedback);
477 :
478 : // Load the map of the {rhs}.
479 172 : Node* rhs_map = LoadMap(rhs);
480 :
481 : // Check if {rhs} is a HeapNumber.
482 : Branch(IsHeapNumberMap(rhs_map), &call_with_oddball_feedback,
483 172 : &check_rhsisoddball);
484 : }
485 :
486 172 : BIND(&check_rhsisoddball);
487 : {
488 : // Check if rhs is an oddball. At this point we know lhs is either a
489 : // Smi or number or oddball and rhs is not a number or Smi.
490 172 : Node* rhs_instance_type = LoadInstanceType(rhs);
491 : Node* rhs_is_oddball =
492 172 : Word32Equal(rhs_instance_type, Int32Constant(ODDBALL_TYPE));
493 : Branch(rhs_is_oddball, &call_with_oddball_feedback,
494 172 : &call_with_any_feedback);
495 : }
496 :
497 172 : BIND(&call_with_oddball_feedback);
498 : {
499 : var_type_feedback.Bind(
500 172 : SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
501 172 : Goto(&call_multiply_stub);
502 : }
503 :
504 172 : BIND(&call_with_any_feedback);
505 : {
506 172 : var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny));
507 172 : Goto(&call_multiply_stub);
508 : }
509 :
510 172 : BIND(&call_multiply_stub);
511 : {
512 172 : Callable callable = CodeFactory::Multiply(isolate());
513 172 : var_result.Bind(CallStub(callable, context, lhs, rhs));
514 172 : Goto(&end);
515 : }
516 :
517 172 : BIND(&end);
518 172 : UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id);
519 344 : return var_result.value();
520 : }
521 :
522 172 : Node* BinaryOpAssembler::Generate_DivideWithFeedback(Node* context,
523 : Node* dividend,
524 : Node* divisor,
525 : Node* slot_id,
526 : Node* feedback_vector) {
527 : // Shared entry point for floating point division.
528 344 : Label do_fdiv(this), dividend_is_not_number(this, Label::kDeferred),
529 172 : check_divisor_for_oddball(this, Label::kDeferred),
530 172 : call_with_oddball_feedback(this), call_with_any_feedback(this),
531 172 : call_divide_stub(this), end(this);
532 344 : VARIABLE(var_dividend_float64, MachineRepresentation::kFloat64);
533 344 : VARIABLE(var_divisor_float64, MachineRepresentation::kFloat64);
534 344 : VARIABLE(var_result, MachineRepresentation::kTagged);
535 344 : VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned);
536 :
537 172 : Label dividend_is_smi(this), dividend_is_not_smi(this);
538 172 : Branch(TaggedIsSmi(dividend), ÷nd_is_smi, ÷nd_is_not_smi);
539 :
540 172 : BIND(÷nd_is_smi);
541 : {
542 172 : Label divisor_is_smi(this), divisor_is_not_smi(this);
543 172 : Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi);
544 :
545 172 : BIND(&divisor_is_smi);
546 : {
547 : Label bailout(this);
548 :
549 : // Try to perform Smi division if possible.
550 172 : var_result.Bind(TrySmiDiv(dividend, divisor, &bailout));
551 : var_type_feedback.Bind(
552 172 : SmiConstant(BinaryOperationFeedback::kSignedSmall));
553 172 : Goto(&end);
554 :
555 : // Bailout: convert {dividend} and {divisor} to double and do double
556 : // division.
557 172 : BIND(&bailout);
558 : {
559 172 : var_dividend_float64.Bind(SmiToFloat64(dividend));
560 172 : var_divisor_float64.Bind(SmiToFloat64(divisor));
561 172 : Goto(&do_fdiv);
562 172 : }
563 : }
564 :
565 172 : BIND(&divisor_is_not_smi);
566 : {
567 172 : Node* divisor_map = LoadMap(divisor);
568 :
569 : // Check if {divisor} is a HeapNumber.
570 172 : GotoIfNot(IsHeapNumberMap(divisor_map), &check_divisor_for_oddball);
571 :
572 : // Convert {dividend} to a double and divide it with the value of
573 : // {divisor}.
574 172 : var_dividend_float64.Bind(SmiToFloat64(dividend));
575 172 : var_divisor_float64.Bind(LoadHeapNumberValue(divisor));
576 172 : Goto(&do_fdiv);
577 : }
578 :
579 172 : BIND(÷nd_is_not_smi);
580 : {
581 172 : Node* dividend_map = LoadMap(dividend);
582 :
583 : // Check if {dividend} is a HeapNumber.
584 172 : GotoIfNot(IsHeapNumberMap(dividend_map), ÷nd_is_not_number);
585 :
586 : // Check if {divisor} is a Smi.
587 172 : Label divisor_is_smi(this), divisor_is_not_smi(this);
588 172 : Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi);
589 :
590 172 : BIND(&divisor_is_smi);
591 : {
592 : // Convert {divisor} to a double and use it for a floating point
593 : // division.
594 172 : var_dividend_float64.Bind(LoadHeapNumberValue(dividend));
595 172 : var_divisor_float64.Bind(SmiToFloat64(divisor));
596 172 : Goto(&do_fdiv);
597 : }
598 :
599 172 : BIND(&divisor_is_not_smi);
600 : {
601 172 : Node* divisor_map = LoadMap(divisor);
602 :
603 : // Check if {divisor} is a HeapNumber.
604 172 : GotoIfNot(IsHeapNumberMap(divisor_map), &check_divisor_for_oddball);
605 :
606 : // Both {dividend} and {divisor} are HeapNumbers. Load their values
607 : // and divide them.
608 172 : var_dividend_float64.Bind(LoadHeapNumberValue(dividend));
609 172 : var_divisor_float64.Bind(LoadHeapNumberValue(divisor));
610 172 : Goto(&do_fdiv);
611 172 : }
612 172 : }
613 : }
614 :
615 172 : BIND(&do_fdiv);
616 : {
617 172 : var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber));
618 : Node* value =
619 172 : Float64Div(var_dividend_float64.value(), var_divisor_float64.value());
620 172 : var_result.Bind(AllocateHeapNumberWithValue(value));
621 172 : Goto(&end);
622 : }
623 :
624 172 : BIND(÷nd_is_not_number);
625 : {
626 : // We just know dividend is not a number or Smi. No checks on divisor yet.
627 : // Check if dividend is an oddball.
628 172 : Node* dividend_instance_type = LoadInstanceType(dividend);
629 : Node* dividend_is_oddball =
630 172 : Word32Equal(dividend_instance_type, Int32Constant(ODDBALL_TYPE));
631 172 : GotoIfNot(dividend_is_oddball, &call_with_any_feedback);
632 :
633 172 : GotoIf(TaggedIsSmi(divisor), &call_with_oddball_feedback);
634 :
635 : // Load the map of the {divisor}.
636 172 : Node* divisor_map = LoadMap(divisor);
637 :
638 : // Check if {divisor} is a HeapNumber.
639 : Branch(IsHeapNumberMap(divisor_map), &call_with_oddball_feedback,
640 172 : &check_divisor_for_oddball);
641 : }
642 :
643 172 : BIND(&check_divisor_for_oddball);
644 : {
645 : // Check if divisor is an oddball. At this point we know dividend is either
646 : // a Smi or number or oddball and divisor is not a number or Smi.
647 172 : Node* divisor_instance_type = LoadInstanceType(divisor);
648 : Node* divisor_is_oddball =
649 172 : Word32Equal(divisor_instance_type, Int32Constant(ODDBALL_TYPE));
650 : Branch(divisor_is_oddball, &call_with_oddball_feedback,
651 172 : &call_with_any_feedback);
652 : }
653 :
654 172 : BIND(&call_with_oddball_feedback);
655 : {
656 : var_type_feedback.Bind(
657 172 : SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
658 172 : Goto(&call_divide_stub);
659 : }
660 :
661 172 : BIND(&call_with_any_feedback);
662 : {
663 172 : var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny));
664 172 : Goto(&call_divide_stub);
665 : }
666 :
667 172 : BIND(&call_divide_stub);
668 : {
669 172 : Callable callable = CodeFactory::Divide(isolate());
670 172 : var_result.Bind(CallStub(callable, context, dividend, divisor));
671 172 : Goto(&end);
672 : }
673 :
674 172 : BIND(&end);
675 172 : UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id);
676 344 : return var_result.value();
677 : }
678 :
679 172 : Node* BinaryOpAssembler::Generate_ModulusWithFeedback(Node* context,
680 : Node* dividend,
681 : Node* divisor,
682 : Node* slot_id,
683 : Node* feedback_vector) {
684 : // Shared entry point for floating point division.
685 344 : Label do_fmod(this), dividend_is_not_number(this, Label::kDeferred),
686 172 : check_divisor_for_oddball(this, Label::kDeferred),
687 172 : call_with_oddball_feedback(this), call_with_any_feedback(this),
688 172 : call_modulus_stub(this), end(this);
689 344 : VARIABLE(var_dividend_float64, MachineRepresentation::kFloat64);
690 344 : VARIABLE(var_divisor_float64, MachineRepresentation::kFloat64);
691 344 : VARIABLE(var_result, MachineRepresentation::kTagged);
692 344 : VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned);
693 :
694 172 : Label dividend_is_smi(this), dividend_is_not_smi(this);
695 172 : Branch(TaggedIsSmi(dividend), ÷nd_is_smi, ÷nd_is_not_smi);
696 :
697 172 : BIND(÷nd_is_smi);
698 : {
699 172 : Label divisor_is_smi(this), divisor_is_not_smi(this);
700 172 : Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi);
701 :
702 172 : BIND(&divisor_is_smi);
703 : {
704 172 : var_result.Bind(SmiMod(dividend, divisor));
705 : var_type_feedback.Bind(
706 : SelectSmiConstant(TaggedIsSmi(var_result.value()),
707 : BinaryOperationFeedback::kSignedSmall,
708 344 : BinaryOperationFeedback::kNumber));
709 172 : Goto(&end);
710 : }
711 :
712 172 : BIND(&divisor_is_not_smi);
713 : {
714 172 : Node* divisor_map = LoadMap(divisor);
715 :
716 : // Check if {divisor} is a HeapNumber.
717 172 : GotoIfNot(IsHeapNumberMap(divisor_map), &check_divisor_for_oddball);
718 :
719 : // Convert {dividend} to a double and divide it with the value of
720 : // {divisor}.
721 172 : var_dividend_float64.Bind(SmiToFloat64(dividend));
722 172 : var_divisor_float64.Bind(LoadHeapNumberValue(divisor));
723 172 : Goto(&do_fmod);
724 172 : }
725 : }
726 :
727 172 : BIND(÷nd_is_not_smi);
728 : {
729 172 : Node* dividend_map = LoadMap(dividend);
730 :
731 : // Check if {dividend} is a HeapNumber.
732 172 : GotoIfNot(IsHeapNumberMap(dividend_map), ÷nd_is_not_number);
733 :
734 : // Check if {divisor} is a Smi.
735 172 : Label divisor_is_smi(this), divisor_is_not_smi(this);
736 172 : Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi);
737 :
738 172 : BIND(&divisor_is_smi);
739 : {
740 : // Convert {divisor} to a double and use it for a floating point
741 : // division.
742 172 : var_dividend_float64.Bind(LoadHeapNumberValue(dividend));
743 172 : var_divisor_float64.Bind(SmiToFloat64(divisor));
744 172 : Goto(&do_fmod);
745 : }
746 :
747 172 : BIND(&divisor_is_not_smi);
748 : {
749 172 : Node* divisor_map = LoadMap(divisor);
750 :
751 : // Check if {divisor} is a HeapNumber.
752 172 : GotoIfNot(IsHeapNumberMap(divisor_map), &check_divisor_for_oddball);
753 :
754 : // Both {dividend} and {divisor} are HeapNumbers. Load their values
755 : // and divide them.
756 172 : var_dividend_float64.Bind(LoadHeapNumberValue(dividend));
757 172 : var_divisor_float64.Bind(LoadHeapNumberValue(divisor));
758 172 : Goto(&do_fmod);
759 172 : }
760 : }
761 :
762 172 : BIND(&do_fmod);
763 : {
764 172 : var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber));
765 : Node* value =
766 172 : Float64Mod(var_dividend_float64.value(), var_divisor_float64.value());
767 172 : var_result.Bind(AllocateHeapNumberWithValue(value));
768 172 : Goto(&end);
769 : }
770 :
771 172 : BIND(÷nd_is_not_number);
772 : {
773 : // No checks on divisor yet. We just know dividend is not a number or Smi.
774 : // Check if dividend is an oddball.
775 172 : Node* dividend_instance_type = LoadInstanceType(dividend);
776 : Node* dividend_is_oddball =
777 172 : Word32Equal(dividend_instance_type, Int32Constant(ODDBALL_TYPE));
778 172 : GotoIfNot(dividend_is_oddball, &call_with_any_feedback);
779 :
780 172 : GotoIf(TaggedIsSmi(divisor), &call_with_oddball_feedback);
781 :
782 : // Load the map of the {divisor}.
783 172 : Node* divisor_map = LoadMap(divisor);
784 :
785 : // Check if {divisor} is a HeapNumber.
786 : Branch(IsHeapNumberMap(divisor_map), &call_with_oddball_feedback,
787 172 : &check_divisor_for_oddball);
788 : }
789 :
790 172 : BIND(&check_divisor_for_oddball);
791 : {
792 : // Check if divisor is an oddball. At this point we know dividend is either
793 : // a Smi or number or oddball and divisor is not a number or Smi.
794 172 : Node* divisor_instance_type = LoadInstanceType(divisor);
795 : Node* divisor_is_oddball =
796 172 : Word32Equal(divisor_instance_type, Int32Constant(ODDBALL_TYPE));
797 : Branch(divisor_is_oddball, &call_with_oddball_feedback,
798 172 : &call_with_any_feedback);
799 : }
800 :
801 172 : BIND(&call_with_oddball_feedback);
802 : {
803 : var_type_feedback.Bind(
804 172 : SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
805 172 : Goto(&call_modulus_stub);
806 : }
807 :
808 172 : BIND(&call_with_any_feedback);
809 : {
810 172 : var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny));
811 172 : Goto(&call_modulus_stub);
812 : }
813 :
814 172 : BIND(&call_modulus_stub);
815 : {
816 172 : Callable callable = CodeFactory::Modulus(isolate());
817 172 : var_result.Bind(CallStub(callable, context, dividend, divisor));
818 172 : Goto(&end);
819 : }
820 :
821 172 : BIND(&end);
822 172 : UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id);
823 344 : return var_result.value();
824 : }
825 :
826 : } // namespace internal
827 : } // namespace v8
|