11cb0ef41Sopenharmony_ci// Copyright 2019 the V8 project authors. All rights reserved. Use of this
21cb0ef41Sopenharmony_ci// source code is governed by a BSD-style license that can be found in the
31cb0ef41Sopenharmony_ci// LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include 'src/ic/binary-op-assembler.h'
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ciextern enum Operation extends uint31 {
81cb0ef41Sopenharmony_ci  // Binary operations.
91cb0ef41Sopenharmony_ci  kAdd,
101cb0ef41Sopenharmony_ci  kSubtract,
111cb0ef41Sopenharmony_ci  kMultiply,
121cb0ef41Sopenharmony_ci  kDivide,
131cb0ef41Sopenharmony_ci  kModulus,
141cb0ef41Sopenharmony_ci  kExponentiate,
151cb0ef41Sopenharmony_ci  kBitwiseAnd,
161cb0ef41Sopenharmony_ci  kBitwiseOr,
171cb0ef41Sopenharmony_ci  kBitwiseXor,
181cb0ef41Sopenharmony_ci  kShiftLeft,
191cb0ef41Sopenharmony_ci  kShiftRight,
201cb0ef41Sopenharmony_ci  kShiftRightLogical,
211cb0ef41Sopenharmony_ci  // Unary operations.
221cb0ef41Sopenharmony_ci  kBitwiseNot,
231cb0ef41Sopenharmony_ci  kNegate,
241cb0ef41Sopenharmony_ci  kIncrement,
251cb0ef41Sopenharmony_ci  kDecrement,
261cb0ef41Sopenharmony_ci  // Compare operations.
271cb0ef41Sopenharmony_ci  kEqual,
281cb0ef41Sopenharmony_ci  kStrictEqual,
291cb0ef41Sopenharmony_ci  kLessThan,
301cb0ef41Sopenharmony_ci  kLessThanOrEqual,
311cb0ef41Sopenharmony_ci  kGreaterThan,
321cb0ef41Sopenharmony_ci  kGreaterThanOrEqual
331cb0ef41Sopenharmony_ci}
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_cinamespace runtime {
361cb0ef41Sopenharmony_ciextern transitioning runtime
371cb0ef41Sopenharmony_ciDoubleToStringWithRadix(implicit context: Context)(Number, Number): String;
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ciextern transitioning runtime StringParseFloat(implicit context: Context)(
401cb0ef41Sopenharmony_ci    String): Number;
411cb0ef41Sopenharmony_ciextern transitioning runtime StringParseInt(implicit context: Context)(
421cb0ef41Sopenharmony_ci    JSAny, JSAny): Number;
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ciextern runtime BigIntUnaryOp(Context, BigInt, SmiTagged<Operation>): BigInt;
451cb0ef41Sopenharmony_ciextern runtime BigIntBinaryOp(
461cb0ef41Sopenharmony_ci    Context, Numeric, Numeric, SmiTagged<Operation>): BigInt;
471cb0ef41Sopenharmony_ci}  // namespace runtime
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_cinamespace number {
501cb0ef41Sopenharmony_ciextern macro NaNStringConstant(): String;
511cb0ef41Sopenharmony_ciextern macro ZeroStringConstant(): String;
521cb0ef41Sopenharmony_ciextern macro InfinityStringConstant(): String;
531cb0ef41Sopenharmony_ciextern macro MinusInfinityStringConstant(): String;
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ciconst kAsciiZero: constexpr int32 = 48;        // '0' (ascii)
561cb0ef41Sopenharmony_ciconst kAsciiLowerCaseA: constexpr int32 = 97;  // 'a' (ascii)
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_citransitioning macro ThisNumberValue(implicit context: Context)(
591cb0ef41Sopenharmony_ci    receiver: JSAny, method: constexpr string): Number {
601cb0ef41Sopenharmony_ci  return UnsafeCast<Number>(
611cb0ef41Sopenharmony_ci      ToThisValue(receiver, PrimitiveType::kNumber, method));
621cb0ef41Sopenharmony_ci}
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_cimacro ToCharCode(input: int32): char8 {
651cb0ef41Sopenharmony_ci  dcheck(0 <= input && input < 36);
661cb0ef41Sopenharmony_ci  return input < 10 ?
671cb0ef41Sopenharmony_ci      %RawDownCast<char8>(Unsigned(input + kAsciiZero)) :
681cb0ef41Sopenharmony_ci      %RawDownCast<char8>(Unsigned(input - 10 + kAsciiLowerCaseA));
691cb0ef41Sopenharmony_ci}
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci@export
721cb0ef41Sopenharmony_cimacro NumberToStringSmi(x: int32, radix: int32): String labels Slow {
731cb0ef41Sopenharmony_ci  const isNegative: bool = x < 0;
741cb0ef41Sopenharmony_ci  let n: int32 = x;
751cb0ef41Sopenharmony_ci  if (!isNegative) {
761cb0ef41Sopenharmony_ci    // Fast case where the result is a one character string.
771cb0ef41Sopenharmony_ci    if (x < radix) {
781cb0ef41Sopenharmony_ci      if (x == 0) {
791cb0ef41Sopenharmony_ci        return ZeroStringConstant();
801cb0ef41Sopenharmony_ci      }
811cb0ef41Sopenharmony_ci      return StringFromSingleCharCode(ToCharCode(n));
821cb0ef41Sopenharmony_ci    }
831cb0ef41Sopenharmony_ci  } else {
841cb0ef41Sopenharmony_ci    dcheck(isNegative);
851cb0ef41Sopenharmony_ci    if (n == kMinInt32) {
861cb0ef41Sopenharmony_ci      goto Slow;
871cb0ef41Sopenharmony_ci    }
881cb0ef41Sopenharmony_ci    n = 0 - n;
891cb0ef41Sopenharmony_ci  }
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_ci  // Calculate length and pre-allocate the result string.
921cb0ef41Sopenharmony_ci  let temp: int32 = n;
931cb0ef41Sopenharmony_ci  let length: int32 = isNegative ? Convert<int32>(1) : Convert<int32>(0);
941cb0ef41Sopenharmony_ci  while (temp > 0) {
951cb0ef41Sopenharmony_ci    temp = temp / radix;
961cb0ef41Sopenharmony_ci    length = length + 1;
971cb0ef41Sopenharmony_ci  }
981cb0ef41Sopenharmony_ci  dcheck(length > 0);
991cb0ef41Sopenharmony_ci  const strSeq = AllocateNonEmptySeqOneByteString(Unsigned(length));
1001cb0ef41Sopenharmony_ci  let cursor: intptr = Convert<intptr>(length) - 1;
1011cb0ef41Sopenharmony_ci  while (n > 0) {
1021cb0ef41Sopenharmony_ci    const digit: int32 = n % radix;
1031cb0ef41Sopenharmony_ci    n = n / radix;
1041cb0ef41Sopenharmony_ci    *UnsafeConstCast(&strSeq.chars[cursor]) = ToCharCode(digit);
1051cb0ef41Sopenharmony_ci    cursor = cursor - 1;
1061cb0ef41Sopenharmony_ci  }
1071cb0ef41Sopenharmony_ci  if (isNegative) {
1081cb0ef41Sopenharmony_ci    dcheck(cursor == 0);
1091cb0ef41Sopenharmony_ci    // Insert '-' to result.
1101cb0ef41Sopenharmony_ci    *UnsafeConstCast(&strSeq.chars[0]) = 45;
1111cb0ef41Sopenharmony_ci  } else {
1121cb0ef41Sopenharmony_ci    dcheck(cursor == -1);
1131cb0ef41Sopenharmony_ci    // In sync with Factory::SmiToString: If radix = 10 and positive number,
1141cb0ef41Sopenharmony_ci    // update hash for string.
1151cb0ef41Sopenharmony_ci    if (radix == 10) {
1161cb0ef41Sopenharmony_ci      dcheck(strSeq.raw_hash_field == kNameEmptyHashField);
1171cb0ef41Sopenharmony_ci      strSeq.raw_hash_field = MakeArrayIndexHash(Unsigned(x), Unsigned(length));
1181cb0ef41Sopenharmony_ci    }
1191cb0ef41Sopenharmony_ci  }
1201cb0ef41Sopenharmony_ci  return strSeq;
1211cb0ef41Sopenharmony_ci}
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci// https://tc39.github.io/ecma262/#sec-number.prototype.tostring
1241cb0ef41Sopenharmony_citransitioning javascript builtin NumberPrototypeToString(
1251cb0ef41Sopenharmony_ci    js-implicit context: NativeContext, receiver: JSAny)(...arguments): String {
1261cb0ef41Sopenharmony_ci  // 1. Let x be ? thisNumberValue(this value).
1271cb0ef41Sopenharmony_ci  const x = ThisNumberValue(receiver, 'Number.prototype.toString');
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci  // 2. If radix is not present, let radixNumber be 10.
1301cb0ef41Sopenharmony_ci  // 3. Else if radix is undefined, let radixNumber be 10.
1311cb0ef41Sopenharmony_ci  // 4. Else, let radixNumber be ? ToInteger(radix).
1321cb0ef41Sopenharmony_ci  const radix: JSAny = arguments[0];
1331cb0ef41Sopenharmony_ci  const radixNumber: Number = radix == Undefined ? 10 : ToInteger_Inline(radix);
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci  // 5. If radixNumber < 2 or radixNumber > 36, throw a RangeError exception.
1361cb0ef41Sopenharmony_ci  if (radixNumber < 2 || radixNumber > 36) {
1371cb0ef41Sopenharmony_ci    ThrowRangeError(MessageTemplate::kToRadixFormatRange);
1381cb0ef41Sopenharmony_ci  }
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_ci  // 6. If radixNumber = 10, return ! ToString(x).
1411cb0ef41Sopenharmony_ci  if (radixNumber == 10) {
1421cb0ef41Sopenharmony_ci    return NumberToString(x);
1431cb0ef41Sopenharmony_ci  }
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_ci  // 7. Return the String representation of this Number
1461cb0ef41Sopenharmony_ci  //    value using the radix specified by radixNumber.
1471cb0ef41Sopenharmony_ci
1481cb0ef41Sopenharmony_ci  if (TaggedIsSmi(x)) {
1491cb0ef41Sopenharmony_ci    return NumberToStringSmi(Convert<int32>(x), Convert<int32>(radixNumber))
1501cb0ef41Sopenharmony_ci        otherwise return runtime::DoubleToStringWithRadix(x, radixNumber);
1511cb0ef41Sopenharmony_ci  }
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci  if (x == -0) {
1541cb0ef41Sopenharmony_ci    return ZeroStringConstant();
1551cb0ef41Sopenharmony_ci  } else if (::NumberIsNaN(x)) {
1561cb0ef41Sopenharmony_ci    return NaNStringConstant();
1571cb0ef41Sopenharmony_ci  } else if (x == V8_INFINITY) {
1581cb0ef41Sopenharmony_ci    return InfinityStringConstant();
1591cb0ef41Sopenharmony_ci  } else if (x == MINUS_V8_INFINITY) {
1601cb0ef41Sopenharmony_ci    return MinusInfinityStringConstant();
1611cb0ef41Sopenharmony_ci  }
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_ci  return runtime::DoubleToStringWithRadix(x, radixNumber);
1641cb0ef41Sopenharmony_ci}
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci// ES6 #sec-number.isfinite
1671cb0ef41Sopenharmony_cijavascript builtin NumberIsFinite(
1681cb0ef41Sopenharmony_ci    js-implicit context: NativeContext,
1691cb0ef41Sopenharmony_ci    receiver: JSAny)(value: JSAny): Boolean {
1701cb0ef41Sopenharmony_ci  typeswitch (value) {
1711cb0ef41Sopenharmony_ci    case (Smi): {
1721cb0ef41Sopenharmony_ci      return True;
1731cb0ef41Sopenharmony_ci    }
1741cb0ef41Sopenharmony_ci    case (h: HeapNumber): {
1751cb0ef41Sopenharmony_ci      const number: float64 = Convert<float64>(h);
1761cb0ef41Sopenharmony_ci      const infiniteOrNaN: bool = Float64IsNaN(number - number);
1771cb0ef41Sopenharmony_ci      return Convert<Boolean>(!infiniteOrNaN);
1781cb0ef41Sopenharmony_ci    }
1791cb0ef41Sopenharmony_ci    case (JSAnyNotNumber): {
1801cb0ef41Sopenharmony_ci      return False;
1811cb0ef41Sopenharmony_ci    }
1821cb0ef41Sopenharmony_ci  }
1831cb0ef41Sopenharmony_ci}
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_ci// ES6 #sec-number.isinteger
1861cb0ef41Sopenharmony_cijavascript builtin NumberIsInteger(js-implicit context: NativeContext)(
1871cb0ef41Sopenharmony_ci    value: JSAny): Boolean {
1881cb0ef41Sopenharmony_ci  return SelectBooleanConstant(IsInteger(value));
1891cb0ef41Sopenharmony_ci}
1901cb0ef41Sopenharmony_ci
1911cb0ef41Sopenharmony_ci// ES6 #sec-number.isnan
1921cb0ef41Sopenharmony_cijavascript builtin NumberIsNaN(js-implicit context: NativeContext)(
1931cb0ef41Sopenharmony_ci    value: JSAny): Boolean {
1941cb0ef41Sopenharmony_ci  typeswitch (value) {
1951cb0ef41Sopenharmony_ci    case (Smi): {
1961cb0ef41Sopenharmony_ci      return False;
1971cb0ef41Sopenharmony_ci    }
1981cb0ef41Sopenharmony_ci    case (h: HeapNumber): {
1991cb0ef41Sopenharmony_ci      const number: float64 = Convert<float64>(h);
2001cb0ef41Sopenharmony_ci      return Convert<Boolean>(Float64IsNaN(number));
2011cb0ef41Sopenharmony_ci    }
2021cb0ef41Sopenharmony_ci    case (JSAnyNotNumber): {
2031cb0ef41Sopenharmony_ci      return False;
2041cb0ef41Sopenharmony_ci    }
2051cb0ef41Sopenharmony_ci  }
2061cb0ef41Sopenharmony_ci}
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_ci// ES6 #sec-number.issafeinteger
2091cb0ef41Sopenharmony_cijavascript builtin NumberIsSafeInteger(js-implicit context: NativeContext)(
2101cb0ef41Sopenharmony_ci    value: JSAny): Boolean {
2111cb0ef41Sopenharmony_ci  return SelectBooleanConstant(IsSafeInteger(value));
2121cb0ef41Sopenharmony_ci}
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ci// ES6 #sec-number.prototype.valueof
2151cb0ef41Sopenharmony_citransitioning javascript builtin NumberPrototypeValueOf(
2161cb0ef41Sopenharmony_ci    js-implicit context: NativeContext, receiver: JSAny)(): JSAny {
2171cb0ef41Sopenharmony_ci  return ToThisValue(
2181cb0ef41Sopenharmony_ci      receiver, PrimitiveType::kNumber, 'Number.prototype.valueOf');
2191cb0ef41Sopenharmony_ci}
2201cb0ef41Sopenharmony_ci
2211cb0ef41Sopenharmony_ci// ES6 #sec-number.parsefloat
2221cb0ef41Sopenharmony_citransitioning javascript builtin NumberParseFloat(
2231cb0ef41Sopenharmony_ci    js-implicit context: NativeContext)(value: JSAny): Number {
2241cb0ef41Sopenharmony_ci  try {
2251cb0ef41Sopenharmony_ci    typeswitch (value) {
2261cb0ef41Sopenharmony_ci      case (s: Smi): {
2271cb0ef41Sopenharmony_ci        return s;
2281cb0ef41Sopenharmony_ci      }
2291cb0ef41Sopenharmony_ci      case (h: HeapNumber): {
2301cb0ef41Sopenharmony_ci        // The input is already a Number. Take care of -0.
2311cb0ef41Sopenharmony_ci        // The sense of comparison is important for the NaN case.
2321cb0ef41Sopenharmony_ci        return (Convert<float64>(h) == 0) ? SmiConstant(0) : h;
2331cb0ef41Sopenharmony_ci      }
2341cb0ef41Sopenharmony_ci      case (s: String): {
2351cb0ef41Sopenharmony_ci        goto String(s);
2361cb0ef41Sopenharmony_ci      }
2371cb0ef41Sopenharmony_ci      case (HeapObject): {
2381cb0ef41Sopenharmony_ci        goto String(string::ToString(context, value));
2391cb0ef41Sopenharmony_ci      }
2401cb0ef41Sopenharmony_ci    }
2411cb0ef41Sopenharmony_ci  } label String(s: String) {
2421cb0ef41Sopenharmony_ci    // Check if the string is a cached array index.
2431cb0ef41Sopenharmony_ci    const hash: NameHash = s.raw_hash_field;
2441cb0ef41Sopenharmony_ci    if (IsIntegerIndex(hash) &&
2451cb0ef41Sopenharmony_ci        hash.array_index_length < kMaxCachedArrayIndexLength) {
2461cb0ef41Sopenharmony_ci      const arrayIndex: uint32 = hash.array_index_value;
2471cb0ef41Sopenharmony_ci      return SmiFromUint32(arrayIndex);
2481cb0ef41Sopenharmony_ci    }
2491cb0ef41Sopenharmony_ci    // Fall back to the runtime to convert string to a number.
2501cb0ef41Sopenharmony_ci    return runtime::StringParseFloat(s);
2511cb0ef41Sopenharmony_ci  }
2521cb0ef41Sopenharmony_ci}
2531cb0ef41Sopenharmony_ci
2541cb0ef41Sopenharmony_ciextern macro TruncateFloat64ToWord32(float64): uint32;
2551cb0ef41Sopenharmony_ci
2561cb0ef41Sopenharmony_citransitioning builtin ParseInt(implicit context: Context)(
2571cb0ef41Sopenharmony_ci    input: JSAny, radix: JSAny): Number {
2581cb0ef41Sopenharmony_ci  try {
2591cb0ef41Sopenharmony_ci    // Check if radix should be 10 (i.e. undefined, 0 or 10).
2601cb0ef41Sopenharmony_ci    if (radix != Undefined && !TaggedEqual(radix, SmiConstant(10)) &&
2611cb0ef41Sopenharmony_ci        !TaggedEqual(radix, SmiConstant(0))) {
2621cb0ef41Sopenharmony_ci      goto CallRuntime;
2631cb0ef41Sopenharmony_ci    }
2641cb0ef41Sopenharmony_ci
2651cb0ef41Sopenharmony_ci    typeswitch (input) {
2661cb0ef41Sopenharmony_ci      case (s: Smi): {
2671cb0ef41Sopenharmony_ci        return s;
2681cb0ef41Sopenharmony_ci      }
2691cb0ef41Sopenharmony_ci      case (h: HeapNumber): {
2701cb0ef41Sopenharmony_ci        // Check if the input value is in Signed32 range.
2711cb0ef41Sopenharmony_ci        const asFloat64: float64 = Convert<float64>(h);
2721cb0ef41Sopenharmony_ci        const asInt32: int32 = Signed(TruncateFloat64ToWord32(asFloat64));
2731cb0ef41Sopenharmony_ci        // The sense of comparison is important for the NaN case.
2741cb0ef41Sopenharmony_ci        if (asFloat64 == ChangeInt32ToFloat64(asInt32)) goto Int32(asInt32);
2751cb0ef41Sopenharmony_ci
2761cb0ef41Sopenharmony_ci        // Check if the absolute value of input is in the [1,1<<31[ range. Call
2771cb0ef41Sopenharmony_ci        // the runtime for the range [0,1[ because the result could be -0.
2781cb0ef41Sopenharmony_ci        const kMaxAbsValue: float64 = 2147483648.0;
2791cb0ef41Sopenharmony_ci        const absInput: float64 = math::Float64Abs(asFloat64);
2801cb0ef41Sopenharmony_ci        if (absInput < kMaxAbsValue && absInput >= 1.0) goto Int32(asInt32);
2811cb0ef41Sopenharmony_ci        goto CallRuntime;
2821cb0ef41Sopenharmony_ci      }
2831cb0ef41Sopenharmony_ci      case (s: String): {
2841cb0ef41Sopenharmony_ci        goto String(s);
2851cb0ef41Sopenharmony_ci      }
2861cb0ef41Sopenharmony_ci      case (HeapObject): {
2871cb0ef41Sopenharmony_ci        goto CallRuntime;
2881cb0ef41Sopenharmony_ci      }
2891cb0ef41Sopenharmony_ci    }
2901cb0ef41Sopenharmony_ci  } label Int32(i: int32) {
2911cb0ef41Sopenharmony_ci    return ChangeInt32ToTagged(i);
2921cb0ef41Sopenharmony_ci  } label String(s: String) {
2931cb0ef41Sopenharmony_ci    // Check if the string is a cached array index.
2941cb0ef41Sopenharmony_ci    const hash: NameHash = s.raw_hash_field;
2951cb0ef41Sopenharmony_ci    if (IsIntegerIndex(hash) &&
2961cb0ef41Sopenharmony_ci        hash.array_index_length < kMaxCachedArrayIndexLength) {
2971cb0ef41Sopenharmony_ci      const arrayIndex: uint32 = hash.array_index_value;
2981cb0ef41Sopenharmony_ci      return SmiFromUint32(arrayIndex);
2991cb0ef41Sopenharmony_ci    }
3001cb0ef41Sopenharmony_ci    // Fall back to the runtime.
3011cb0ef41Sopenharmony_ci    goto CallRuntime;
3021cb0ef41Sopenharmony_ci  } label CallRuntime {
3031cb0ef41Sopenharmony_ci    tail runtime::StringParseInt(input, radix);
3041cb0ef41Sopenharmony_ci  }
3051cb0ef41Sopenharmony_ci}
3061cb0ef41Sopenharmony_ci
3071cb0ef41Sopenharmony_ci// ES6 #sec-number.parseint
3081cb0ef41Sopenharmony_citransitioning javascript builtin NumberParseInt(
3091cb0ef41Sopenharmony_ci    js-implicit context: NativeContext)(value: JSAny, radix: JSAny): Number {
3101cb0ef41Sopenharmony_ci  return ParseInt(value, radix);
3111cb0ef41Sopenharmony_ci}
3121cb0ef41Sopenharmony_ci
3131cb0ef41Sopenharmony_ciextern builtin NonNumberToNumeric(implicit context: Context)(JSAny): Numeric;
3141cb0ef41Sopenharmony_ciextern builtin BitwiseXor(implicit context: Context)(Number, Number): Number;
3151cb0ef41Sopenharmony_ciextern builtin Subtract(implicit context: Context)(Number, Number): Number;
3161cb0ef41Sopenharmony_ciextern builtin Add(implicit context: Context)(Number, Number): Number;
3171cb0ef41Sopenharmony_ciextern builtin StringAddConvertLeft(implicit context: Context)(
3181cb0ef41Sopenharmony_ci    JSAny, String): JSAny;
3191cb0ef41Sopenharmony_ciextern builtin StringAddConvertRight(implicit context: Context)(
3201cb0ef41Sopenharmony_ci    String, JSAny): JSAny;
3211cb0ef41Sopenharmony_ci
3221cb0ef41Sopenharmony_ciextern macro BitwiseOp(int32, int32, constexpr Operation): Number;
3231cb0ef41Sopenharmony_ciextern macro RelationalComparison(
3241cb0ef41Sopenharmony_ci    constexpr Operation, JSAny, JSAny, Context): Boolean;
3251cb0ef41Sopenharmony_ci
3261cb0ef41Sopenharmony_ci// TODO(bbudge) Use a simpler macro structure that doesn't loop when converting
3271cb0ef41Sopenharmony_ci// non-numbers, if such a code sequence doesn't make the builtin bigger.
3281cb0ef41Sopenharmony_ci
3291cb0ef41Sopenharmony_citransitioning macro ToNumericOrPrimitive(implicit context: Context)(
3301cb0ef41Sopenharmony_ci    value: JSAny): JSAny {
3311cb0ef41Sopenharmony_ci  typeswitch (value) {
3321cb0ef41Sopenharmony_ci    case (v: JSReceiver): {
3331cb0ef41Sopenharmony_ci      return NonPrimitiveToPrimitive_Default(context, v);
3341cb0ef41Sopenharmony_ci    }
3351cb0ef41Sopenharmony_ci    case (v: JSPrimitive): {
3361cb0ef41Sopenharmony_ci      return NonNumberToNumeric(v);
3371cb0ef41Sopenharmony_ci    }
3381cb0ef41Sopenharmony_ci  }
3391cb0ef41Sopenharmony_ci}
3401cb0ef41Sopenharmony_ci
3411cb0ef41Sopenharmony_citransitioning builtin Add(implicit context: Context)(
3421cb0ef41Sopenharmony_ci    leftArg: JSAny, rightArg: JSAny): JSAny {
3431cb0ef41Sopenharmony_ci  let left: JSAny = leftArg;
3441cb0ef41Sopenharmony_ci  let right: JSAny = rightArg;
3451cb0ef41Sopenharmony_ci  try {
3461cb0ef41Sopenharmony_ci    while (true) {
3471cb0ef41Sopenharmony_ci      typeswitch (left) {
3481cb0ef41Sopenharmony_ci        case (left: Smi): {
3491cb0ef41Sopenharmony_ci          typeswitch (right) {
3501cb0ef41Sopenharmony_ci            case (right: Smi): {
3511cb0ef41Sopenharmony_ci              return math::TrySmiAdd(left, right) otherwise goto Float64s(
3521cb0ef41Sopenharmony_ci                  SmiToFloat64(left), SmiToFloat64(right));
3531cb0ef41Sopenharmony_ci            }
3541cb0ef41Sopenharmony_ci            case (right: HeapNumber): {
3551cb0ef41Sopenharmony_ci              goto Float64s(SmiToFloat64(left), Convert<float64>(right));
3561cb0ef41Sopenharmony_ci            }
3571cb0ef41Sopenharmony_ci            case (right: BigInt): {
3581cb0ef41Sopenharmony_ci              goto Numerics(left, right);
3591cb0ef41Sopenharmony_ci            }
3601cb0ef41Sopenharmony_ci            case (right: String): {
3611cb0ef41Sopenharmony_ci              goto StringAddConvertLeft(left, right);
3621cb0ef41Sopenharmony_ci            }
3631cb0ef41Sopenharmony_ci            case (HeapObject): {
3641cb0ef41Sopenharmony_ci              right = ToNumericOrPrimitive(right);
3651cb0ef41Sopenharmony_ci              continue;
3661cb0ef41Sopenharmony_ci            }
3671cb0ef41Sopenharmony_ci          }
3681cb0ef41Sopenharmony_ci        }
3691cb0ef41Sopenharmony_ci        case (left: HeapNumber): {
3701cb0ef41Sopenharmony_ci          typeswitch (right) {
3711cb0ef41Sopenharmony_ci            case (right: Smi): {
3721cb0ef41Sopenharmony_ci              goto Float64s(Convert<float64>(left), SmiToFloat64(right));
3731cb0ef41Sopenharmony_ci            }
3741cb0ef41Sopenharmony_ci            case (right: HeapNumber): {
3751cb0ef41Sopenharmony_ci              goto Float64s(Convert<float64>(left), Convert<float64>(right));
3761cb0ef41Sopenharmony_ci            }
3771cb0ef41Sopenharmony_ci            case (right: BigInt): {
3781cb0ef41Sopenharmony_ci              goto Numerics(left, right);
3791cb0ef41Sopenharmony_ci            }
3801cb0ef41Sopenharmony_ci            case (right: String): {
3811cb0ef41Sopenharmony_ci              goto StringAddConvertLeft(left, right);
3821cb0ef41Sopenharmony_ci            }
3831cb0ef41Sopenharmony_ci            case (HeapObject): {
3841cb0ef41Sopenharmony_ci              right = ToNumericOrPrimitive(right);
3851cb0ef41Sopenharmony_ci              continue;
3861cb0ef41Sopenharmony_ci            }
3871cb0ef41Sopenharmony_ci          }
3881cb0ef41Sopenharmony_ci        }
3891cb0ef41Sopenharmony_ci        case (left: BigInt): {
3901cb0ef41Sopenharmony_ci          typeswitch (right) {
3911cb0ef41Sopenharmony_ci            case (right: Numeric): {
3921cb0ef41Sopenharmony_ci              goto Numerics(left, right);
3931cb0ef41Sopenharmony_ci            }
3941cb0ef41Sopenharmony_ci            case (right: String): {
3951cb0ef41Sopenharmony_ci              goto StringAddConvertLeft(left, right);
3961cb0ef41Sopenharmony_ci            }
3971cb0ef41Sopenharmony_ci            case (HeapObject): {
3981cb0ef41Sopenharmony_ci              right = ToNumericOrPrimitive(right);
3991cb0ef41Sopenharmony_ci              continue;
4001cb0ef41Sopenharmony_ci            }
4011cb0ef41Sopenharmony_ci          }
4021cb0ef41Sopenharmony_ci        }
4031cb0ef41Sopenharmony_ci        case (left: String): {
4041cb0ef41Sopenharmony_ci          goto StringAddConvertRight(left, right);
4051cb0ef41Sopenharmony_ci        }
4061cb0ef41Sopenharmony_ci        case (leftReceiver: JSReceiver): {
4071cb0ef41Sopenharmony_ci          left = ToPrimitiveDefault(leftReceiver);
4081cb0ef41Sopenharmony_ci        }
4091cb0ef41Sopenharmony_ci        case (HeapObject): {
4101cb0ef41Sopenharmony_ci          // left: HeapObject
4111cb0ef41Sopenharmony_ci          typeswitch (right) {
4121cb0ef41Sopenharmony_ci            case (right: String): {
4131cb0ef41Sopenharmony_ci              goto StringAddConvertLeft(left, right);
4141cb0ef41Sopenharmony_ci            }
4151cb0ef41Sopenharmony_ci            case (rightReceiver: JSReceiver): {
4161cb0ef41Sopenharmony_ci              // left is JSPrimitive and right is JSReceiver, convert right
4171cb0ef41Sopenharmony_ci              // with priority.
4181cb0ef41Sopenharmony_ci              right = ToPrimitiveDefault(rightReceiver);
4191cb0ef41Sopenharmony_ci              continue;
4201cb0ef41Sopenharmony_ci            }
4211cb0ef41Sopenharmony_ci            case (JSPrimitive): {
4221cb0ef41Sopenharmony_ci              // Neither left or right is JSReceiver, convert left.
4231cb0ef41Sopenharmony_ci              left = NonNumberToNumeric(left);
4241cb0ef41Sopenharmony_ci              continue;
4251cb0ef41Sopenharmony_ci            }
4261cb0ef41Sopenharmony_ci          }
4271cb0ef41Sopenharmony_ci        }
4281cb0ef41Sopenharmony_ci      }
4291cb0ef41Sopenharmony_ci    }
4301cb0ef41Sopenharmony_ci  } label StringAddConvertLeft(left: JSAny, right: String) {
4311cb0ef41Sopenharmony_ci    tail StringAddConvertLeft(left, right);
4321cb0ef41Sopenharmony_ci  } label StringAddConvertRight(left: String, right: JSAny) {
4331cb0ef41Sopenharmony_ci    tail StringAddConvertRight(left, right);
4341cb0ef41Sopenharmony_ci  } label Numerics(left: Numeric, right: Numeric) {
4351cb0ef41Sopenharmony_ci    tail bigint::BigIntAdd(left, right);
4361cb0ef41Sopenharmony_ci  } label Float64s(left: float64, right: float64) {
4371cb0ef41Sopenharmony_ci    return AllocateHeapNumberWithValue(left + right);
4381cb0ef41Sopenharmony_ci  }
4391cb0ef41Sopenharmony_ci  unreachable;
4401cb0ef41Sopenharmony_ci}
4411cb0ef41Sopenharmony_ci
4421cb0ef41Sopenharmony_ci// Unary type switch on Number | BigInt.
4431cb0ef41Sopenharmony_cimacro UnaryOp1(implicit context: Context)(value: JSAny): never labels
4441cb0ef41Sopenharmony_ciNumber(Number), BigInt(BigInt) {
4451cb0ef41Sopenharmony_ci  let x: JSAny = value;
4461cb0ef41Sopenharmony_ci  while (true) {
4471cb0ef41Sopenharmony_ci    typeswitch (x) {
4481cb0ef41Sopenharmony_ci      case (n: Number): {
4491cb0ef41Sopenharmony_ci        goto Number(n);
4501cb0ef41Sopenharmony_ci      }
4511cb0ef41Sopenharmony_ci      case (b: BigInt): {
4521cb0ef41Sopenharmony_ci        goto BigInt(b);
4531cb0ef41Sopenharmony_ci      }
4541cb0ef41Sopenharmony_ci      case (JSAnyNotNumeric): {
4551cb0ef41Sopenharmony_ci        x = NonNumberToNumeric(x);
4561cb0ef41Sopenharmony_ci      }
4571cb0ef41Sopenharmony_ci    }
4581cb0ef41Sopenharmony_ci  }
4591cb0ef41Sopenharmony_ci  unreachable;
4601cb0ef41Sopenharmony_ci}
4611cb0ef41Sopenharmony_ci
4621cb0ef41Sopenharmony_ci// Unary type switch on Smi | HeapNumber | BigInt.
4631cb0ef41Sopenharmony_cimacro UnaryOp2(implicit context: Context)(value: JSAny): never labels
4641cb0ef41Sopenharmony_ciSmi(Smi), HeapNumber(HeapNumber), BigInt(BigInt) {
4651cb0ef41Sopenharmony_ci  let x: JSAny = value;
4661cb0ef41Sopenharmony_ci  while (true) {
4671cb0ef41Sopenharmony_ci    typeswitch (x) {
4681cb0ef41Sopenharmony_ci      case (s: Smi): {
4691cb0ef41Sopenharmony_ci        goto Smi(s);
4701cb0ef41Sopenharmony_ci      }
4711cb0ef41Sopenharmony_ci      case (h: HeapNumber): {
4721cb0ef41Sopenharmony_ci        goto HeapNumber(h);
4731cb0ef41Sopenharmony_ci      }
4741cb0ef41Sopenharmony_ci      case (b: BigInt): {
4751cb0ef41Sopenharmony_ci        goto BigInt(b);
4761cb0ef41Sopenharmony_ci      }
4771cb0ef41Sopenharmony_ci      case (JSAnyNotNumeric): {
4781cb0ef41Sopenharmony_ci        x = NonNumberToNumeric(x);
4791cb0ef41Sopenharmony_ci      }
4801cb0ef41Sopenharmony_ci    }
4811cb0ef41Sopenharmony_ci  }
4821cb0ef41Sopenharmony_ci  unreachable;
4831cb0ef41Sopenharmony_ci}
4841cb0ef41Sopenharmony_ci
4851cb0ef41Sopenharmony_ci// Binary type switch on Number | BigInt.
4861cb0ef41Sopenharmony_cimacro BinaryOp1(implicit context: Context)(
4871cb0ef41Sopenharmony_ci    leftVal: JSAny, rightVal: JSAny): never labels
4881cb0ef41Sopenharmony_ciNumber(Number, Number), AtLeastOneBigInt(Numeric, Numeric) {
4891cb0ef41Sopenharmony_ci  let left: JSAny = leftVal;
4901cb0ef41Sopenharmony_ci  let right: JSAny = rightVal;
4911cb0ef41Sopenharmony_ci  while (true) {
4921cb0ef41Sopenharmony_ci    try {
4931cb0ef41Sopenharmony_ci      typeswitch (left) {
4941cb0ef41Sopenharmony_ci        case (left: Number): {
4951cb0ef41Sopenharmony_ci          typeswitch (right) {
4961cb0ef41Sopenharmony_ci            case (right: Number): {
4971cb0ef41Sopenharmony_ci              goto Number(left, right);
4981cb0ef41Sopenharmony_ci            }
4991cb0ef41Sopenharmony_ci            case (right: BigInt): {
5001cb0ef41Sopenharmony_ci              goto AtLeastOneBigInt(left, right);
5011cb0ef41Sopenharmony_ci            }
5021cb0ef41Sopenharmony_ci            case (JSAnyNotNumeric): {
5031cb0ef41Sopenharmony_ci              goto RightNotNumeric;
5041cb0ef41Sopenharmony_ci            }
5051cb0ef41Sopenharmony_ci          }
5061cb0ef41Sopenharmony_ci        }
5071cb0ef41Sopenharmony_ci        case (left: BigInt): {
5081cb0ef41Sopenharmony_ci          typeswitch (right) {
5091cb0ef41Sopenharmony_ci            case (right: Numeric): {
5101cb0ef41Sopenharmony_ci              goto AtLeastOneBigInt(left, right);
5111cb0ef41Sopenharmony_ci            }
5121cb0ef41Sopenharmony_ci            case (JSAnyNotNumeric): {
5131cb0ef41Sopenharmony_ci              goto RightNotNumeric;
5141cb0ef41Sopenharmony_ci            }
5151cb0ef41Sopenharmony_ci          }
5161cb0ef41Sopenharmony_ci        }
5171cb0ef41Sopenharmony_ci        case (JSAnyNotNumeric): {
5181cb0ef41Sopenharmony_ci          left = NonNumberToNumeric(left);
5191cb0ef41Sopenharmony_ci        }
5201cb0ef41Sopenharmony_ci      }
5211cb0ef41Sopenharmony_ci    } label RightNotNumeric {
5221cb0ef41Sopenharmony_ci      right = NonNumberToNumeric(right);
5231cb0ef41Sopenharmony_ci    }
5241cb0ef41Sopenharmony_ci  }
5251cb0ef41Sopenharmony_ci  unreachable;
5261cb0ef41Sopenharmony_ci}
5271cb0ef41Sopenharmony_ci
5281cb0ef41Sopenharmony_ci// Binary type switch on Smi | HeapNumber | BigInt.
5291cb0ef41Sopenharmony_cimacro BinaryOp2(implicit context: Context)(leftVal: JSAny, rightVal: JSAny):
5301cb0ef41Sopenharmony_ci    never labels Smis(Smi, Smi), Float64s(float64, float64),
5311cb0ef41Sopenharmony_ci    AtLeastOneBigInt(Numeric, Numeric) {
5321cb0ef41Sopenharmony_ci  let left: JSAny = leftVal;
5331cb0ef41Sopenharmony_ci  let right: JSAny = rightVal;
5341cb0ef41Sopenharmony_ci  while (true) {
5351cb0ef41Sopenharmony_ci    try {
5361cb0ef41Sopenharmony_ci      typeswitch (left) {
5371cb0ef41Sopenharmony_ci        case (left: Smi): {
5381cb0ef41Sopenharmony_ci          typeswitch (right) {
5391cb0ef41Sopenharmony_ci            case (right: Smi): {
5401cb0ef41Sopenharmony_ci              goto Smis(left, right);
5411cb0ef41Sopenharmony_ci            }
5421cb0ef41Sopenharmony_ci            case (right: HeapNumber): {
5431cb0ef41Sopenharmony_ci              goto Float64s(SmiToFloat64(left), Convert<float64>(right));
5441cb0ef41Sopenharmony_ci            }
5451cb0ef41Sopenharmony_ci            case (right: BigInt): {
5461cb0ef41Sopenharmony_ci              goto AtLeastOneBigInt(left, right);
5471cb0ef41Sopenharmony_ci            }
5481cb0ef41Sopenharmony_ci            case (JSAnyNotNumeric): {
5491cb0ef41Sopenharmony_ci              goto RightNotNumeric;
5501cb0ef41Sopenharmony_ci            }
5511cb0ef41Sopenharmony_ci          }
5521cb0ef41Sopenharmony_ci        }
5531cb0ef41Sopenharmony_ci        case (left: HeapNumber): {
5541cb0ef41Sopenharmony_ci          typeswitch (right) {
5551cb0ef41Sopenharmony_ci            case (right: Smi): {
5561cb0ef41Sopenharmony_ci              goto Float64s(Convert<float64>(left), SmiToFloat64(right));
5571cb0ef41Sopenharmony_ci            }
5581cb0ef41Sopenharmony_ci            case (right: HeapNumber): {
5591cb0ef41Sopenharmony_ci              goto Float64s(Convert<float64>(left), Convert<float64>(right));
5601cb0ef41Sopenharmony_ci            }
5611cb0ef41Sopenharmony_ci            case (right: BigInt): {
5621cb0ef41Sopenharmony_ci              goto AtLeastOneBigInt(left, right);
5631cb0ef41Sopenharmony_ci            }
5641cb0ef41Sopenharmony_ci            case (JSAnyNotNumeric): {
5651cb0ef41Sopenharmony_ci              goto RightNotNumeric;
5661cb0ef41Sopenharmony_ci            }
5671cb0ef41Sopenharmony_ci          }
5681cb0ef41Sopenharmony_ci        }
5691cb0ef41Sopenharmony_ci        case (left: BigInt): {
5701cb0ef41Sopenharmony_ci          typeswitch (right) {
5711cb0ef41Sopenharmony_ci            case (right: Numeric): {
5721cb0ef41Sopenharmony_ci              goto AtLeastOneBigInt(left, right);
5731cb0ef41Sopenharmony_ci            }
5741cb0ef41Sopenharmony_ci            case (JSAnyNotNumeric): {
5751cb0ef41Sopenharmony_ci              goto RightNotNumeric;
5761cb0ef41Sopenharmony_ci            }
5771cb0ef41Sopenharmony_ci          }
5781cb0ef41Sopenharmony_ci        }
5791cb0ef41Sopenharmony_ci        case (JSAnyNotNumeric): {
5801cb0ef41Sopenharmony_ci          left = NonNumberToNumeric(left);
5811cb0ef41Sopenharmony_ci        }
5821cb0ef41Sopenharmony_ci      }
5831cb0ef41Sopenharmony_ci    } label RightNotNumeric {
5841cb0ef41Sopenharmony_ci      right = NonNumberToNumeric(right);
5851cb0ef41Sopenharmony_ci    }
5861cb0ef41Sopenharmony_ci  }
5871cb0ef41Sopenharmony_ci  unreachable;
5881cb0ef41Sopenharmony_ci}
5891cb0ef41Sopenharmony_ci
5901cb0ef41Sopenharmony_cibuiltin Subtract(implicit context: Context)(
5911cb0ef41Sopenharmony_ci    left: JSAny, right: JSAny): Numeric {
5921cb0ef41Sopenharmony_ci  try {
5931cb0ef41Sopenharmony_ci    BinaryOp2(left, right) otherwise Smis, Float64s, AtLeastOneBigInt;
5941cb0ef41Sopenharmony_ci  } label Smis(left: Smi, right: Smi) {
5951cb0ef41Sopenharmony_ci    try {
5961cb0ef41Sopenharmony_ci      return math::TrySmiSub(left, right) otherwise Overflow;
5971cb0ef41Sopenharmony_ci    } label Overflow {
5981cb0ef41Sopenharmony_ci      goto Float64s(SmiToFloat64(left), SmiToFloat64(right));
5991cb0ef41Sopenharmony_ci    }
6001cb0ef41Sopenharmony_ci  } label Float64s(left: float64, right: float64) {
6011cb0ef41Sopenharmony_ci    return AllocateHeapNumberWithValue(left - right);
6021cb0ef41Sopenharmony_ci  } label AtLeastOneBigInt(left: Numeric, right: Numeric) {
6031cb0ef41Sopenharmony_ci    tail bigint::BigIntSubtract(left, right);
6041cb0ef41Sopenharmony_ci  }
6051cb0ef41Sopenharmony_ci}
6061cb0ef41Sopenharmony_ci
6071cb0ef41Sopenharmony_cibuiltin Multiply(implicit context: Context)(
6081cb0ef41Sopenharmony_ci    left: JSAny, right: JSAny): Numeric {
6091cb0ef41Sopenharmony_ci  try {
6101cb0ef41Sopenharmony_ci    BinaryOp2(left, right) otherwise Smis, Float64s, AtLeastOneBigInt;
6111cb0ef41Sopenharmony_ci  } label Smis(left: Smi, right: Smi) {
6121cb0ef41Sopenharmony_ci    // The result is not necessarily a smi, in case of overflow.
6131cb0ef41Sopenharmony_ci    return SmiMul(left, right);
6141cb0ef41Sopenharmony_ci  } label Float64s(left: float64, right: float64) {
6151cb0ef41Sopenharmony_ci    return AllocateHeapNumberWithValue(left * right);
6161cb0ef41Sopenharmony_ci  } label AtLeastOneBigInt(left: Numeric, right: Numeric) {
6171cb0ef41Sopenharmony_ci    tail runtime::BigIntBinaryOp(
6181cb0ef41Sopenharmony_ci        context, left, right, SmiTag<Operation>(Operation::kMultiply));
6191cb0ef41Sopenharmony_ci  }
6201cb0ef41Sopenharmony_ci}
6211cb0ef41Sopenharmony_ci
6221cb0ef41Sopenharmony_ciconst kSmiValueSize: constexpr int32 generates 'kSmiValueSize';
6231cb0ef41Sopenharmony_ciconst kMinInt32: constexpr int32 generates 'kMinInt';
6241cb0ef41Sopenharmony_ciconst kMinInt31: constexpr int32 generates 'kMinInt31';
6251cb0ef41Sopenharmony_ciconst kMinimumDividend: int32 = (kSmiValueSize == 32) ? kMinInt32 : kMinInt31;
6261cb0ef41Sopenharmony_ci
6271cb0ef41Sopenharmony_cibuiltin Divide(implicit context: Context)(left: JSAny, right: JSAny): Numeric {
6281cb0ef41Sopenharmony_ci  try {
6291cb0ef41Sopenharmony_ci    BinaryOp2(left, right) otherwise Smis, Float64s, AtLeastOneBigInt;
6301cb0ef41Sopenharmony_ci  } label Smis(left: Smi, right: Smi) {
6311cb0ef41Sopenharmony_ci    // TODO(jkummerow): Consider just always doing a double division.
6321cb0ef41Sopenharmony_ci    // Bail out if {divisor} is zero.
6331cb0ef41Sopenharmony_ci    if (right == 0) goto SmiBailout(left, right);
6341cb0ef41Sopenharmony_ci
6351cb0ef41Sopenharmony_ci    // Bail out if dividend is zero and divisor is negative.
6361cb0ef41Sopenharmony_ci    if (left == 0 && right < 0) goto SmiBailout(left, right);
6371cb0ef41Sopenharmony_ci
6381cb0ef41Sopenharmony_ci    const dividend: int32 = SmiToInt32(left);
6391cb0ef41Sopenharmony_ci    const divisor: int32 = SmiToInt32(right);
6401cb0ef41Sopenharmony_ci
6411cb0ef41Sopenharmony_ci    // Bail out if dividend is kMinInt31 (or kMinInt32 if Smis are 32 bits)
6421cb0ef41Sopenharmony_ci    // and divisor is -1.
6431cb0ef41Sopenharmony_ci    if (divisor == -1 && dividend == kMinimumDividend) {
6441cb0ef41Sopenharmony_ci      goto SmiBailout(left, right);
6451cb0ef41Sopenharmony_ci    }
6461cb0ef41Sopenharmony_ci    // TODO(epertoso): consider adding a machine instruction that returns
6471cb0ef41Sopenharmony_ci    // both the result and the remainder.
6481cb0ef41Sopenharmony_ci    const result: int32 = dividend / divisor;
6491cb0ef41Sopenharmony_ci    const truncated: int32 = result * divisor;
6501cb0ef41Sopenharmony_ci    if (dividend != truncated) goto SmiBailout(left, right);
6511cb0ef41Sopenharmony_ci    return SmiFromInt32(result);
6521cb0ef41Sopenharmony_ci  } label SmiBailout(left: Smi, right: Smi) {
6531cb0ef41Sopenharmony_ci    goto Float64s(SmiToFloat64(left), SmiToFloat64(right));
6541cb0ef41Sopenharmony_ci  } label Float64s(left: float64, right: float64) {
6551cb0ef41Sopenharmony_ci    return AllocateHeapNumberWithValue(left / right);
6561cb0ef41Sopenharmony_ci  } label AtLeastOneBigInt(left: Numeric, right: Numeric) {
6571cb0ef41Sopenharmony_ci    tail runtime::BigIntBinaryOp(
6581cb0ef41Sopenharmony_ci        context, left, right, SmiTag<Operation>(Operation::kDivide));
6591cb0ef41Sopenharmony_ci  }
6601cb0ef41Sopenharmony_ci}
6611cb0ef41Sopenharmony_ci
6621cb0ef41Sopenharmony_cibuiltin Modulus(implicit context: Context)(left: JSAny, right: JSAny): Numeric {
6631cb0ef41Sopenharmony_ci  try {
6641cb0ef41Sopenharmony_ci    BinaryOp2(left, right) otherwise Smis, Float64s, AtLeastOneBigInt;
6651cb0ef41Sopenharmony_ci  } label Smis(left: Smi, right: Smi) {
6661cb0ef41Sopenharmony_ci    return SmiMod(left, right);
6671cb0ef41Sopenharmony_ci  } label Float64s(left: float64, right: float64) {
6681cb0ef41Sopenharmony_ci    return AllocateHeapNumberWithValue(left % right);
6691cb0ef41Sopenharmony_ci  } label AtLeastOneBigInt(left: Numeric, right: Numeric) {
6701cb0ef41Sopenharmony_ci    tail runtime::BigIntBinaryOp(
6711cb0ef41Sopenharmony_ci        context, left, right, SmiTag<Operation>(Operation::kModulus));
6721cb0ef41Sopenharmony_ci  }
6731cb0ef41Sopenharmony_ci}
6741cb0ef41Sopenharmony_ci
6751cb0ef41Sopenharmony_cibuiltin Exponentiate(implicit context: Context)(
6761cb0ef41Sopenharmony_ci    left: JSAny, right: JSAny): Numeric {
6771cb0ef41Sopenharmony_ci  try {
6781cb0ef41Sopenharmony_ci    BinaryOp1(left, right) otherwise Numbers, AtLeastOneBigInt;
6791cb0ef41Sopenharmony_ci  } label Numbers(left: Number, right: Number) {
6801cb0ef41Sopenharmony_ci    return math::MathPowImpl(left, right);
6811cb0ef41Sopenharmony_ci  } label AtLeastOneBigInt(left: Numeric, right: Numeric) {
6821cb0ef41Sopenharmony_ci    tail runtime::BigIntBinaryOp(
6831cb0ef41Sopenharmony_ci        context, left, right, SmiTag<Operation>(Operation::kExponentiate));
6841cb0ef41Sopenharmony_ci  }
6851cb0ef41Sopenharmony_ci}
6861cb0ef41Sopenharmony_ci
6871cb0ef41Sopenharmony_cibuiltin Negate(implicit context: Context)(value: JSAny): Numeric {
6881cb0ef41Sopenharmony_ci  try {
6891cb0ef41Sopenharmony_ci    UnaryOp2(value) otherwise Smi, HeapNumber, BigInt;
6901cb0ef41Sopenharmony_ci  } label Smi(s: Smi) {
6911cb0ef41Sopenharmony_ci    return SmiMul(s, -1);
6921cb0ef41Sopenharmony_ci  } label HeapNumber(h: HeapNumber) {
6931cb0ef41Sopenharmony_ci    return AllocateHeapNumberWithValue(Convert<float64>(h) * -1.0);
6941cb0ef41Sopenharmony_ci  } label BigInt(b: BigInt) {
6951cb0ef41Sopenharmony_ci    tail runtime::BigIntUnaryOp(
6961cb0ef41Sopenharmony_ci        context, b, SmiTag<Operation>(Operation::kNegate));
6971cb0ef41Sopenharmony_ci  }
6981cb0ef41Sopenharmony_ci}
6991cb0ef41Sopenharmony_ci
7001cb0ef41Sopenharmony_cibuiltin BitwiseNot(implicit context: Context)(value: JSAny): Numeric {
7011cb0ef41Sopenharmony_ci  try {
7021cb0ef41Sopenharmony_ci    UnaryOp1(value) otherwise Number, BigInt;
7031cb0ef41Sopenharmony_ci  } label Number(n: Number) {
7041cb0ef41Sopenharmony_ci    tail BitwiseXor(n, -1);
7051cb0ef41Sopenharmony_ci  } label BigInt(b: BigInt) {
7061cb0ef41Sopenharmony_ci    return runtime::BigIntUnaryOp(
7071cb0ef41Sopenharmony_ci        context, b, SmiTag<Operation>(Operation::kBitwiseNot));
7081cb0ef41Sopenharmony_ci  }
7091cb0ef41Sopenharmony_ci}
7101cb0ef41Sopenharmony_ci
7111cb0ef41Sopenharmony_cibuiltin Decrement(implicit context: Context)(value: JSAny): Numeric {
7121cb0ef41Sopenharmony_ci  try {
7131cb0ef41Sopenharmony_ci    UnaryOp1(value) otherwise Number, BigInt;
7141cb0ef41Sopenharmony_ci  } label Number(n: Number) {
7151cb0ef41Sopenharmony_ci    tail Subtract(n, 1);
7161cb0ef41Sopenharmony_ci  } label BigInt(b: BigInt) {
7171cb0ef41Sopenharmony_ci    return runtime::BigIntUnaryOp(
7181cb0ef41Sopenharmony_ci        context, b, SmiTag<Operation>(Operation::kDecrement));
7191cb0ef41Sopenharmony_ci  }
7201cb0ef41Sopenharmony_ci}
7211cb0ef41Sopenharmony_ci
7221cb0ef41Sopenharmony_cibuiltin Increment(implicit context: Context)(value: JSAny): Numeric {
7231cb0ef41Sopenharmony_ci  try {
7241cb0ef41Sopenharmony_ci    UnaryOp1(value) otherwise Number, BigInt;
7251cb0ef41Sopenharmony_ci  } label Number(n: Number) {
7261cb0ef41Sopenharmony_ci    tail Add(n, 1);
7271cb0ef41Sopenharmony_ci  } label BigInt(b: BigInt) {
7281cb0ef41Sopenharmony_ci    return runtime::BigIntUnaryOp(
7291cb0ef41Sopenharmony_ci        context, b, SmiTag<Operation>(Operation::kIncrement));
7301cb0ef41Sopenharmony_ci  }
7311cb0ef41Sopenharmony_ci}
7321cb0ef41Sopenharmony_ci
7331cb0ef41Sopenharmony_ci// Bitwise binary operations.
7341cb0ef41Sopenharmony_ci
7351cb0ef41Sopenharmony_ciextern macro BinaryOpAssembler::Generate_BitwiseBinaryOp(
7361cb0ef41Sopenharmony_ci    constexpr Operation, JSAny, JSAny, Context): Object;
7371cb0ef41Sopenharmony_ci
7381cb0ef41Sopenharmony_cibuiltin ShiftLeft(implicit context: Context)(
7391cb0ef41Sopenharmony_ci    left: JSAny, right: JSAny): Object {
7401cb0ef41Sopenharmony_ci  return Generate_BitwiseBinaryOp(Operation::kShiftLeft, left, right, context);
7411cb0ef41Sopenharmony_ci}
7421cb0ef41Sopenharmony_ci
7431cb0ef41Sopenharmony_cibuiltin ShiftRight(implicit context: Context)(
7441cb0ef41Sopenharmony_ci    left: JSAny, right: JSAny): Object {
7451cb0ef41Sopenharmony_ci  return Generate_BitwiseBinaryOp(Operation::kShiftRight, left, right, context);
7461cb0ef41Sopenharmony_ci}
7471cb0ef41Sopenharmony_ci
7481cb0ef41Sopenharmony_cibuiltin ShiftRightLogical(implicit context: Context)(
7491cb0ef41Sopenharmony_ci    left: JSAny, right: JSAny): Object {
7501cb0ef41Sopenharmony_ci  return Generate_BitwiseBinaryOp(
7511cb0ef41Sopenharmony_ci      Operation::kShiftRightLogical, left, right, context);
7521cb0ef41Sopenharmony_ci}
7531cb0ef41Sopenharmony_ci
7541cb0ef41Sopenharmony_cibuiltin BitwiseAnd(implicit context: Context)(
7551cb0ef41Sopenharmony_ci    left: JSAny, right: JSAny): Object {
7561cb0ef41Sopenharmony_ci  return Generate_BitwiseBinaryOp(Operation::kBitwiseAnd, left, right, context);
7571cb0ef41Sopenharmony_ci}
7581cb0ef41Sopenharmony_ci
7591cb0ef41Sopenharmony_cibuiltin BitwiseOr(implicit context: Context)(
7601cb0ef41Sopenharmony_ci    left: JSAny, right: JSAny): Object {
7611cb0ef41Sopenharmony_ci  return Generate_BitwiseBinaryOp(Operation::kBitwiseOr, left, right, context);
7621cb0ef41Sopenharmony_ci}
7631cb0ef41Sopenharmony_ci
7641cb0ef41Sopenharmony_cibuiltin BitwiseXor(implicit context: Context)(
7651cb0ef41Sopenharmony_ci    left: JSAny, right: JSAny): Object {
7661cb0ef41Sopenharmony_ci  return Generate_BitwiseBinaryOp(Operation::kBitwiseXor, left, right, context);
7671cb0ef41Sopenharmony_ci}
7681cb0ef41Sopenharmony_ci
7691cb0ef41Sopenharmony_ci// Relational builtins.
7701cb0ef41Sopenharmony_ci
7711cb0ef41Sopenharmony_cibuiltin LessThan(implicit context: Context)(left: JSAny, right: JSAny): Object {
7721cb0ef41Sopenharmony_ci  return RelationalComparison(Operation::kLessThan, left, right, context);
7731cb0ef41Sopenharmony_ci}
7741cb0ef41Sopenharmony_ci
7751cb0ef41Sopenharmony_cibuiltin LessThanOrEqual(implicit context: Context)(
7761cb0ef41Sopenharmony_ci    left: JSAny, right: JSAny): Object {
7771cb0ef41Sopenharmony_ci  return RelationalComparison(
7781cb0ef41Sopenharmony_ci      Operation::kLessThanOrEqual, left, right, context);
7791cb0ef41Sopenharmony_ci}
7801cb0ef41Sopenharmony_ci
7811cb0ef41Sopenharmony_cibuiltin GreaterThan(implicit context: Context)(
7821cb0ef41Sopenharmony_ci    left: JSAny, right: JSAny): Object {
7831cb0ef41Sopenharmony_ci  return RelationalComparison(Operation::kGreaterThan, left, right, context);
7841cb0ef41Sopenharmony_ci}
7851cb0ef41Sopenharmony_ci
7861cb0ef41Sopenharmony_cibuiltin GreaterThanOrEqual(implicit context: Context)(
7871cb0ef41Sopenharmony_ci    left: JSAny, right: JSAny): Object {
7881cb0ef41Sopenharmony_ci  return RelationalComparison(
7891cb0ef41Sopenharmony_ci      Operation::kGreaterThanOrEqual, left, right, context);
7901cb0ef41Sopenharmony_ci}
7911cb0ef41Sopenharmony_ci
7921cb0ef41Sopenharmony_cibuiltin Equal(implicit context: Context)(left: JSAny, right: JSAny): Object {
7931cb0ef41Sopenharmony_ci  return Equal(left, right, context);
7941cb0ef41Sopenharmony_ci}
7951cb0ef41Sopenharmony_ci
7961cb0ef41Sopenharmony_cibuiltin StrictEqual(implicit context: Context)(
7971cb0ef41Sopenharmony_ci    left: JSAny, right: JSAny): Object {
7981cb0ef41Sopenharmony_ci  return ::StrictEqual(left, right);
7991cb0ef41Sopenharmony_ci}
8001cb0ef41Sopenharmony_ci
8011cb0ef41Sopenharmony_ci}  // namespace number
802