Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions vlib/math/bits/bits.amd64.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module bits

fn C._umul128(x u64, y u64, result_hi &u64) u64
fn C._addcarry_u64(carry_in u8, a u64, b u64, out &u64) u8
fn C._udiv128(hi u64, lo u64, y u64, rem &u64) u64

// mul_64 returns the 128-bit product of x and y: (hi, lo) = x * y
// with the product bits' upper half returned in hi and the lower
// half returned in lo.
//
// This function's execution time does not depend on the inputs.
@[inline]
pub fn mul_64(x u64, y u64) (u64, u64) {
mut hi := u64(0)
mut lo := u64(0)
$if msvc {
lo = C._umul128(x, y, &hi)
return hi, lo
} $else $if amd64 {
asm amd64 {
mulq rdx
; =a (lo)
=d (hi)
; a (x)
d (y)
; cc
}
return hi, lo
}
// cross compile
return mul_64_default(x, y)
}

// mul_add_64 returns the 128-bit result of x * y + z: (hi, lo) = x * y + z
// with the result bits' upper half returned in hi and the lower
// half returned in lo.
@[inline]
pub fn mul_add_64(x u64, y u64, z u64) (u64, u64) {
mut hi := u64(0)
mut lo := u64(0)
$if msvc {
lo = C._umul128(x, y, &hi)
carry := C._addcarry_u64(0, lo, z, &lo)
hi += carry
return hi, lo
} $else $if amd64 {
asm amd64 {
mulq rdx
addq rax, z
adcq rdx, 0
; =a (lo)
=d (hi)
; a (x)
d (y)
r (z)
; cc
}
return hi, lo
}
// cross compile
return mul_add_64_default(x, y, z)
}

// div_64 returns the quotient and remainder of (hi, lo) divided by y:
// quo = (hi, lo)/y, rem = (hi, lo)%y with the dividend bits' upper
// half in parameter hi and the lower half in parameter lo.
// div_64 panics for y == 0 (division by zero) or y <= hi (quotient overflow).
@[inline]
pub fn div_64(hi u64, lo u64, y1 u64) (u64, u64) {
mut y := y1
if y == 0 {
panic(overflow_error)
}
if y <= hi {
panic(overflow_error)
}

mut quo := u64(0)
mut rem := u64(0)
$if msvc {
quo = C._udiv128(hi, lo, y, &rem)
return quo, rem
} $else $if amd64 {
asm amd64 {
div y
; =a (quo)
=d (rem)
; d (hi)
a (lo)
r (y)
; cc
}
return quo, rem
}
// cross compile
return div_64_default(hi, lo, y1)
}
55 changes: 55 additions & 0 deletions vlib/math/bits/bits.arm64.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module bits

// mul_64 returns the 128-bit product of x and y: (hi, lo) = x * y
// with the product bits' upper half returned in hi and the lower
// half returned in lo.
//
// This function's execution time does not depend on the inputs.
@[inline]
pub fn mul_64(x u64, y u64) (u64, u64) {
mut hi := u64(0)
mut lo := u64(0)
$if arm64 && !tinyc {
asm arm64 {
mul lo, x, y
umulh hi, x, y
; =&r (hi)
=&r (lo)
; r (x)
r (y)
; cc
}
return hi, lo
}
// cross compile
return mul_64_default(x, y)
}

// mul_add_64 returns the 128-bit result of x * y + z: (hi, lo) = x * y + z
// with the result bits' upper half returned in hi and the lower
// half returned in lo.
@[inline]
pub fn mul_add_64(x u64, y u64, z u64) (u64, u64) {
mut hi := u64(0)
mut lo := u64(0)
$if arm64 && !tinyc {
asm arm64 {
mul lo, x, y
umulh hi, x, y
adds lo, lo, z
adc hi, hi, xzr
; =&r (hi)
=&r (lo)
; r (x)
r (y)
r (z)
; cc
}
return hi, lo
}
// cross compile
return mul_add_64_default(x, y, z)
}
186 changes: 186 additions & 0 deletions vlib/math/bits/bits.c.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module bits

fn C.__builtin_clz(x u32) int
fn C.__builtin_clzll(x u64) int
fn C.__lzcnt(x u32) int
fn C.__lzcnt64(x u64) int

// --- LeadingZeros ---
// leading_zeros_8 returns the number of leading zero bits in x; the result is 8 for x == 0.
@[inline]
pub fn leading_zeros_8(x u8) int {
if x == 0 {
return 8
}
$if msvc {
return C.__lzcnt(x) - 24
} $else $if !tinyc {
return C.__builtin_clz(x) - 24
}
return leading_zeros_8_default(x)
}

