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