Pull out duplicate short_read_src code.
name old speed new speed delta
lzw_puffs_decode_20k/clang 127MB/s ± 0% 127MB/s ± 0% +0.40% (p=0.008 n=5+5)
lzw_puffs_decode_100k/clang 176MB/s ± 0% 176MB/s ± 0% +0.23% (p=0.008 n=5+5)
gif_puffs_decode_1k/clang 380MB/s ± 1% 389MB/s ± 2% +2.26% (p=0.008 n=5+5)
gif_puffs_decode_10k/clang 136MB/s ± 0% 137MB/s ± 0% +0.59% (p=0.016 n=4+5)
gif_puffs_decode_100k/clang 121MB/s ± 0% 121MB/s ± 0% +0.33% (p=0.008 n=5+5)
gif_puffs_decode_1000k/clang 124MB/s ± 0% 124MB/s ± 0% +0.25% (p=0.008 n=5+5)
lzw_puffs_decode_20k/gcc 150MB/s ± 1% 151MB/s ± 0% +0.97% (p=0.008 n=5+5)
lzw_puffs_decode_100k/gcc 207MB/s ± 0% 197MB/s ± 0% -4.84% (p=0.008 n=5+5)
gif_puffs_decode_1k/gcc 413MB/s ± 1% 406MB/s ± 1% -1.71% (p=0.008 n=5+5)
gif_puffs_decode_10k/gcc 147MB/s ± 0% 158MB/s ± 0% +7.15% (p=0.008 n=5+5)
gif_puffs_decode_100k/gcc 136MB/s ± 0% 138MB/s ± 0% +1.68% (p=0.008 n=5+5)
gif_puffs_decode_1000k/gcc 139MB/s ± 0% 142MB/s ± 0% +2.07% (p=0.008 n=5+5)
diff --git a/cmd/puffs-gen-c/base-impl.h b/cmd/puffs-gen-c/base-impl.h
index a7a4ee0..d426dc4 100644
--- a/cmd/puffs-gen-c/base-impl.h
+++ b/cmd/puffs-gen-c/base-impl.h
@@ -17,4 +17,12 @@
#define PUFFS_LOW_BITS(x, n) ((x) & ((1 << (n)) - 1))
+#if defined(__clang__) || defined(__GNUC__)
+#define PUFFS_LIKELY(expr) (__builtin_expect((expr), 1))
+#define PUFFS_UNLIKELY(expr) (__builtin_expect((expr), 0))
+#else
+#define PUFFS_LIKELY(expr) (expr)
+#define PUFFS_UNLIKELY(expr) (expr)
+#endif
+
#endif // PUFFS_BASE_IMPL_H
diff --git a/cmd/puffs-gen-c/data.go b/cmd/puffs-gen-c/data.go
index 6e0ceaf..3f810bf 100644
--- a/cmd/puffs-gen-c/data.go
+++ b/cmd/puffs-gen-c/data.go
@@ -12,5 +12,5 @@
""
const baseImpl = "" +
- "#ifndef PUFFS_BASE_IMPL_H\n#define PUFFS_BASE_IMPL_H\n\n// Use of this source code is governed by a BSD-style license that can be found\n// in the LICENSE file.\n\n// Use switch cases for coroutine state, similar to the technique in\n// https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html\n//\n// We use a trivial macro instead of an explicit assignment and case statement\n// so that clang-format doesn't get confused by the unusual \"case\"s.\n#define PUFFS_COROUTINE_STATE(n) \\\n coro_state = n; \\\n case n:\n\n#define PUFFS_LOW_BITS(x, n) ((x) & ((1 << (n)) - 1))\n\n#endif // PUFFS_BASE_IMPL_H\n" +
+ "#ifndef PUFFS_BASE_IMPL_H\n#define PUFFS_BASE_IMPL_H\n\n// Use of this source code is governed by a BSD-style license that can be found\n// in the LICENSE file.\n\n// Use switch cases for coroutine state, similar to the technique in\n// https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html\n//\n// We use a trivial macro instead of an explicit assignment and case statement\n// so that clang-format doesn't get confused by the unusual \"case\"s.\n#define PUFFS_COROUTINE_STATE(n) \\\n coro_state = n; \\\n case n:\n\n#define PUFFS_LOW_BITS(x, n) ((x) & ((1 << (n)) - 1))\n\n#if defined(__clang__) || defined(__GNUC__)\n#define PUFFS_LIKELY(expr) (__builtin_expect((expr), 1))\n#define PUFFS_UNLIKELY(expr) (__builtin_expect((expr), 0))\n#else\n#define PUFFS_LIKELY(expr) (expr)\n#define PUFFS_UNLIKELY(expr) (expr)\n#endif\n\n#endif // PUFFS_BASE_IMPL_H\n" +
""
diff --git a/cmd/puffs-gen-c/func.go b/cmd/puffs-gen-c/func.go
index c480f18..7f8d864 100644
--- a/cmd/puffs-gen-c/func.go
+++ b/cmd/puffs-gen-c/func.go
@@ -22,6 +22,7 @@
public bool
suspendible bool
limitVarName string
+ shortReads []string
}
func (g *gen) writeFuncSignature(n *a.Func) error {
@@ -181,6 +182,17 @@
g.writes("self->private_impl.status = status;\n")
}
g.writes("return status;\n\n")
+
+ shortReadsSeen := map[string]struct{}{}
+ for _, sr := range g.perFunc.shortReads {
+ if _, ok := shortReadsSeen[sr]; ok {
+ continue
+ }
+ shortReadsSeen[sr] = struct{}{}
+ if err := g.writeShortRead(sr); err != nil {
+ return err
+ }
+ }
}
g.writes("}\n\n")
@@ -780,17 +792,8 @@
temp := g.perFunc.tempW
g.perFunc.tempW++
- g.printf("if (%srptr_src == %srend_src) {", bPrefix, bPrefix)
- // TODO: ri == wi isn't the right condition.
- g.printf("status = ((%ssrc.buf->closed) && (%ssrc.buf->ri == %ssrc.buf->wi)) ?"+
- "puffs_%s_error_unexpected_eof : puffs_%s_status_short_read;",
- aPrefix, aPrefix, aPrefix, g.pkgName, g.pkgName)
- if g.perFunc.public && g.perFunc.suspendible {
- g.writes("goto suspend;")
- } else {
- g.writes("return status;")
- }
- g.writes("}\n")
+ g.printf("if (PUFFS_UNLIKELY(%srptr_src == %srend_src)) { goto short_read_src; }", bPrefix, bPrefix)
+ g.perFunc.shortReads = append(g.perFunc.shortReads, "src")
// TODO: watch for passing an array type to writeCTypeName? In C, an
// array type can decay into a pointer.
if err := g.writeCTypeName(n.MType(), tPrefix, fmt.Sprint(temp)); err != nil {
@@ -919,6 +922,20 @@
return nil
}
+func (g *gen) writeShortRead(name string) error {
+ g.printf("\nshort_read_%s:\n", name)
+ // TODO: ri == wi isn't the right condition.
+ g.printf("status = ((%s%s.buf->closed) && (%s%s.buf->ri == %s%s.buf->wi)) ?"+
+ "puffs_%s_error_unexpected_eof : puffs_%s_status_short_read;",
+ aPrefix, name, aPrefix, name, aPrefix, name, g.pkgName, g.pkgName)
+ if g.perFunc.public && g.perFunc.suspendible { // TODO: drop the g.perFunc.public?
+ g.writes("goto suspend;")
+ } else {
+ g.writes("return status;")
+ }
+ return nil
+}
+
func (g *gen) writeExpr(n *a.Expr, rp replacementPolicy, pp parenthesesPolicy, depth uint32) error {
if depth > a.MaxExprDepth {
return fmt.Errorf("expression recursion depth too large")
diff --git a/gen/c/std/gif.c b/gen/c/std/gif.c
index 5476db0..87bc756 100644
--- a/gen/c/std/gif.c
+++ b/gen/c/std/gif.c
@@ -250,6 +250,14 @@
#define PUFFS_LOW_BITS(x, n) ((x) & ((1 << (n)) - 1))
+#if defined(__clang__) || defined(__GNUC__)
+#define PUFFS_LIKELY(expr) (__builtin_expect((expr), 1))
+#define PUFFS_UNLIKELY(expr) (__builtin_expect((expr), 0))
+#else
+#define PUFFS_LIKELY(expr) (expr)
+#define PUFFS_UNLIKELY(expr) (expr)
+#endif
+
#endif // PUFFS_BASE_IMPL_H
// ---------------- Status Codes Implementations
@@ -466,11 +474,8 @@
}
while (true) {
PUFFS_COROUTINE_STATE(3);
- if (b_rptr_src == b_rend_src) {
- status = ((a_src.buf->closed) && (a_src.buf->ri == a_src.buf->wi))
- ? puffs_gif_error_unexpected_eof
- : puffs_gif_status_short_read;
- goto suspend;
+ if (PUFFS_UNLIKELY(b_rptr_src == b_rend_src)) {
+ goto short_read_src;
}
uint8_t t_0 = *b_rptr_src++;
v_c = t_0;
@@ -559,6 +564,12 @@
exit:
self->private_impl.status = status;
return status;
+
+short_read_src:
+ status = ((a_src.buf->closed) && (a_src.buf->ri == a_src.buf->wi))
+ ? puffs_gif_error_unexpected_eof
+ : puffs_gif_status_short_read;
+ goto suspend;
}
puffs_gif_status puffs_gif_decoder_decode_header(puffs_gif_decoder* self,
@@ -599,11 +610,8 @@
v_i = 0;
while (v_i < 6) {
PUFFS_COROUTINE_STATE(1);
- if (b_rptr_src == b_rend_src) {
- status = ((a_src.buf->closed) && (a_src.buf->ri == a_src.buf->wi))
- ? puffs_gif_error_unexpected_eof
- : puffs_gif_status_short_read;
- return status;
+ if (PUFFS_UNLIKELY(b_rptr_src == b_rend_src)) {
+ goto short_read_src;
}
uint8_t t_0 = *b_rptr_src++;
v_c[v_i] = t_0;
@@ -636,6 +644,12 @@
goto exit;
exit:
return status;
+
+short_read_src:
+ status = ((a_src.buf->closed) && (a_src.buf->ri == a_src.buf->wi))
+ ? puffs_gif_error_unexpected_eof
+ : puffs_gif_status_short_read;
+ return status;
}
puffs_gif_status puffs_gif_decoder_decode_lsd(puffs_gif_decoder* self,
@@ -678,11 +692,8 @@
v_i = 0;
while (v_i < 7) {
PUFFS_COROUTINE_STATE(1);
- if (b_rptr_src == b_rend_src) {
- status = ((a_src.buf->closed) && (a_src.buf->ri == a_src.buf->wi))
- ? puffs_gif_error_unexpected_eof
- : puffs_gif_status_short_read;
- return status;
+ if (PUFFS_UNLIKELY(b_rptr_src == b_rend_src)) {
+ goto short_read_src;
}
uint8_t t_0 = *b_rptr_src++;
v_c[v_i] = t_0;
@@ -698,29 +709,20 @@
v_i = 0;
while (v_i < v_gct_size) {
PUFFS_COROUTINE_STATE(2);
- if (b_rptr_src == b_rend_src) {
- status = ((a_src.buf->closed) && (a_src.buf->ri == a_src.buf->wi))
- ? puffs_gif_error_unexpected_eof
- : puffs_gif_status_short_read;
- return status;
+ if (PUFFS_UNLIKELY(b_rptr_src == b_rend_src)) {
+ goto short_read_src;
}
uint8_t t_1 = *b_rptr_src++;
self->private_impl.f_gct[(3 * v_i) + 0] = t_1;
PUFFS_COROUTINE_STATE(3);
- if (b_rptr_src == b_rend_src) {
- status = ((a_src.buf->closed) && (a_src.buf->ri == a_src.buf->wi))
- ? puffs_gif_error_unexpected_eof
- : puffs_gif_status_short_read;
- return status;
+ if (PUFFS_UNLIKELY(b_rptr_src == b_rend_src)) {
+ goto short_read_src;
}
uint8_t t_2 = *b_rptr_src++;
self->private_impl.f_gct[(3 * v_i) + 1] = t_2;
PUFFS_COROUTINE_STATE(4);
- if (b_rptr_src == b_rend_src) {
- status = ((a_src.buf->closed) && (a_src.buf->ri == a_src.buf->wi))
- ? puffs_gif_error_unexpected_eof
- : puffs_gif_status_short_read;
- return status;
+ if (PUFFS_UNLIKELY(b_rptr_src == b_rend_src)) {
+ goto short_read_src;
}
uint8_t t_3 = *b_rptr_src++;
self->private_impl.f_gct[(3 * v_i) + 2] = t_3;
@@ -751,6 +753,12 @@
goto exit;
exit:
return status;
+
+short_read_src:
+ status = ((a_src.buf->closed) && (a_src.buf->ri == a_src.buf->wi))
+ ? puffs_gif_error_unexpected_eof
+ : puffs_gif_status_short_read;
+ return status;
}
puffs_gif_status puffs_gif_decoder_decode_extension(puffs_gif_decoder* self,
@@ -783,11 +791,8 @@
PUFFS_COROUTINE_STATE(0);
PUFFS_COROUTINE_STATE(1);
- if (b_rptr_src == b_rend_src) {
- status = ((a_src.buf->closed) && (a_src.buf->ri == a_src.buf->wi))
- ? puffs_gif_error_unexpected_eof
- : puffs_gif_status_short_read;
- return status;
+ if (PUFFS_UNLIKELY(b_rptr_src == b_rend_src)) {
+ goto short_read_src;
}
uint8_t t_0 = *b_rptr_src++;
v_label = t_0;
@@ -800,11 +805,8 @@
}
while (true) {
PUFFS_COROUTINE_STATE(2);
- if (b_rptr_src == b_rend_src) {
- status = ((a_src.buf->closed) && (a_src.buf->ri == a_src.buf->wi))
- ? puffs_gif_error_unexpected_eof
- : puffs_gif_status_short_read;
- return status;
+ if (PUFFS_UNLIKELY(b_rptr_src == b_rend_src)) {
+ goto short_read_src;
}
uint8_t t_1 = *b_rptr_src++;
v_block_size = t_1;
@@ -846,6 +848,12 @@
goto exit;
exit:
return status;
+
+short_read_src:
+ status = ((a_src.buf->closed) && (a_src.buf->ri == a_src.buf->wi))
+ ? puffs_gif_error_unexpected_eof
+ : puffs_gif_status_short_read;
+ return status;
}
puffs_gif_status puffs_gif_decoder_decode_id(puffs_gif_decoder* self,
@@ -897,11 +905,8 @@
v_i = 0;
while (v_i < 9) {
PUFFS_COROUTINE_STATE(1);
- if (b_rptr_src == b_rend_src) {
- status = ((a_src.buf->closed) && (a_src.buf->ri == a_src.buf->wi))
- ? puffs_gif_error_unexpected_eof
- : puffs_gif_status_short_read;
- return status;
+ if (PUFFS_UNLIKELY(b_rptr_src == b_rend_src)) {
+ goto short_read_src;
}
uint8_t t_0 = *b_rptr_src++;
v_c[v_i] = t_0;
@@ -914,11 +919,8 @@
return puffs_gif_error_todo_unsupported_local_color_table;
}
PUFFS_COROUTINE_STATE(2);
- if (b_rptr_src == b_rend_src) {
- status = ((a_src.buf->closed) && (a_src.buf->ri == a_src.buf->wi))
- ? puffs_gif_error_unexpected_eof
- : puffs_gif_status_short_read;
- return status;
+ if (PUFFS_UNLIKELY(b_rptr_src == b_rend_src)) {
+ goto short_read_src;
}
uint8_t t_1 = *b_rptr_src++;
v_lw = t_1;
@@ -929,11 +931,8 @@
((uint32_t)(v_lw)));
while (true) {
PUFFS_COROUTINE_STATE(3);
- if (b_rptr_src == b_rend_src) {
- status = ((a_src.buf->closed) && (a_src.buf->ri == a_src.buf->wi))
- ? puffs_gif_error_unexpected_eof
- : puffs_gif_status_short_read;
- return status;
+ if (PUFFS_UNLIKELY(b_rptr_src == b_rend_src)) {
+ goto short_read_src;
}
uint8_t t_2 = *b_rptr_src++;
v_block_size = t_2;
@@ -1003,6 +1002,12 @@
goto exit;
exit:
return status;
+
+short_read_src:
+ status = ((a_src.buf->closed) && (a_src.buf->ri == a_src.buf->wi))
+ ? puffs_gif_error_unexpected_eof
+ : puffs_gif_status_short_read;
+ return status;
}
void puffs_gif_lzw_decoder_set_literal_width(puffs_gif_lzw_decoder* self,
@@ -1105,11 +1110,8 @@
while (true) {
while (v_n_bits < v_width) {
PUFFS_COROUTINE_STATE(1);
- if (b_rptr_src == b_rend_src) {
- status = ((a_src.buf->closed) && (a_src.buf->ri == a_src.buf->wi))
- ? puffs_gif_error_unexpected_eof
- : puffs_gif_status_short_read;
- goto suspend;
+ if (PUFFS_UNLIKELY(b_rptr_src == b_rend_src)) {
+ goto short_read_src;
}
uint8_t t_0 = *b_rptr_src++;
v_bits |= (((uint32_t)(t_0)) << v_n_bits);
@@ -1230,4 +1232,10 @@
exit:
self->private_impl.status = status;
return status;
+
+short_read_src:
+ status = ((a_src.buf->closed) && (a_src.buf->ri == a_src.buf->wi))
+ ? puffs_gif_error_unexpected_eof
+ : puffs_gif_status_short_read;
+ goto suspend;
}