github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/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 }