aboutsummaryrefslogtreecommitdiff
path: root/src/image
diff options
context:
space:
mode:
authorNigel Tao <nigeltao@golang.org>2026-03-05 19:10:23 +1100
committerNigel Tao <nigeltao@golang.org>2026-03-05 12:53:45 -0800
commit94a89c61e494a756aef63edb9890170a1ff45faf (patch)
tree5aab5145c94dbf4c78f34c38b8ce600cc52f29d2 /src/image
parent1a8f9d8141bd5682f38d2320c8e8df4ae5891000 (diff)
downloadgo-94a89c61e494a756aef63edb9890170a1ff45faf.tar.xz
image/jpeg: make decoder.receiveExtend branchless
On linux/amd64: name old speed new speed delta DecodeBaseline-8 76.4MB/s ± 0% 84.3MB/s ± 0% +10.38% (p=0.008 n=5+5) DecodeProgressive-8 51.0MB/s ± 1% 52.6MB/s ± 0% +3.20% (p=0.008 n=5+5) Thanks to David Le Corfec for the suggestion. Updates #24499 Change-Id: I749102ff0b50044dfd6a73172a1aa03f89ad97bd Reviewed-on: https://go-review.googlesource.com/c/go/+/750900 Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Reviewed-by: Nigel Tao <nigeltao@google.com>
Diffstat (limited to 'src/image')
-rw-r--r--src/image/jpeg/huffman.go25
1 files changed, 22 insertions, 3 deletions
diff --git a/src/image/jpeg/huffman.go b/src/image/jpeg/huffman.go
index 0b81fbae96..17a45fc614 100644
--- a/src/image/jpeg/huffman.go
+++ b/src/image/jpeg/huffman.go
@@ -70,6 +70,16 @@ func (d *decoder) ensureNBits(n int32) error {
// receiveExtend is the composition of RECEIVE and EXTEND, specified in section
// F.2.2.1.
+//
+// It returns the signed integer that's encoded in t bits, where t < 16. The
+// possible return values are:
+//
+// - t == 0: 0
+// - t == 1: -1, +1
+// - t == 2: -3, -2, +2, +3
+// - t == 3: -7, -6, -5, -4, +4, +5, +6, +7
+// - ...
+// - t == 15: -32767, -32766, ..., -16384, +16384, ..., +32766, +32767
func (d *decoder) receiveExtend(t uint8) (int32, error) {
if d.bits.n < int32(t) {
if err := d.ensureNBits(int32(t)); err != nil {
@@ -80,9 +90,18 @@ func (d *decoder) receiveExtend(t uint8) (int32, error) {
d.bits.m >>= t
s := int32(1) << t
x := int32(d.bits.a>>uint8(d.bits.n)) & (s - 1)
- if x < s>>1 {
- x += ((-1) << t) + 1
- }
+
+ // This adjustment, assuming two's complement, is a branchless equivalent of:
+ //
+ // if x < s>>1 {
+ // x += ((-1) << t) + 1
+ // }
+ //
+ // sign is either -1 or 0, depending on whether x is in the low or high
+ // half of the range 0 .. 1<<t.
+ sign := (x >> (t - 1)) - 1
+ x += sign & (((-1) << t) + 1)
+
return x, nil
}