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;
 }