github.com/gopherjs/gopherjs@v1.19.0-beta1.0.20240506212314-27071a8796e4/compiler/natives/src/math/bits/bits.go (about)

     1  //go:build js
     2  // +build js
     3  
     4  package bits
     5  
     6  type _err string
     7  
     8  func (e _err) Error() string {
     9  	return string(e)
    10  }
    11  
    12  // RuntimeError implements runtime.Error.
    13  func (e _err) RuntimeError() {
    14  }
    15  
    16  var (
    17  	overflowError error = _err("runtime error: integer overflow")
    18  	divideError   error = _err("runtime error: integer divide by zero")
    19  )
    20  
    21  func Mul32(x, y uint32) (hi, lo uint32) {
    22  	// Avoid slow 64-bit integers for better performance. Adapted from Mul64().
    23  	const mask16 = 1<<16 - 1
    24  	x0 := x & mask16
    25  	x1 := x >> 16
    26  	y0 := y & mask16
    27  	y1 := y >> 16
    28  	w0 := x0 * y0
    29  	t := x1*y0 + w0>>16
    30  	w1 := t & mask16
    31  	w2 := t >> 16
    32  	w1 += x0 * y1
    33  	hi = x1*y1 + w2 + w1>>16
    34  	lo = x * y
    35  	return
    36  }
    37  
    38  func Add32(x, y, carry uint32) (sum, carryOut uint32) {
    39  	// Avoid slow 64-bit integers for better performance. Adapted from Add64().
    40  	sum = x + y + carry
    41  	carryOut = ((x & y) | ((x | y) &^ sum)) >> 31
    42  	return
    43  }
    44  
    45  func Div32(hi, lo, y uint32) (quo, rem uint32) {
    46  	// Avoid slow 64-bit integers for better performance. Adapted from Div64().
    47  	const (
    48  		two16  = 1 << 16
    49  		mask16 = two16 - 1
    50  	)
    51  	if y == 0 {
    52  		panic(divideError)
    53  	}
    54  	if y <= hi {
    55  		panic(overflowError)
    56  	}
    57  
    58  	s := uint(LeadingZeros32(y))
    59  	y <<= s
    60  
    61  	yn1 := y >> 16
    62  	yn0 := y & mask16
    63  	un16 := hi<<s | lo>>(32-s)
    64  	un10 := lo << s
    65  	un1 := un10 >> 16
    66  	un0 := un10 & mask16
    67  	q1 := un16 / yn1
    68  	rhat := un16 - q1*yn1
    69  
    70  	for q1 >= two16 || q1*yn0 > two16*rhat+un1 {
    71  		q1--
    72  		rhat += yn1
    73  		if rhat >= two16 {
    74  			break
    75  		}
    76  	}
    77  
    78  	un21 := un16*two16 + un1 - q1*y
    79  	q0 := un21 / yn1
    80  	rhat = un21 - q0*yn1
    81  
    82  	for q0 >= two16 || q0*yn0 > two16*rhat+un0 {
    83  		q0--
    84  		rhat += yn1
    85  		if rhat >= two16 {
    86  			break
    87  		}
    88  	}
    89  
    90  	return q1*two16 + q0, (un21*two16 + un0 - q0*y) >> s
    91  }
    92  
    93  func Rem32(hi, lo, y uint32) uint32 {
    94  	// We scale down hi so that hi < y, then use Div32 to compute the
    95  	// rem with the guarantee that it won't panic on quotient overflow.
    96  	// Given that
    97  	//   hi ≡ hi%y    (mod y)
    98  	// we have
    99  	//   hi<<64 + lo ≡ (hi%y)<<64 + lo    (mod y)
   100  	_, rem := Div32(hi%y, lo, y)
   101  	return rem
   102  }