diff options
author | smasher164 <aindurti@gmail.com> | 2019-04-04 15:57:24 -0400 |
---|---|---|
committer | Filippo Valsorda <filippo@golang.org> | 2019-05-20 01:13:27 +0000 |
commit | 5ca44dc403d4a609eeafb0f699a63f19ef045cd6 (patch) | |
tree | 79748a6eaed5b47b1d0c7e161d01a0159f4c74fe /src/math | |
parent | 1ab063ce532f72851cef735238ba656cc7680b66 (diff) | |
download | go-git-5ca44dc403d4a609eeafb0f699a63f19ef045cd6.tar.gz |
math/bits: make Add and Sub fallbacks constant time
Make the extended precision add-with-carry and sub-with-carry operations
take a constant amount of time to execute, regardless of input.
name old time/op new time/op delta
Add-4 1.16ns ±11% 1.51ns ± 5% +30.52% (p=0.008 n=5+5)
Add32-4 1.08ns ± 0% 1.03ns ± 1% -4.86% (p=0.029 n=4+4)
Add64-4 1.09ns ± 1% 1.95ns ± 3% +79.23% (p=0.008 n=5+5)
Add64multiple-4 4.03ns ± 1% 4.55ns ±11% +13.07% (p=0.008 n=5+5)
Sub-4 1.08ns ± 1% 1.50ns ± 0% +38.17% (p=0.016 n=5+4)
Sub32-4 1.09ns ± 2% 1.53ns ±10% +40.26% (p=0.008 n=5+5)
Sub64-4 1.10ns ± 1% 1.47ns ± 1% +33.39% (p=0.008 n=5+5)
Sub64multiple-4 4.30ns ± 2% 4.08ns ± 4% -5.07% (p=0.032 n=5+5)
Fixes #31267
Change-Id: I1824b1b3ab8f09902ce8b5fef84ce2fdb8847ed9
Reviewed-on: https://go-review.googlesource.com/c/go/+/170758
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src/math')
-rw-r--r-- | src/math/bits/bits.go | 49 |
1 files changed, 19 insertions, 30 deletions
diff --git a/src/math/bits/bits.go b/src/math/bits/bits.go index 24d910c27e..1a85485a5a 100644 --- a/src/math/bits/bits.go +++ b/src/math/bits/bits.go @@ -332,23 +332,21 @@ func Len64(x uint64) (n int) { // The carry input must be 0 or 1; otherwise the behavior is undefined. // The carryOut output is guaranteed to be 0 or 1. func Add(x, y, carry uint) (sum, carryOut uint) { - yc := y + carry - sum = x + yc - if sum < x || yc < y { - carryOut = 1 + if UintSize == 32 { + s32, c32 := Add32(uint32(x), uint32(y), uint32(carry)) + return uint(s32), uint(c32) } - return + s64, c64 := Add64(uint64(x), uint64(y), uint64(carry)) + return uint(s64), uint(c64) } // Add32 returns the sum with carry of x, y and carry: sum = x + y + carry. // The carry input must be 0 or 1; otherwise the behavior is undefined. // The carryOut output is guaranteed to be 0 or 1. func Add32(x, y, carry uint32) (sum, carryOut uint32) { - yc := y + carry - sum = x + yc - if sum < x || yc < y { - carryOut = 1 - } + sum64 := uint64(x) + uint64(y) + uint64(carry) + sum = uint32(sum64) + carryOut = uint32(sum64 >> 32) return } @@ -356,11 +354,8 @@ func Add32(x, y, carry uint32) (sum, carryOut uint32) { // The carry input must be 0 or 1; otherwise the behavior is undefined. // The carryOut output is guaranteed to be 0 or 1. func Add64(x, y, carry uint64) (sum, carryOut uint64) { - yc := y + carry - sum = x + yc - if sum < x || yc < y { - carryOut = 1 - } + sum = x + y + carry + carryOut = ((x & y) | ((x | y) &^ sum)) >> 63 return } @@ -370,23 +365,20 @@ func Add64(x, y, carry uint64) (sum, carryOut uint64) { // The borrow input must be 0 or 1; otherwise the behavior is undefined. // The borrowOut output is guaranteed to be 0 or 1. func Sub(x, y, borrow uint) (diff, borrowOut uint) { - yb := y + borrow - diff = x - yb - if diff > x || yb < y { - borrowOut = 1 + if UintSize == 32 { + d32, b32 := Sub32(uint32(x), uint32(y), uint32(borrow)) + return uint(d32), uint(b32) } - return + d64, b64 := Sub64(uint64(x), uint64(y), uint64(borrow)) + return uint(d64), uint(b64) } // Sub32 returns the difference of x, y and borrow, diff = x - y - borrow. // The borrow input must be 0 or 1; otherwise the behavior is undefined. // The borrowOut output is guaranteed to be 0 or 1. func Sub32(x, y, borrow uint32) (diff, borrowOut uint32) { - yb := y + borrow - diff = x - yb - if diff > x || yb < y { - borrowOut = 1 - } + diff = x - y - borrow + borrowOut = ((^x & y) | (^(x ^ y) & diff)) >> 31 return } @@ -394,11 +386,8 @@ func Sub32(x, y, borrow uint32) (diff, borrowOut uint32) { // The borrow input must be 0 or 1; otherwise the behavior is undefined. // The borrowOut output is guaranteed to be 0 or 1. func Sub64(x, y, borrow uint64) (diff, borrowOut uint64) { - yb := y + borrow - diff = x - yb - if diff > x || yb < y { - borrowOut = 1 - } + diff = x - y - borrow + borrowOut = ((^x & y) | (^(x ^ y) & diff)) >> 63 return } |