]> Cypherpunks repositories - gostls13.git/commitdiff
image/png: use branch-free abs function
authorRui Ueyama <ruiu@google.com>
Tue, 29 Jul 2014 04:29:14 +0000 (14:29 +1000)
committerNigel Tao <nigeltao@golang.org>
Tue, 29 Jul 2014 04:29:14 +0000 (14:29 +1000)
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

src/pkg/image/png/paeth.go
src/pkg/image/png/paeth_test.go

index 37978aa662d75befa9130f778874e71360eb7928..9ed6300c865470238eb82ed7efebf3ba5953a6ac 100644 (file)
@@ -4,6 +4,21 @@
 
 package png
 
+// intSize is either 32 or 64.
+const intSize = 32 << (^uint(0) >> 63)
+
+func abs(x int) int {
+       // m := -1 if x < 0. m := 0 otherwise.
+       m := x >> (intSize - 1)
+
+       // In two's complement representation, the negative number
+       // of any number (except the smallest one) can be computed
+       // by flipping all the bits and add 1. This is faster than
+       // code with a branch.
+       // See Hacker's Delight, section 2-4.
+       return (x ^ m) - m
+}
+
 // paeth implements the Paeth filter function, as per the PNG specification.
 func paeth(a, b, c uint8) uint8 {
        // This is an optimized version of the sample code in the PNG spec.
@@ -16,16 +31,9 @@ func paeth(a, b, c uint8) uint8 {
        pc := int(c)
        pa := int(b) - pc
        pb := int(a) - pc
-       pc = pa + pb
-       if pa < 0 {
-               pa = -pa
-       }
-       if pb < 0 {
-               pb = -pb
-       }
-       if pc < 0 {
-               pc = -pc
-       }
+       pc = abs(pa + pb)
+       pa = abs(pa)
+       pb = abs(pb)
        if pa <= pb && pa <= pc {
                return a
        } else if pb <= pc {
@@ -44,16 +52,9 @@ func filterPaeth(cdat, pdat []byte, bytesPerPixel int) {
                        b = int(pdat[j])
                        pa = b - c
                        pb = a - c
-                       pc = pa + pb
-                       if pa < 0 {
-                               pa = -pa
-                       }
-                       if pb < 0 {
-                               pb = -pb
-                       }
-                       if pc < 0 {
-                               pc = -pc
-                       }
+                       pc = abs(pa + pb)
+                       pa = abs(pa)
+                       pb = abs(pb)
                        if pa <= pb && pa <= pc {
                                // No-op.
                        } else if pb <= pc {
index bb084861ae96f0a5aa3d74bb4225f6b1b2a4fd8f..cfc1896cd7f2478f8fdd1ec90a0b46d282657bf8 100644 (file)
@@ -10,7 +10,7 @@ import (
        "testing"
 )
 
-func abs(x int) int {
+func slowAbs(x int) int {
        if x < 0 {
                return -x
        }
@@ -21,9 +21,9 @@ func abs(x int) int {
 // It is a straight port of the sample code in the PNG spec, section 9.4.
 func slowPaeth(a, b, c uint8) uint8 {
        p := int(a) + int(b) - int(c)
-       pa := abs(p - int(a))
-       pb := abs(p - int(b))
-       pc := abs(p - int(c))
+       pa := slowAbs(p - int(a))
+       pb := slowAbs(p - int(b))
+       pc := slowAbs(p - int(c))
        if pa <= pb && pa <= pc {
                return a
        } else if pb <= pc {