uint128_amd64.go raw
1 //go:build amd64
2
3 package avx
4
5 import "math/bits"
6
7 // AMD64 implementation with AVX2 assembly where beneficial.
8 // For simple operations, Go with compiler intrinsics is often as fast as assembly.
9
10 // Add adds two Uint128 values, returning the result and carry.
11 func (a Uint128) Add(b Uint128) (result Uint128, carry uint64) {
12 result.Lo, carry = bits.Add64(a.Lo, b.Lo, 0)
13 result.Hi, carry = bits.Add64(a.Hi, b.Hi, carry)
14 return
15 }
16
17 // AddCarry adds two Uint128 values with an input carry.
18 func (a Uint128) AddCarry(b Uint128, carryIn uint64) (result Uint128, carryOut uint64) {
19 result.Lo, carryOut = bits.Add64(a.Lo, b.Lo, carryIn)
20 result.Hi, carryOut = bits.Add64(a.Hi, b.Hi, carryOut)
21 return
22 }
23
24 // Sub subtracts b from a, returning the result and borrow.
25 func (a Uint128) Sub(b Uint128) (result Uint128, borrow uint64) {
26 result.Lo, borrow = bits.Sub64(a.Lo, b.Lo, 0)
27 result.Hi, borrow = bits.Sub64(a.Hi, b.Hi, borrow)
28 return
29 }
30
31 // SubBorrow subtracts b from a with an input borrow.
32 func (a Uint128) SubBorrow(b Uint128, borrowIn uint64) (result Uint128, borrowOut uint64) {
33 result.Lo, borrowOut = bits.Sub64(a.Lo, b.Lo, borrowIn)
34 result.Hi, borrowOut = bits.Sub64(a.Hi, b.Hi, borrowOut)
35 return
36 }
37
38 // Mul64 multiplies two 64-bit values and returns a 128-bit result.
39 func Mul64(a, b uint64) Uint128 {
40 hi, lo := bits.Mul64(a, b)
41 return Uint128{Lo: lo, Hi: hi}
42 }
43
44 // Mul multiplies two Uint128 values and returns a 256-bit result as [4]uint64.
45 // Result is [lo0, lo1, hi0, hi1] where value = lo0 + lo1<<64 + hi0<<128 + hi1<<192
46 func (a Uint128) Mul(b Uint128) [4]uint64 {
47 // Use assembly for the full 128x128->256 multiplication
48 return uint128Mul(a, b)
49 }
50
51 // uint128Mul performs 128x128->256 bit multiplication using optimized assembly.
52 //
53 //go:noescape
54 func uint128Mul(a, b Uint128) [4]uint64
55
56 // IsZero returns true if the Uint128 is zero.
57 func (a Uint128) IsZero() bool {
58 return a.Lo == 0 && a.Hi == 0
59 }
60
61 // Cmp compares two Uint128 values.
62 // Returns -1 if a < b, 0 if a == b, 1 if a > b.
63 func (a Uint128) Cmp(b Uint128) int {
64 if a.Hi < b.Hi {
65 return -1
66 }
67 if a.Hi > b.Hi {
68 return 1
69 }
70 if a.Lo < b.Lo {
71 return -1
72 }
73 if a.Lo > b.Lo {
74 return 1
75 }
76 return 0
77 }
78
79 // Lsh shifts a Uint128 left by n bits (n < 128).
80 func (a Uint128) Lsh(n uint) Uint128 {
81 if n >= 64 {
82 return Uint128{Lo: 0, Hi: a.Lo << (n - 64)}
83 }
84 if n == 0 {
85 return a
86 }
87 return Uint128{
88 Lo: a.Lo << n,
89 Hi: (a.Hi << n) | (a.Lo >> (64 - n)),
90 }
91 }
92
93 // Rsh shifts a Uint128 right by n bits (n < 128).
94 func (a Uint128) Rsh(n uint) Uint128 {
95 if n >= 64 {
96 return Uint128{Lo: a.Hi >> (n - 64), Hi: 0}
97 }
98 if n == 0 {
99 return a
100 }
101 return Uint128{
102 Lo: (a.Lo >> n) | (a.Hi << (64 - n)),
103 Hi: a.Hi >> n,
104 }
105 }
106
107 // Or returns the bitwise OR of two Uint128 values.
108 func (a Uint128) Or(b Uint128) Uint128 {
109 return Uint128{Lo: a.Lo | b.Lo, Hi: a.Hi | b.Hi}
110 }
111
112 // And returns the bitwise AND of two Uint128 values.
113 func (a Uint128) And(b Uint128) Uint128 {
114 return Uint128{Lo: a.Lo & b.Lo, Hi: a.Hi & b.Hi}
115 }
116
117 // Xor returns the bitwise XOR of two Uint128 values.
118 func (a Uint128) Xor(b Uint128) Uint128 {
119 return Uint128{Lo: a.Lo ^ b.Lo, Hi: a.Hi ^ b.Hi}
120 }
121
122 // Not returns the bitwise NOT of a Uint128.
123 func (a Uint128) Not() Uint128 {
124 return Uint128{Lo: ^a.Lo, Hi: ^a.Hi}
125 }
126