// leading_zeros_16 returns the number of leading zero bits in x; the result is 16 for x == 0.
@[inline]
pub fn leading_zeros_16(x u16) int {
if x == 0 {
return 16
}
$if msvc {
return C.__lzcnt(x) - 16
} $else $if !tinyc {
return C.__builtin_clz(x) - 16
}
return leading_zeros_16_default(x)
}

// leading_zeros_32 returns the number of leading zero bits in x; the result is 32 for x == 0.
@[inline]
pub fn leading_zeros_32(x u32) int {
if x == 0 {
return 32
}
$if msvc {
return C.__lzcnt(x)
} $else $if !tinyc {
return C.__builtin_clz(x)
}
return leading_zeros_32_default(x)
}

// leading_zeros_64 returns the number of leading zero bits in x; the result is 64 for x == 0.
@[inline]
pub fn leading_zeros_64(x u64) int {
if x == 0 {
return 64
}
$if msvc {
return C.__lzcnt64(x)
} $else $if !tinyc {
return C.__builtin_clzll(x)
}
return leading_zeros_64_default(x)
}

fn C.__builtin_ctz(x u32) int
fn C.__builtin_ctzll(x u64) int
fn C._BitScanForward(pos &int, x u32) u8
fn C._BitScanForward64(pos &int, x u64) u8

// --- TrailingZeros ---
// trailing_zeros_8 returns the number of trailing zero bits in x; the result is 8 for x == 0.
@[inline]
pub fn trailing_zeros_8(x u8) int {
if x == 0 {
return 8
}
$if msvc {
mut pos := 0
_ := C._BitScanForward(&pos, x)
return pos
} $else $if !tinyc {
return C.__builtin_ctz(x)
}
return trailing_zeros_8_default(x)
}

// trailing_zeros_16 returns the number of trailing zero bits in x; the result is 16 for x == 0.
@[inline]
pub fn trailing_zeros_16(x u16) int {
if x == 0 {
return 16
}
$if msvc {
mut pos := 0
_ := C._BitScanForward(&pos, x)
return pos
} $else $if !tinyc {
return C.__builtin_ctz(x)
}
return trailing_zeros_16_default(x)
}

// trailing_zeros_32 returns the number of trailing zero bits in x; the result is 32 for x == 0.
@[inline]
pub fn trailing_zeros_32(x u32) int {
if x == 0 {
return 32
}
$if msvc {
mut pos := 0
_ := C._BitScanForward(&pos, x)
return pos
} $else $if !tinyc {
return C.__builtin_ctz(x)
}
return trailing_zeros_32_default(x)
}

// trailing_zeros_64 returns the number of trailing zero bits in x; the result is 64 for x == 0.
@[inline]
pub fn trailing_zeros_64(x u64) int {
if x == 0 {
return 64
}
$if msvc {
mut pos := 0
_ := C._BitScanForward64(&pos, x)
return pos
} $else $if !tinyc {
return C.__builtin_ctzll(x)
}
return trailing_zeros_64_default(x)
}

fn C.__builtin_popcount(x u32) int
fn C.__builtin_popcountll(x u64) int
fn C.__popcnt(x u32) int
fn C.__popcnt64(x u64) int

// --- OnesCount ---
// ones_count_8 returns the number of one bits ("population count") in x.
@[inline]
pub fn ones_count_8(x u8) int {
$if msvc {
return C.__popcnt(x)
} $else $if !tinyc {
return C.__builtin_popcount(x)
}
return ones_count_8_default(x)
}

// ones_count_16 returns the number of one bits ("population count") in x.
@[inline]
pub fn ones_count_16(x u16) int {
$if msvc {
return C.__popcnt(x)
} $else $if !tinyc {
return C.__builtin_popcount(x)
}
return ones_count_16_default(x)
}

// ones_count_32 returns the number of one bits ("population count") in x.
@[inline]
pub fn ones_count_32(x u32) int {
$if msvc {
return C.__popcnt(x)
} $else $if !tinyc {
return C.__builtin_popcount(x)
}
return ones_count_32_default(x)
}

// ones_count_64 returns the number of one bits ("population count") in x.
@[inline]
pub fn ones_count_64(x u64) int {
$if msvc {
return C.__popcnt64(x)
} $else $if !tinyc {
return C.__builtin_popcountll(x)
}
return ones_count_64_default(x)
}
Loading
Loading