gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/time/arith_arm64.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // This file provides a generic Go implementation of uint128 divided by uint64.
     6  
     7  // The code is derived from Go's generic math/big.divWW_g
     8  // (src/math/big/arith.go), but is only used on ARM64.
     9  
    10  package time
    11  
    12  import "math/bits"
    13  
    14  type word uint
    15  
    16  const (
    17  	_W  = bits.UintSize // word size in bits
    18  	_W2 = _W / 2        // half word size in bits
    19  	_B2 = 1 << _W2      // half digit base
    20  	_M2 = _B2 - 1       // half digit mask
    21  )
    22  
    23  // nlz returns the number of leading zeros in x.
    24  // Wraps bits.LeadingZeros call for convenience.
    25  func nlz(x word) uint {
    26  	return uint(bits.LeadingZeros(uint(x)))
    27  }
    28  
    29  // q = (u1<<_W + u0 - r)/y
    30  // Adapted from Warren, Hacker's Delight, p. 152.
    31  func divWW(u1, u0, v word) (q, r word) {
    32  	if u1 >= v {
    33  		return 1<<_W - 1, 1<<_W - 1
    34  	}
    35  
    36  	s := nlz(v)
    37  	v <<= s
    38  
    39  	vn1 := v >> _W2
    40  	vn0 := v & _M2
    41  	un32 := u1<<s | u0>>(_W-s)
    42  	un10 := u0 << s
    43  	un1 := un10 >> _W2
    44  	un0 := un10 & _M2
    45  	q1 := un32 / vn1
    46  	rhat := un32 - q1*vn1
    47  
    48  	for q1 >= _B2 || q1*vn0 > _B2*rhat+un1 {
    49  		q1--
    50  		rhat += vn1
    51  
    52  		if rhat >= _B2 {
    53  			break
    54  		}
    55  	}
    56  
    57  	un21 := un32*_B2 + un1 - q1*v
    58  	q0 := un21 / vn1
    59  	rhat = un21 - q0*vn1
    60  
    61  	for q0 >= _B2 || q0*vn0 > _B2*rhat+un0 {
    62  		q0--
    63  		rhat += vn1
    64  		if rhat >= _B2 {
    65  			break
    66  		}
    67  	}
    68  
    69  	return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s
    70  }