[K/Wasm] Generate wasm-specific unsigned implementations ^KT-58039 Fixed

This commit is contained in:
Artem Kobzar
2024-01-23 18:49:06 +01:00
committed by Space Team
parent b59993d88a
commit 8c69ffe8c9
24 changed files with 666 additions and 541 deletions
@@ -4,6 +4,8 @@
*/
package kotlin.wasm.internal
// Based on the AssemblyScript implementation [https://github.com/AssemblyScript/assemblyscript/blob/1e0466ef94fa5cacd0984e4f31a0087de51538a8/std/assembly/util/number.ts]
private enum class CharCodes(val code: Int) {
// PERCENT(0x25),
PLUS(0x2B),
@@ -42,125 +44,115 @@ private fun digitToChar(input: Int): Char {
return (CharCodes._0.code + input).toChar()
}
// Inspired by the AssemblyScript implementation
internal fun itoa32(inputValue: Int, radix: Int): String {
if (radix < 2 || radix > 36)
throw IllegalArgumentException("Radix argument is unreasonable")
if (radix != 10)
TODO("When we need it")
internal fun itoa32(inputValue: Int): String {
if (inputValue == 0) return "0"
// We can't represent abs(Int.MIN_VALUE), so just hardcode it here
if (inputValue == Int.MIN_VALUE) return "-2147483648"
val sign = inputValue ushr 31
assert(sign == 1 || sign == 0)
val absValue = if (sign == 1) -inputValue else inputValue
val isNegative = inputValue < 0
val absValue = if (isNegative) -inputValue else inputValue
val absValueString = utoa32(absValue.toUInt())
val decimals = decimalCount32(absValue) + sign
return if (isNegative) "-$absValueString" else absValueString
}
internal fun utoa32(inputValue: UInt): String {
if (inputValue == 0U) return "0"
val decimals = decimalCount32(inputValue)
val buf = WasmCharArray(decimals)
utoaDecSimple(buf, absValue, decimals)
if (sign == 1)
buf.set(0, CharCodes.MINUS.code.toChar())
utoaDecSimple(buf, inputValue, decimals)
return buf.createString()
}
private fun utoaDecSimple(buffer: WasmCharArray, numInput: Int, offsetInput: Int) {
assert(numInput != 0)
private fun utoaDecSimple(buffer: WasmCharArray, numInput: UInt, offsetInput: Int) {
assert(numInput != 0U)
assert(buffer.len() > 0)
assert(offsetInput > 0 && offsetInput <= buffer.len())
var num = numInput
var offset = offsetInput
do {
val t = num / 10
val r = num % 10
val t = num / 10U
val r = num % 10U
num = t
offset--
buffer.set(offset, digitToChar(r))
} while (num > 0)
buffer.set(offset, digitToChar(r.toInt()))
} while (num > 0U)
}
private fun utoaDecSimple64(buffer: WasmCharArray, numInput: Long, offsetInput: Int) {
assert(numInput != 0L)
private fun utoaDecSimple64(buffer: WasmCharArray, numInput: ULong, offsetInput: Int) {
assert(numInput != 0UL)
assert(buffer.len() > 0)
assert(offsetInput > 0 && offsetInput <= buffer.len())
var num = numInput
var offset = offsetInput
do {
val t = num / 10
val r = (num % 10).toInt()
val t = num / 10U
val r = num % 10U
num = t
offset--
buffer.set(offset, digitToChar(r))
} while (num > 0)
buffer.set(offset, digitToChar(r.toInt()))
} while (num > 0U)
}
private fun Boolean.toInt() = if (this) 1 else 0
private fun Boolean.toLong() = if (this) 1L else 0L
private fun decimalCount32(value: Int): Int {
if (value < 100000) {
if (value < 100) {
return 1 + (value >= 10).toInt()
private fun decimalCount32(value: UInt): Int {
if (value < 100000u) {
if (value < 100u) {
return 1 + (value >= 10u).toInt()
} else {
return 3 + (value >= 10000).toInt() + (value >= 1000).toInt()
return 3 + (value >= 10000u).toInt() + (value >= 1000u).toInt()
}
} else {
if (value < 10000000) {
return 6 + (value >= 1000000).toInt()
if (value < 10000000u) {
return 6 + (value >= 1000000u).toInt()
} else {
return 8 + (value >= 1000000000).toInt() + (value >= 100000000).toInt()
return 8 + (value >= 1000000000u).toInt() + (value >= 100000000u).toInt()
}
}
}
internal fun itoa64(inputValue: Long, radix: Int): String {
internal fun itoa64(inputValue: Long): String {
if (inputValue in Int.MIN_VALUE..Int.MAX_VALUE)
return itoa32(inputValue.toInt(), radix)
return itoa32(inputValue.toInt())
if (radix < 2 || radix > 36)
throw IllegalArgumentException("Radix argument is unreasonable")
val isNegative = inputValue < 0
val absValue = if (isNegative) -inputValue else inputValue
val absValueString = utoa64(absValue.toULong())
if (inputValue == 0L) return "0"
// We can't represent abs(Long.MIN_VALUE), so just hardcode it here
if (inputValue == Long.MIN_VALUE) return "-9223372036854775808"
return if (isNegative) "-$absValueString" else absValueString
}
if (radix != 10) {
TODO("When we need it")
}
internal fun utoa64(inputValue: ULong): String {
if (inputValue <= UInt.MAX_VALUE) return utoa32(inputValue.toUInt())
val sign = (inputValue ushr 63).toInt()
assert(sign == 1 || sign == 0)
val absValue = if (sign == 1) -inputValue else inputValue
val decimals = decimalCount64High(absValue) + sign
val decimals = decimalCount64High(inputValue)
val buf = WasmCharArray(decimals)
utoaDecSimple64(buf, absValue, decimals)
if (sign == 1)
buf.set(0, CharCodes.MINUS.code.toChar())
utoaDecSimple64(buf, inputValue, decimals)
return buf.createString()
}
// Count number of decimals for u64 values
// In our case input value always greater than 2^32-1 so we can skip some parts
private fun decimalCount64High(value: Long): Int {
if (value < 1000000000000000) {
if (value < 1000000000000) {
return 10 + (value >= 100000000000).toInt() + (value >= 10000000000).toInt()
private fun decimalCount64High(value: ULong): Int {
if (value < 1000000000000000UL) {
if (value < 1000000000000UL) {
return 10 + (value >= 100000000000UL).toInt() + (value >= 10000000000UL).toInt()
} else {
return 13 + (value >= 100000000000000).toInt() + (value >= 10000000000000).toInt()
return 13 + (value >= 100000000000000UL).toInt() + (value >= 10000000000000UL).toInt()
}
} else {
if (value < 100000000000000000) {
return 16 + (value >= 10000000000000000).toInt()
if (value < 100000000000000000UL) {
return 16 + (value >= 10000000000000000UL).toInt()
} else {
return 18 + (value >= 1000000000000000000).toInt()
return 18 + (value >= 10000000000000000000UL).toInt() + (value >= 1000000000000000000UL).toInt()
}
}
}
@@ -331,7 +323,7 @@ private fun genDigits(buffer: WasmCharArray, w_frc: Long, mp_frc: Long, mp_exp:
var p1 = (mp_frc ushr one_exp).toInt()
var p2 = mp_frc and mask
var kappa = decimalCount32(p1)
var kappa = decimalCount32(p1.toUInt())
var len = sign
while (kappa > 0) {
@@ -11,6 +11,14 @@ package kotlin.wasm.internal
internal fun wasm_i32_compareTo(x: Int, y: Int): Int =
wasm_i32_ge_s(x, y).toInt() - wasm_i32_le_s(x, y).toInt()
@PublishedApi
internal fun wasm_u32_compareTo(x: Int, y: Int): Int =
wasm_i32_ge_u(x, y).toInt() - wasm_i32_le_u(x, y).toInt()
@PublishedApi
internal fun wasm_i64_compareTo(x: Long, y: Long): Int =
wasm_i64_ge_s(x, y).toInt() - wasm_i64_le_s(x, y).toInt()
@PublishedApi
internal fun wasm_u64_compareTo(x: Long, y: Long): Int =
wasm_i64_ge_u(x, y).toInt() - wasm_i64_le_u(x, y).toInt()