Skip to content

Commit 0100afb

Browse files
rui314nigeltao
authored andcommitted
image/png: use branch-free abs function
benchmark old ns/op new ns/op delta BenchmarkPaeth 5.06 6.02 +18.97% BenchmarkDecodeGray 1010551 956911 -5.31% BenchmarkDecodeNRGBAGradient 3877813 3754160 -3.19% BenchmarkDecodeNRGBAOpaque 3194058 3079094 -3.60% BenchmarkDecodePaletted 699243 700211 +0.14% BenchmarkDecodeRGB 2835733 2692120 -5.06% BenchmarkDecodeInterlacing 3651805 3563124 -2.43% BenchmarkEncodeGray 4399183 4404113 +0.11% BenchmarkEncodeNRGBOpaque 13323627 13306485 -0.13% BenchmarkEncodeNRGBA 15840092 15751188 -0.56% BenchmarkEncodePaletted 4396622 4404373 +0.18% BenchmarkEncodeRGBOpaque 13320475 13279189 -0.31% BenchmarkEncodeRGBA 36898392 36781002 -0.32% LGTM=nigeltao R=nigeltao CC=golang-codereviews https://golang.org/cl/117290043
1 parent d3fb02b commit 0100afb

File tree

2 files changed

+25
-24
lines changed

2 files changed

+25
-24
lines changed

src/pkg/image/png/paeth.go

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,21 @@
44

55
package png
66

7+
// intSize is either 32 or 64.
8+
const intSize = 32 << (^uint(0) >> 63)
9+
10+
func abs(x int) int {
11+
// m := -1 if x < 0. m := 0 otherwise.
12+
m := x >> (intSize - 1)
13+
14+
// In two's complement representation, the negative number
15+
// of any number (except the smallest one) can be computed
16+
// by flipping all the bits and add 1. This is faster than
17+
// code with a branch.
18+
// See Hacker's Delight, section 2-4.
19+
return (x ^ m) - m
20+
}
21+
722
// paeth implements the Paeth filter function, as per the PNG specification.
823
func paeth(a, b, c uint8) uint8 {
924
// This is an optimized version of the sample code in the PNG spec.
@@ -16,16 +31,9 @@ func paeth(a, b, c uint8) uint8 {
1631
pc := int(c)
1732
pa := int(b) - pc
1833
pb := int(a) - pc
19-
pc = pa + pb
20-
if pa < 0 {
21-
pa = -pa
22-
}
23-
if pb < 0 {
24-
pb = -pb
25-
}
26-
if pc < 0 {
27-
pc = -pc
28-
}
34+
pc = abs(pa + pb)
35+
pa = abs(pa)
36+
pb = abs(pb)
2937
if pa <= pb && pa <= pc {
3038
return a
3139
} else if pb <= pc {
@@ -44,16 +52,9 @@ func filterPaeth(cdat, pdat []byte, bytesPerPixel int) {
4452
b = int(pdat[j])
4553
pa = b - c
4654
pb = a - c
47-
pc = pa + pb
48-
if pa < 0 {
49-
pa = -pa
50-
}
51-
if pb < 0 {
52-
pb = -pb
53-
}
54-
if pc < 0 {
55-
pc = -pc
56-
}
55+
pc = abs(pa + pb)
56+
pa = abs(pa)
57+
pb = abs(pb)
5758
if pa <= pb && pa <= pc {
5859
// No-op.
5960
} else if pb <= pc {

src/pkg/image/png/paeth_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
"testing"
1111
)
1212

13-
func abs(x int) int {
13+
func slowAbs(x int) int {
1414
if x < 0 {
1515
return -x
1616
}
@@ -21,9 +21,9 @@ func abs(x int) int {
2121
// It is a straight port of the sample code in the PNG spec, section 9.4.
2222
func slowPaeth(a, b, c uint8) uint8 {
2323
p := int(a) + int(b) - int(c)
24-
pa := abs(p - int(a))
25-
pb := abs(p - int(b))
26-
pc := abs(p - int(c))
24+
pa := slowAbs(p - int(a))
25+
pb := slowAbs(p - int(b))
26+
pc := slowAbs(p - int(c))
2727
if pa <= pb && pa <= pc {
2828
return a
2929
} else if pb <= pc {

0 commit comments

Comments
 (0)