5 #include "src/ic/binary-op-assembler.h" 7 #include "src/globals.h" 14 Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
15 Node* rhs, Node* slot_id,
16 Node* feedback_vector,
19 Label do_fadd(
this), if_lhsisnotnumber(
this, Label::kDeferred),
20 check_rhsisoddball(
this, Label::kDeferred),
21 call_with_oddball_feedback(
this), call_with_any_feedback(
this),
22 call_add_stub(
this), end(
this), bigint(
this, Label::kDeferred);
23 VARIABLE(var_fadd_lhs, MachineRepresentation::kFloat64);
24 VARIABLE(var_fadd_rhs, MachineRepresentation::kFloat64);
25 VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned);
26 VARIABLE(var_result, MachineRepresentation::kTagged);
29 Label if_lhsissmi(
this);
34 Label if_lhsisnotsmi(
this,
35 rhs_is_smi ? Label::kDeferred : Label::kNonDeferred);
36 Branch(TaggedIsNotSmi(lhs), &if_lhsisnotsmi, &if_lhsissmi);
40 Comment(
"lhs is Smi");
43 Label if_rhsissmi(
this), if_rhsisnotsmi(
this);
44 Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
46 BIND(&if_rhsisnotsmi);
49 GotoIfNot(IsHeapNumber(rhs), &check_rhsisoddball);
51 var_fadd_lhs.Bind(SmiToFloat64(lhs));
52 var_fadd_rhs.Bind(LoadHeapNumberValue(rhs));
60 Comment(
"perform smi operation");
65 Label if_overflow(
this,
66 rhs_is_smi ? Label::kDeferred : Label::kNonDeferred);
67 TNode<Smi> smi_result = TrySmiAdd(CAST(lhs), CAST(rhs), &if_overflow);
70 var_type_feedback.Bind(
71 SmiConstant(BinaryOperationFeedback::kSignedSmall));
72 var_result.Bind(smi_result);
78 var_fadd_lhs.Bind(SmiToFloat64(lhs));
79 var_fadd_rhs.Bind(SmiToFloat64(rhs));
85 BIND(&if_lhsisnotsmi);
88 GotoIfNot(IsHeapNumber(lhs), &if_lhsisnotnumber);
92 Label if_rhsissmi(
this), if_rhsisnotsmi(
this);
93 Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
95 BIND(&if_rhsisnotsmi);
98 GotoIfNot(IsHeapNumber(rhs), &check_rhsisoddball);
100 var_fadd_lhs.Bind(LoadHeapNumberValue(lhs));
101 var_fadd_rhs.Bind(LoadHeapNumberValue(rhs));
108 var_fadd_lhs.Bind(LoadHeapNumberValue(lhs));
109 var_fadd_rhs.Bind(SmiToFloat64(rhs));
116 var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber));
117 Node* value = Float64Add(var_fadd_lhs.value(), var_fadd_rhs.value());
118 Node* result = AllocateHeapNumberWithValue(value);
119 var_result.Bind(result);
123 BIND(&if_lhsisnotnumber);
126 Label if_lhsisoddball(
this), if_lhsisnotoddball(
this);
127 Node* lhs_instance_type = LoadInstanceType(lhs);
128 Node* lhs_is_oddball = InstanceTypeEqual(lhs_instance_type, ODDBALL_TYPE);
129 Branch(lhs_is_oddball, &if_lhsisoddball, &if_lhsisnotoddball);
131 BIND(&if_lhsisoddball);
133 GotoIf(TaggedIsSmi(rhs), &call_with_oddball_feedback);
136 Branch(IsHeapNumber(rhs), &call_with_oddball_feedback,
137 &check_rhsisoddball);
140 BIND(&if_lhsisnotoddball);
142 Label lhs_is_string(
this), lhs_is_bigint(
this);
143 GotoIf(IsStringInstanceType(lhs_instance_type), &lhs_is_string);
144 GotoIf(IsBigIntInstanceType(lhs_instance_type), &lhs_is_bigint);
145 Goto(&call_with_any_feedback);
147 BIND(&lhs_is_bigint);
149 GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback);
150 Branch(IsBigInt(rhs), &bigint, &call_with_any_feedback);
153 BIND(&lhs_is_string);
155 GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback);
157 Node* rhs_instance_type = LoadInstanceType(rhs);
161 GotoIfNot(IsStringInstanceType(rhs_instance_type),
162 &call_with_any_feedback);
164 var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kString));
166 CallBuiltin(Builtins::kStringAdd_CheckNone, context, lhs, rhs));
172 BIND(&check_rhsisoddball);
176 Node* rhs_instance_type = LoadInstanceType(rhs);
177 Node* rhs_is_oddball = InstanceTypeEqual(rhs_instance_type, ODDBALL_TYPE);
178 GotoIf(rhs_is_oddball, &call_with_oddball_feedback);
179 Branch(IsBigIntInstanceType(rhs_instance_type), &bigint,
180 &call_with_any_feedback);
185 var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kBigInt));
186 var_result.Bind(CallRuntime(Runtime::kBigIntBinaryOp, context, lhs, rhs,
187 SmiConstant(Operation::kAdd)));
191 BIND(&call_with_oddball_feedback);
193 var_type_feedback.Bind(
194 SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
195 Goto(&call_add_stub);
198 BIND(&call_with_any_feedback);
200 var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny));
201 Goto(&call_add_stub);
204 BIND(&call_add_stub);
206 var_result.Bind(CallBuiltin(Builtins::kAdd, context, lhs, rhs));
211 UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id);
212 return var_result.value();
215 Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
216 Node* context, Node* lhs, Node* rhs, Node* slot_id, Node* feedback_vector,
217 const SmiOperation& smiOperation,
const FloatOperation& floatOperation,
218 Operation op,
bool rhs_is_smi) {
219 Label do_float_operation(
this), end(
this), call_stub(
this),
220 check_rhsisoddball(
this, Label::kDeferred), call_with_any_feedback(
this),
221 if_lhsisnotnumber(
this, Label::kDeferred),
222 if_bigint(
this, Label::kDeferred);
223 VARIABLE(var_float_lhs, MachineRepresentation::kFloat64);
224 VARIABLE(var_float_rhs, MachineRepresentation::kFloat64);
225 VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned);
226 VARIABLE(var_result, MachineRepresentation::kTagged);
228 Label if_lhsissmi(
this);
233 Label if_lhsisnotsmi(
this,
234 rhs_is_smi ? Label::kDeferred : Label::kNonDeferred);
235 Branch(TaggedIsNotSmi(lhs), &if_lhsisnotsmi, &if_lhsissmi);
240 Comment(
"lhs is Smi");
243 Label if_rhsissmi(
this), if_rhsisnotsmi(
this);
244 Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
245 BIND(&if_rhsisnotsmi);
248 GotoIfNot(IsHeapNumber(rhs), &check_rhsisoddball);
251 var_float_lhs.Bind(SmiToFloat64(lhs));
252 var_float_rhs.Bind(LoadHeapNumberValue(rhs));
253 Goto(&do_float_operation);
260 Comment(
"perform smi operation");
261 var_result.Bind(smiOperation(lhs, rhs, &var_type_feedback));
266 BIND(&if_lhsisnotsmi);
268 Comment(
"lhs is not Smi");
270 GotoIfNot(IsHeapNumber(lhs), &if_lhsisnotnumber);
274 Label if_rhsissmi(
this), if_rhsisnotsmi(
this);
275 Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
277 BIND(&if_rhsisnotsmi);
280 GotoIfNot(IsHeapNumber(rhs), &check_rhsisoddball);
283 var_float_lhs.Bind(LoadHeapNumberValue(lhs));
284 var_float_rhs.Bind(LoadHeapNumberValue(rhs));
285 Goto(&do_float_operation);
293 var_float_lhs.Bind(LoadHeapNumberValue(lhs));
294 var_float_rhs.Bind(SmiToFloat64(rhs));
295 Goto(&do_float_operation);
299 BIND(&do_float_operation);
301 var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber));
302 Node* lhs_value = var_float_lhs.value();
303 Node* rhs_value = var_float_rhs.value();
304 Node* value = floatOperation(lhs_value, rhs_value);
305 var_result.Bind(AllocateHeapNumberWithValue(value));
309 BIND(&if_lhsisnotnumber);
312 Label if_left_bigint(
this), if_left_oddball(
this);
313 Node* lhs_instance_type = LoadInstanceType(lhs);
314 GotoIf(IsBigIntInstanceType(lhs_instance_type), &if_left_bigint);
315 Node* lhs_is_oddball = InstanceTypeEqual(lhs_instance_type, ODDBALL_TYPE);
316 Branch(lhs_is_oddball, &if_left_oddball, &call_with_any_feedback);
318 BIND(&if_left_oddball);
320 Label if_rhsissmi(
this), if_rhsisnotsmi(
this);
321 Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
325 var_type_feedback.Bind(
326 SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
330 BIND(&if_rhsisnotsmi);
333 GotoIfNot(IsHeapNumber(rhs), &check_rhsisoddball);
335 var_type_feedback.Bind(
336 SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
341 BIND(&if_left_bigint);
343 GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback);
344 Branch(IsBigInt(rhs), &if_bigint, &call_with_any_feedback);
348 BIND(&check_rhsisoddball);
352 Node* rhs_instance_type = LoadInstanceType(rhs);
353 GotoIf(IsBigIntInstanceType(rhs_instance_type), &if_bigint);
354 Node* rhs_is_oddball = InstanceTypeEqual(rhs_instance_type, ODDBALL_TYPE);
355 GotoIfNot(rhs_is_oddball, &call_with_any_feedback);
357 var_type_feedback.Bind(
358 SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
365 var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kBigInt));
366 var_result.Bind(CallRuntime(Runtime::kBigIntBinaryOp, context, lhs, rhs,
371 BIND(&call_with_any_feedback);
373 var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny));
381 case Operation::kSubtract:
382 result = CallBuiltin(Builtins::kSubtract, context, lhs, rhs);
384 case Operation::kMultiply:
385 result = CallBuiltin(Builtins::kMultiply, context, lhs, rhs);
387 case Operation::kDivide:
388 result = CallBuiltin(Builtins::kDivide, context, lhs, rhs);
390 case Operation::kModulus:
391 result = CallBuiltin(Builtins::kModulus, context, lhs, rhs);
396 var_result.Bind(result);
401 UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id);
402 return var_result.value();
405 Node* BinaryOpAssembler::Generate_SubtractWithFeedback(Node* context, Node* lhs,
406 Node* rhs, Node* slot_id,
407 Node* feedback_vector,
409 auto smiFunction = [=](Node* lhs, Node* rhs, Variable* var_type_feedback) {
411 TVARIABLE(Number, var_result);
415 Label if_overflow(
this,
416 rhs_is_smi ? Label::kDeferred : Label::kNonDeferred);
417 var_result = TrySmiSub(CAST(lhs), CAST(rhs), &if_overflow);
418 var_type_feedback->Bind(SmiConstant(BinaryOperationFeedback::kSignedSmall));
423 var_type_feedback->Bind(SmiConstant(BinaryOperationFeedback::kNumber));
424 Node* value = Float64Sub(SmiToFloat64(lhs), SmiToFloat64(rhs));
425 var_result = AllocateHeapNumberWithValue(value);
430 return var_result.value();
432 auto floatFunction = [=](Node* lhs, Node* rhs) {
433 return Float64Sub(lhs, rhs);
435 return Generate_BinaryOperationWithFeedback(
436 context, lhs, rhs, slot_id, feedback_vector, smiFunction, floatFunction,
437 Operation::kSubtract, rhs_is_smi);
440 Node* BinaryOpAssembler::Generate_MultiplyWithFeedback(Node* context, Node* lhs,
441 Node* rhs, Node* slot_id,
442 Node* feedback_vector,
444 auto smiFunction = [=](Node* lhs, Node* rhs, Variable* var_type_feedback) {
445 TNode<Number> result = SmiMul(CAST(lhs), CAST(rhs));
446 var_type_feedback->Bind(SelectSmiConstant(
447 TaggedIsSmi(result), BinaryOperationFeedback::kSignedSmall,
448 BinaryOperationFeedback::kNumber));
451 auto floatFunction = [=](Node* lhs, Node* rhs) {
452 return Float64Mul(lhs, rhs);
454 return Generate_BinaryOperationWithFeedback(
455 context, lhs, rhs, slot_id, feedback_vector, smiFunction, floatFunction,
456 Operation::kMultiply, rhs_is_smi);
459 Node* BinaryOpAssembler::Generate_DivideWithFeedback(
460 Node* context, Node* dividend, Node* divisor, Node* slot_id,
461 Node* feedback_vector,
bool rhs_is_smi) {
462 auto smiFunction = [=](Node* lhs, Node* rhs, Variable* var_type_feedback) {
463 VARIABLE(var_result, MachineRepresentation::kTagged);
467 Label bailout(
this, rhs_is_smi ? Label::kDeferred : Label::kNonDeferred),
469 var_result.Bind(TrySmiDiv(CAST(lhs), CAST(rhs), &bailout));
470 var_type_feedback->Bind(SmiConstant(BinaryOperationFeedback::kSignedSmall));
475 var_type_feedback->Bind(
476 SmiConstant(BinaryOperationFeedback::kSignedSmallInputs));
477 Node* value = Float64Div(SmiToFloat64(lhs), SmiToFloat64(rhs));
478 var_result.Bind(AllocateHeapNumberWithValue(value));
483 return var_result.value();
485 auto floatFunction = [=](Node* lhs, Node* rhs) {
486 return Float64Div(lhs, rhs);
488 return Generate_BinaryOperationWithFeedback(
489 context, dividend, divisor, slot_id, feedback_vector, smiFunction,
490 floatFunction, Operation::kDivide, rhs_is_smi);
493 Node* BinaryOpAssembler::Generate_ModulusWithFeedback(
494 Node* context, Node* dividend, Node* divisor, Node* slot_id,
495 Node* feedback_vector,
bool rhs_is_smi) {
496 auto smiFunction = [=](Node* lhs, Node* rhs, Variable* var_type_feedback) {
497 TNode<Number> result = SmiMod(CAST(lhs), CAST(rhs));
498 var_type_feedback->Bind(SelectSmiConstant(
499 TaggedIsSmi(result), BinaryOperationFeedback::kSignedSmall,
500 BinaryOperationFeedback::kNumber));
503 auto floatFunction = [=](Node* lhs, Node* rhs) {
504 return Float64Mod(lhs, rhs);
506 return Generate_BinaryOperationWithFeedback(
507 context, dividend, divisor, slot_id, feedback_vector, smiFunction,
508 floatFunction, Operation::kModulus, rhs_is_smi);
511 Node* BinaryOpAssembler::Generate_ExponentiateWithFeedback(
512 Node* context, Node* base, Node* exponent, Node* slot_id,
513 Node* feedback_vector,
bool rhs_is_smi) {
515 Node* dummy_feedback = SmiConstant(BinaryOperationFeedback::kAny);
516 UpdateFeedback(dummy_feedback, feedback_vector, slot_id);
517 return CallBuiltin(Builtins::kExponentiate, context, base, exponent);