+/* --- These are all variations on a theme --- *
+ *
+ * Essentially we want to feed bits into a shift register, @ibits@ bits at a
+ * time, and extract them @obits@ bits at a time whenever there are enough.
+ * Of course, @i@ and @o@ will, in general, be different sizes, and we don't
+ * necessarily know which is larger.
+ *
+ * During an operation, we have a shift register @w@ and a most-recent input
+ * @t@. Together, these hold @bits@ significant bits of input. We arrange
+ * that @bits < ibits + obits <= 2*MPW_BITS@, so we can get away with using
+ * an @mpw@ for both of these quantitities.
+ */
+
+/* --- @MPX_GETBITS@ --- *
+ *
+ * Arguments: @ibits@ = width of input units, in bits
+ * @obits@ = width of output units, in bits
+ * @iavail@ = condition expression: is input data available?
+ * @getbits@ = function or macro: set argument to next input
+ *
+ * Use: Read an input unit into @t@ and update the necessary
+ * variables.
+ *
+ * It is assumed on entry that @bits < obits@. On exit, we have
+ * @bits < ibits + obits@, and @t@ is live.
+ */
+
+#define MPX_GETBITS(ibits, obits, iavail, getbits) do { \
+ if (!iavail) goto flush; \
+ if (bits >= ibits) w |= t << (bits - ibits); \
+ getbits(t); \
+ bits += ibits; \
+} while (0)
+
+/* --- @MPX_PUTBITS@ --- *
+ *
+ * Arguments: @ibits@ = width of input units, in bits
+ * @obits@ = width of output units, in bits
+ * @oavail@ = condition expression: is output space available?
+ * @putbits@ = function or macro: write its argument to output
+ *
+ * Use: Emit an output unit, and update the necessary variables. If
+ * the output buffer is full, then force an immediate return.
+ *
+ * We assume that @bits < ibits + obits@, and that @t@ is only
+ * relevant if @bits >= ibits@. (The @MPX_GETBITS@ macro
+ * ensures that this is true.)
+ */
+
+#define SHRW(w, b) ((b) < MPW_BITS ? (w) >> (b) : 0)
+
+#define MPX_PUTBITS(ibits, obits, oavail, putbits) do { \
+ if (!oavail) return; \
+ if (bits < ibits) { \
+ putbits(w); \
+ bits -= obits; \
+ w = SHRW(w, obits); \
+ } else { \
+ putbits(w | (t << (bits - ibits))); \
+ bits -= obits; \
+ if (bits >= ibits) w = SHRW(w, obits) | (t << (bits - ibits)); \
+ else w = SHRW(w, obits) | (t >> (ibits - bits)); \
+ t = 0; \
+ } \
+} while (0)
+
+/* --- @MPX_LOADSTORE@ --- *
+ *
+ * Arguments: @name@ = name of function to create, without @mpx_@ prefix
+ * @wconst@ = qualifiers for @mpw *@ arguments
+ * @oconst@ = qualifiers for octet pointers
+ * @decls@ = additional declarations needed
+ * @ibits@ = width of input units, in bits
+ * @iavail@ = condition expression: is input data available?
+ * @getbits@ = function or macro: set argument to next input
+ * @obits@ = width of output units, in bits
+ * @oavail@ = condition expression: is output space available?
+ * @putbits@ = function or macro: write its argument to output
+ * @clear@ = statements to clear remainder of output
+ *
+ * Use: Generates a function to convert between a sequence of
+ * multiprecision words and a vector of octets.
+ *
+ * The arguments @ibits@, @iavail@ and @getbits@ are passed on
+ * to @MPX_GETBITS@; similarly, @obits@, @oavail@, and @putbits@
+ * are passed on to @MPX_PUTBITS@.
+ *
+ * The following variables are in scope: @v@ and @vl are the
+ * current base and limit of the word vector; @p@ and @q@ are
+ * the base and limit of the octet vector; @w@ and @t@ form the
+ * shift register used during the conversion (see commentary
+ * above); and @bits@ tracks the number of live bits in the
+ * shift register.
+ */
+
+#define MPX_LOADSTORE(name, wconst, oconst, decls, \
+ ibits, iavail, getbits, obits, oavail, putbits, \
+ clear) \
+ \
+void mpx_##name(wconst mpw *v, wconst mpw *vl, \
+ oconst void *pp, size_t sz) \
+{ \
+ mpw t = 0, w = 0; \
+ oconst octet *p = pp, *q = p + sz; \
+ int bits = 0; \
+ decls \
+ \
+ for (;;) { \
+ while (bits < obits) MPX_GETBITS(ibits, obits, iavail, getbits); \
+ while (bits >= obits) MPX_PUTBITS(ibits, obits, oavail, putbits); \
+ } \
+ \
+flush: \
+ while (bits > 0) MPX_PUTBITS(ibits, obits, oavail, putbits); \
+ clear; \
+}
+
+#define EMPTY
+
+/* --- Macros for @getbits@ and @putbits@ --- */
+
+#define GETMPW(t) do { t = *v++; } while (0)
+#define PUTMPW(x) do { *v++ = MPW(x); } while (0)
+
+#define GETOCTETI(t) do { t = *p++; } while (0)
+#define PUTOCTETD(x) do { *--q = U8(x); } while (0)
+
+#define PUTOCTETI(x) do { *p++ = U8(x); } while (0)
+#define GETOCTETD(t) do { t = *--q; } while (0)
+
+/* --- Machinery for two's complement I/O --- */
+
+#define DECL_2CN \
+ unsigned c = 1;
+
+#define GETMPW_2CN(t) do { \
+ t = MPW(~*v++ + c); \
+ c = c && !t; \
+} while (0)
+
+#define PUTMPW_2CN(t) do { \
+ mpw _t = MPW(~(t) + c); \
+ c = c && !_t; \
+ *v++ = _t; \
+} while (0)
+
+#define FLUSHW_2CN do { \
+ if (c) MPX_ONE(v, vl); \
+ else MPX_ZERO(v, vl); \
+} while (0)
+
+#define FLUSHO_2CN do { \
+ memset(p, c ? 0xff : 0, q - p); \
+} while (0)
+