From b26ba6f760ad31149d7ef67c672d498595c61ac3 Mon Sep 17 00:00:00 2001 From: Nathan VanBenschoten Date: Sun, 16 Jan 2022 04:39:18 -0500 Subject: [PATCH 1/2] apd: short-circuit in Context.goError This commit adds a fast-path for the common case in `Context.goError` that avoids the function call to `Condition.GoError`. `Context.goError` is inlined in callers, so this avoids any function call in the common case. The commit also adds two addtional `gcassert:inline` directives. --- bigint.go | 1 + context.go | 3 +++ table.go | 1 + 3 files changed, 5 insertions(+) diff --git a/bigint.go b/bigint.go index 0d5737d..c50bb85 100644 --- a/bigint.go +++ b/bigint.go @@ -73,6 +73,7 @@ func NewBigInt(x int64) *BigInt { var negSentinel = new(big.Int) // isInline returns whether the BigInt stores its value in its _inline array. +//gcassert:inline func (z *BigInt) isInline() bool { return z._inner == nil || z._inner == negSentinel } diff --git a/context.go b/context.go index e84d330..260e092 100644 --- a/context.go +++ b/context.go @@ -81,6 +81,9 @@ func (c *Context) WithPrecision(p uint32) *Context { // goError converts flags into an error based on c.Traps. //gcassert:inline func (c *Context) goError(flags Condition) (Condition, error) { + if flags == 0 { + return flags, nil + } return flags.GoError(c.Traps) } diff --git a/table.go b/table.go index 9abee51..d23dbd7 100644 --- a/table.go +++ b/table.go @@ -52,6 +52,7 @@ func init() { } // NumDigits returns the number of decimal digits of d.Coeff. +//gcassert:inline func (d *Decimal) NumDigits() int64 { return NumDigits(&d.Coeff) } From c93277404fb42b7d41d565f01ebedfcf164d3876 Mon Sep 17 00:00:00 2001 From: Nathan VanBenschoten Date: Sun, 16 Jan 2022 04:59:49 -0500 Subject: [PATCH 2/2] apd: inline Context.round This commit reworks the call to `Context.round` to allow for mid-stack function inlining. To do this, we remove the conditional call to one of two functions, which is considered too complex to inline. --- context.go | 4 ++-- round.go | 15 ++++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/context.go b/context.go index 260e092..0d3125d 100644 --- a/context.go +++ b/context.go @@ -1220,8 +1220,8 @@ func (c *Context) quantize(d, v *Decimal, exp int32) Condition { // target eliminates this problem. d.Exponent = -diff - // Avoid the c.Precision == 0 check. - res = nc.Rounding.Round(nc, d, d) + // Round even if nc.Precision == 0. + res = nc.Rounding.Round(nc, d, d, false /* disableIfPrecisionZero */) // Adjust for 0.9 -> 1.0 rollover. if d.Exponent > 0 { d.Coeff.Mul(&d.Coeff, bigTen) diff --git a/round.go b/round.go index 92998c5..c9741a6 100644 --- a/round.go +++ b/round.go @@ -21,13 +21,9 @@ func (c *Context) Round(d, x *Decimal) (Condition, error) { return c.goError(c.round(d, x)) } +//gcassert:inline func (c *Context) round(d, x *Decimal) Condition { - if c.Precision == 0 { - d.Set(x) - return d.setExponent(c, unknownNumDigits, 0, int64(d.Exponent)) - } - res := c.Rounding.Round(c, d, x) - return res + return c.Rounding.Round(c, d, x, true /* disableIfPrecisionZero */) } // Rounder specifies the behavior of rounding. @@ -63,12 +59,17 @@ func (r Rounder) ShouldAddOne(result *BigInt, neg bool, half int) bool { } // Round sets d to rounded x. -func (r Rounder) Round(c *Context, d, x *Decimal) Condition { +func (r Rounder) Round(c *Context, d, x *Decimal, disableIfPrecisionZero bool) Condition { d.Set(x) nd := x.NumDigits() xs := x.Sign() var res Condition + if disableIfPrecisionZero && c.Precision == 0 { + // Rounding has been disabled. + return d.setExponent(c, nd, res, int64(d.Exponent)) + } + // adj is the adjusted exponent: exponent + clength - 1 if adj := int64(x.Exponent) + nd - 1; xs != 0 && adj < int64(c.MinExponent) { // Subnormal is defined before rounding.