1d8a5b
diff --git a/Makefile.am b/Makefile.am
1d8a5b
index 025c914..8b4120c 100644
1d8a5b
--- a/Makefile.am
1d8a5b
+++ b/Makefile.am
1d8a5b
@@ -55,6 +55,9 @@ gzip_SOURCES = \
1d8a5b
   trees.c unlzh.c unlzw.c unpack.c unzip.c util.c zip.c
1d8a5b
 gzip_LDADD = libver.a lib/libgzip.a
1d8a5b
 gzip_LDADD += $(LIB_CLOCK_GETTIME)
1d8a5b
+if IBM_Z_DFLTCC
1d8a5b
+gzip_SOURCES += dfltcc.c
1d8a5b
+endif
1d8a5b
 
1d8a5b
 BUILT_SOURCES += version.c
1d8a5b
 version.c: Makefile
1d8a5b
diff --git a/bits.c b/bits.c
1d8a5b
index b0df2fe..9effc32 100644
1d8a5b
--- a/bits.c
1d8a5b
+++ b/bits.c
1d8a5b
@@ -78,7 +78,7 @@
1d8a5b
 
1d8a5b
 local file_t zfile; /* output gzip file */
1d8a5b
 
1d8a5b
-local unsigned short bi_buf;
1d8a5b
+unsigned short bi_buf;
1d8a5b
 /* Output buffer. bits are inserted starting at the bottom (least significant
1d8a5b
  * bits).
1d8a5b
  */
1d8a5b
@@ -88,7 +88,7 @@ local unsigned short bi_buf;
1d8a5b
  * more than 16 bits on some systems.)
1d8a5b
  */
1d8a5b
 
1d8a5b
-local int bi_valid;
1d8a5b
+int bi_valid;
1d8a5b
 /* Number of valid bits in bi_buf.  All bits above the last valid bit
1d8a5b
  * are always zero.
1d8a5b
  */
1d8a5b
diff --git a/configure.ac b/configure.ac
1d8a5b
index 9a2b635..76ac26f 100644
1d8a5b
--- a/configure.ac
1d8a5b
+++ b/configure.ac
1d8a5b
@@ -78,6 +78,16 @@ AC_ARG_ENABLE([gcc-warnings],
1d8a5b
    fi]
1d8a5b
 )
1d8a5b
 
1d8a5b
+AC_ARG_ENABLE([dfltcc],
1d8a5b
+  [AS_HELP_STRING([--enable-dfltcc],
1d8a5b
+     [use DEFLATE COMPRESSION CALL instruction on IBM Z])],
1d8a5b
+  [case $enableval in
1d8a5b
+     yes|no) gl_dfltcc=$enableval ;;
1d8a5b
+     *)      AC_MSG_ERROR([bad value $enableval for dfltcc option]) ;;
1d8a5b
+   esac],
1d8a5b
+  [gl_dfltcc=no]
1d8a5b
+)
1d8a5b
+
1d8a5b
 # gl_GCC_VERSION_IFELSE([major], [minor], [run-if-found], [run-if-not-found])
1d8a5b
 # ------------------------------------------------
1d8a5b
 # If $CPP is gcc-MAJOR.MINOR or newer, then run RUN-IF-FOUND.
1d8a5b
@@ -188,6 +198,12 @@ if test "$gl_gcc_warnings" = yes; then
1d8a5b
   AC_SUBST([GNULIB_WARN_CFLAGS])
1d8a5b
 fi
1d8a5b
 
1d8a5b
+if test "$gl_dfltcc" = yes; then
1d8a5b
+  AC_DEFINE([IBM_Z_DFLTCC], ,
1d8a5b
+    [Use DEFLATE COMPRESSION CALL instruction on IBM Z machines.])
1d8a5b
+fi
1d8a5b
+AM_CONDITIONAL([IBM_Z_DFLTCC],  [test "$gl_dfltcc" = yes])
1d8a5b
+
1d8a5b
 # cc -E produces incorrect asm files on SVR4, so postprocess it.
1d8a5b
 ASCPPPOST="sed '/^ *\\#/d; s,//.*,,; s/% /%/g; s/\\. /./g'"
1d8a5b
 AC_SUBST([ASCPPPOST])
1d8a5b
diff --git a/deflate.c b/deflate.c
1d8a5b
index 8ffff3a..869b902 100644
1d8a5b
--- a/deflate.c
1d8a5b
+++ b/deflate.c
1d8a5b
@@ -123,10 +123,6 @@
1d8a5b
 #define NIL 0
1d8a5b
 /* Tail of hash chains */
1d8a5b
 
1d8a5b
-#define FAST 4
1d8a5b
-#define SLOW 2
1d8a5b
-/* speed options for the general purpose bit flag */
1d8a5b
-
1d8a5b
 #ifndef TOO_FAR
1d8a5b
 #  define TOO_FAR 4096
1d8a5b
 #endif
1d8a5b
@@ -215,9 +211,6 @@ local unsigned int max_lazy_match;
1d8a5b
  * max_insert_length is used only for compression levels <= 3.
1d8a5b
  */
1d8a5b
 
1d8a5b
-local int compr_level;
1d8a5b
-/* compression level (1..9) */
1d8a5b
-
1d8a5b
 unsigned good_match;
1d8a5b
 /* Use a faster search when the previous match is longer than this */
1d8a5b
 
1d8a5b
@@ -308,14 +301,12 @@ local  void check_match (IPos start, IPos match, int length);
1d8a5b
 /* ===========================================================================
1d8a5b
  * Initialize the "longest match" routines for a new file
1d8a5b
  */
1d8a5b
-void lm_init (pack_level, flags)
1d8a5b
+void lm_init (pack_level)
1d8a5b
     int pack_level; /* 0: store, 1: best speed, 9: best compression */
1d8a5b
-    ush *flags;     /* general purpose bit flag */
1d8a5b
 {
1d8a5b
     register unsigned j;
1d8a5b
 
1d8a5b
     if (pack_level < 1 || pack_level > 9) gzip_error ("bad pack level");
1d8a5b
-    compr_level = pack_level;
1d8a5b
 
1d8a5b
     /* Initialize the hash table. */
1d8a5b
 #if defined MAXSEG_64K && HASH_BITS == 15
1d8a5b
@@ -337,11 +328,6 @@ void lm_init (pack_level, flags)
1d8a5b
     nice_match       = configuration_table[pack_level].nice_length;
1d8a5b
 #endif
1d8a5b
     max_chain_length = configuration_table[pack_level].max_chain;
1d8a5b
-    if (pack_level == 1) {
1d8a5b
-       *flags |= FAST;
1d8a5b
-    } else if (pack_level == 9) {
1d8a5b
-       *flags |= SLOW;
1d8a5b
-    }
1d8a5b
     /* ??? reduce max_chain_length for binary files */
1d8a5b
 
1d8a5b
     strstart = 0;
1d8a5b
@@ -732,7 +718,7 @@ local off_t deflate_fast()
1d8a5b
  * evaluation for matches: a match is finally adopted only if there is
1d8a5b
  * no better match at the next window position.
1d8a5b
  */
1d8a5b
-off_t deflate()
1d8a5b
+off_t deflate(int pack_level)
1d8a5b
 {
1d8a5b
     IPos hash_head;          /* head of hash chain */
1d8a5b
     IPos prev_match;         /* previous match */
1d8a5b
@@ -740,7 +726,8 @@ off_t deflate()
1d8a5b
     int match_available = 0; /* set if previous match exists */
1d8a5b
     register unsigned match_length = MIN_MATCH-1; /* length of best match */
1d8a5b
 
1d8a5b
-    if (compr_level <= 3) return deflate_fast(); /* optimized for speed */
1d8a5b
+    lm_init(pack_level);
1d8a5b
+    if (pack_level <= 3) return deflate_fast(); /* optimized for speed */
1d8a5b
 
1d8a5b
     /* Process the input block. */
1d8a5b
     while (lookahead != 0) {
1d8a5b
diff --git a/dfltcc.c b/dfltcc.c
1d8a5b
new file mode 100644
1d8a5b
index 0000000..9010475
1d8a5b
--- /dev/null
1d8a5b
+++ b/dfltcc.c
1d8a5b
@@ -0,0 +1,429 @@
1d8a5b
+/* dfltcc.c -- compress data using IBM Z DEFLATE COMPRESSION CALL
1d8a5b
+
1d8a5b
+   Copyright (C) 2019 Free Software Foundation, Inc.
1d8a5b
+
1d8a5b
+   This program is free software; you can redistribute it and/or modify
1d8a5b
+   it under the terms of the GNU General Public License as published by
1d8a5b
+   the Free Software Foundation; either version 3, or (at your option)
1d8a5b
+   any later version.
1d8a5b
+
1d8a5b
+   This program is distributed in the hope that it will be useful,
1d8a5b
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
1d8a5b
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1d8a5b
+   GNU General Public License for more details.
1d8a5b
+
1d8a5b
+   You should have received a copy of the GNU General Public License
1d8a5b
+   along with this program; if not, write to the Free Software Foundation,
1d8a5b
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
1d8a5b
+
1d8a5b
+#include <config.h>
1d8a5b
+#include <stdlib.h>
1d8a5b
+#ifdef DFLTCC_USDT
1d8a5b
+#include <sys/sdt.h>
1d8a5b
+#endif
1d8a5b
+
1d8a5b
+#include "tailor.h"
1d8a5b
+#include "gzip.h"
1d8a5b
+
1d8a5b
+#ifdef DYN_ALLOC
1d8a5b
+    error: DYN_ALLOC is not supported by DFLTCC
1d8a5b
+#endif
1d8a5b
+
1d8a5b
+/* ===========================================================================
1d8a5b
+ * C wrappers for the DEFLATE CONVERSION CALL instruction.
1d8a5b
+ */
1d8a5b
+
1d8a5b
+typedef enum
1d8a5b
+{
1d8a5b
+    DFLTCC_CC_OK = 0,
1d8a5b
+    DFLTCC_CC_OP1_TOO_SHORT = 1,
1d8a5b
+    DFLTCC_CC_OP2_TOO_SHORT = 2,
1d8a5b
+    DFLTCC_CC_OP2_CORRUPT = 2,
1d8a5b
+    DFLTCC_CC_AGAIN = 3,
1d8a5b
+} dfltcc_cc;
1d8a5b
+
1d8a5b
+#define DFLTCC_QAF 0
1d8a5b
+#define DFLTCC_GDHT 1
1d8a5b
+#define DFLTCC_CMPR 2
1d8a5b
+#define DFLTCC_XPND 4
1d8a5b
+#define HBT_CIRCULAR (1 << 7)
1d8a5b
+//#define HB_BITS 15
1d8a5b
+//#define HB_SIZE (1 << HB_BITS)
1d8a5b
+#define DFLTCC_FACILITY 151
1d8a5b
+#define DFLTCC_FMT0 0
1d8a5b
+#define CVT_CRC32 0
1d8a5b
+#define HTT_FIXED 0
1d8a5b
+#define HTT_DYNAMIC 1
1d8a5b
+
1d8a5b
+struct dfltcc_qaf_param
1d8a5b
+{
1d8a5b
+    char fns[16];
1d8a5b
+    char reserved1[8];
1d8a5b
+    char fmts[2];
1d8a5b
+    char reserved2[6];
1d8a5b
+};
1d8a5b
+
1d8a5b
+struct dfltcc_param_v0
1d8a5b
+{
1d8a5b
+    unsigned short pbvn;               /* Parameter-Block-Version Number */
1d8a5b
+    unsigned char mvn;                 /* Model-Version Number */
1d8a5b
+    unsigned char ribm;                /* Reserved for IBM use */
1d8a5b
+    unsigned reserved32 : 31;
1d8a5b
+    unsigned cf : 1;                   /* Continuation Flag */
1d8a5b
+    unsigned char reserved64[8];
1d8a5b
+    unsigned nt : 1;                   /* New Task */
1d8a5b
+    unsigned reserved129 : 1;
1d8a5b
+    unsigned cvt : 1;                  /* Check Value Type */
1d8a5b
+    unsigned reserved131 : 1;
1d8a5b
+    unsigned htt : 1;                  /* Huffman-Table Type */
1d8a5b
+    unsigned bcf : 1;                  /* Block-Continuation Flag */
1d8a5b
+    unsigned bcc : 1;                  /* Block Closing Control */
1d8a5b
+    unsigned bhf : 1;                  /* Block Header Final */
1d8a5b
+    unsigned reserved136 : 1;
1d8a5b
+    unsigned reserved137 : 1;
1d8a5b
+    unsigned dhtgc : 1;                /* DHT Generation Control */
1d8a5b
+    unsigned reserved139 : 5;
1d8a5b
+    unsigned reserved144 : 5;
1d8a5b
+    unsigned sbb : 3;                  /* Sub-Byte Boundary */
1d8a5b
+    unsigned char oesc;                /* Operation-Ending-Supplemental Code */
1d8a5b
+    unsigned reserved160 : 12;
1d8a5b
+    unsigned ifs : 4;                  /* Incomplete-Function Status */
1d8a5b
+    unsigned short ifl;                /* Incomplete-Function Length */
1d8a5b
+    unsigned char reserved192[8];
1d8a5b
+    unsigned char reserved256[8];
1d8a5b
+    unsigned char reserved320[4];
1d8a5b
+    unsigned short hl;                 /* History Length */
1d8a5b
+    unsigned reserved368 : 1;
1d8a5b
+    unsigned short ho : 15;            /* History Offset */
1d8a5b
+    unsigned int cv;                   /* Check Value */
1d8a5b
+    unsigned eobs : 15;                /* End-of-block Symbol */
1d8a5b
+    unsigned reserved431 : 1;
1d8a5b
+    unsigned char eobl : 4;            /* End-of-block Length */
1d8a5b
+    unsigned reserved436 : 12;
1d8a5b
+    unsigned reserved448 : 4;
1d8a5b
+    unsigned short cdhtl : 12;         /* Compressed-Dynamic-Huffman Table
1d8a5b
+                                          Length */
1d8a5b
+    unsigned char reserved464[6];
1d8a5b
+    unsigned char cdht[288];
1d8a5b
+    unsigned char reserved[32];
1d8a5b
+    unsigned char csb[1152];
1d8a5b
+};
1d8a5b
+
1d8a5b
+static int is_bit_set(const char *bits, int n)
1d8a5b
+{
1d8a5b
+    return bits[n / 8] & (1 << (7 - (n % 8)));
1d8a5b
+}
1d8a5b
+
1d8a5b
+static int is_dfltcc_enabled(void)
1d8a5b
+{
1d8a5b
+    const char *env;
1d8a5b
+    char facilities[((DFLTCC_FACILITY / 64) + 1) * 8];
1d8a5b
+    register int r0 __asm__("r0");
1d8a5b
+
1d8a5b
+    env = getenv("DFLTCC");
1d8a5b
+    if (env && !strcmp(env, "0")) {
1d8a5b
+        return 0;
1d8a5b
+    }
1d8a5b
+
1d8a5b
+    r0 = sizeof(facilities) / 8;
1d8a5b
+    __asm__("stfle %[facilities]\n"
1d8a5b
+            : [facilities] "=Q"(facilities) : [r0] "r"(r0) : "cc", "memory");
1d8a5b
+    return is_bit_set((const char *) facilities, DFLTCC_FACILITY);
1d8a5b
+}
1d8a5b
+
1d8a5b
+static dfltcc_cc dfltcc(int fn, void *param,
1d8a5b
+                        uch **op1, size_t *len1,
1d8a5b
+                        const uch **op2, size_t *len2,
1d8a5b
+                        void *hist)
1d8a5b
+{
1d8a5b
+    uch *t2 = op1 ? *op1 : NULL;
1d8a5b
+    size_t t3 = len1 ? *len1 : 0;
1d8a5b
+    const uch *t4 = op2 ? *op2 : NULL;
1d8a5b
+    size_t t5 = len2 ? *len2 : 0;
1d8a5b
+    register int r0 __asm__("r0") = fn;
1d8a5b
+    register void *r1 __asm__("r1") = param;
1d8a5b
+    register uch *r2 __asm__("r2") = t2;
1d8a5b
+    register size_t r3 __asm__("r3") = t3;
1d8a5b
+    register const uch *r4 __asm__("r4") = t4;
1d8a5b
+    register size_t r5 __asm__("r5") = t5;
1d8a5b
+    int cc;
1d8a5b
+
1d8a5b
+    __asm__ volatile(
1d8a5b
+#ifdef DFLTCC_USDT
1d8a5b
+                     STAP_PROBE_ASM(zlib, dfltcc_entry,
1d8a5b
+                                    STAP_PROBE_ASM_TEMPLATE(5))
1d8a5b
+#endif
1d8a5b
+                     ".insn rrf,0xb9390000,%[r2],%[r4],%[hist],0\n"
1d8a5b
+#ifdef DFLTCC_USDT
1d8a5b
+                     STAP_PROBE_ASM(zlib, dfltcc_exit,
1d8a5b
+                                    STAP_PROBE_ASM_TEMPLATE(5))
1d8a5b
+#endif
1d8a5b
+                     "ipm %[cc]\n"
1d8a5b
+                     : [r2] "+r" (r2)
1d8a5b
+                     , [r3] "+r" (r3)
1d8a5b
+                     , [r4] "+r" (r4)
1d8a5b
+                     , [r5] "+r" (r5)
1d8a5b
+                     , [cc] "=r" (cc)
1d8a5b
+                     : [r0] "r" (r0)
1d8a5b
+                     , [r1] "r" (r1)
1d8a5b
+                     , [hist] "r" (hist)
1d8a5b
+#ifdef DFLTCC_USDT
1d8a5b
+                     , STAP_PROBE_ASM_OPERANDS(5, r2, r3, r4, r5, hist)
1d8a5b
+#endif
1d8a5b
+                     : "cc", "memory");
1d8a5b
+    t2 = r2; t3 = r3; t4 = r4; t5 = r5;
1d8a5b
+
1d8a5b
+    if (op1)
1d8a5b
+        *op1 = t2;
1d8a5b
+    if (len1)
1d8a5b
+        *len1 = t3;
1d8a5b
+    if (op2)
1d8a5b
+        *op2 = t4;
1d8a5b
+    if (len2)
1d8a5b
+        *len2 = t5;
1d8a5b
+    return (cc >> 28) & 3;
1d8a5b
+}
1d8a5b
+
1d8a5b
+static void dfltcc_qaf(struct dfltcc_qaf_param *param)
1d8a5b
+{
1d8a5b
+    dfltcc(DFLTCC_QAF, param, NULL, NULL, NULL, NULL, NULL);
1d8a5b
+}
1d8a5b
+
1d8a5b
+static void dfltcc_gdht(struct dfltcc_param_v0 *param)
1d8a5b
+{
1d8a5b
+    const uch *next_in = inbuf + inptr;
1d8a5b
+    size_t avail_in = insize - inptr;
1d8a5b
+
1d8a5b
+    dfltcc(DFLTCC_GDHT, param, NULL, NULL, &next_in, &avail_in, NULL);
1d8a5b
+}
1d8a5b
+
1d8a5b
+static off_t total_in;
1d8a5b
+
1d8a5b
+static dfltcc_cc dfltcc_cmpr_xpnd(struct dfltcc_param_v0 *param, int fn)
1d8a5b
+{
1d8a5b
+    uch *next_out = outbuf + outcnt;
1d8a5b
+    size_t avail_out = OUTBUFSIZ - outcnt;
1d8a5b
+    const uch *next_in = inbuf + inptr;
1d8a5b
+    size_t avail_in = insize - inptr;
1d8a5b
+    off_t consumed_in;
1d8a5b
+    dfltcc_cc cc;
1d8a5b
+
1d8a5b
+    cc = dfltcc(fn | HBT_CIRCULAR, param,
1d8a5b
+                &next_out, &avail_out,
1d8a5b
+                &next_in, &avail_in,
1d8a5b
+                window);
1d8a5b
+    consumed_in = next_in - (inbuf + inptr);
1d8a5b
+    inptr += consumed_in;
1d8a5b
+    total_in += consumed_in;
1d8a5b
+    outcnt += ((OUTBUFSIZ - outcnt) - avail_out);
1d8a5b
+    return cc;
1d8a5b
+}
1d8a5b
+
1d8a5b
+__attribute__((aligned(8)))
1d8a5b
+static struct context
1d8a5b
+{
1d8a5b
+    union
1d8a5b
+    {
1d8a5b
+        struct dfltcc_qaf_param af;
1d8a5b
+        struct dfltcc_param_v0 param;
1d8a5b
+    };
1d8a5b
+} ctx;
1d8a5b
+
1d8a5b
+static struct dfltcc_param_v0 *init_param(struct dfltcc_param_v0 *param)
1d8a5b
+{
1d8a5b
+    const char *s;
1d8a5b
+
1d8a5b
+    memset(param, 0, sizeof(*param));
1d8a5b
+#ifndef DFLTCC_RIBM
1d8a5b
+#define DFLTCC_RIBM 0
1d8a5b
+#endif
1d8a5b
+    s = getenv("DFLTCC_RIBM");
1d8a5b
+    param->ribm = (s && *s) ? strtoul(s, NULL, 0) : DFLTCC_RIBM;
1d8a5b
+    param->nt = 1;
1d8a5b
+    param->cvt = CVT_CRC32;
1d8a5b
+    param->cv = __builtin_bswap32(getcrc());
1d8a5b
+    return param;
1d8a5b
+}
1d8a5b
+
1d8a5b
+static void bi_close_block(struct dfltcc_param_v0 *param)
1d8a5b
+{
1d8a5b
+    bi_valid = param->sbb;
1d8a5b
+    bi_buf = bi_valid == 0 ? 0 : outbuf[outcnt] & ((1 << bi_valid) - 1);
1d8a5b
+    send_bits(
1d8a5b
+        bi_reverse(param->eobs >> (15 - param->eobl), param->eobl),
1d8a5b
+        param->eobl);
1d8a5b
+    param->bcf = 0;
1d8a5b
+}
1d8a5b
+
1d8a5b
+static void close_block(struct dfltcc_param_v0 *param)
1d8a5b
+{
1d8a5b
+    bi_close_block(param);
1d8a5b
+    bi_windup();
1d8a5b
+    param->sbb = (param->sbb + param->eobl) % 8;
1d8a5b
+    if (param->sbb != 0) {
1d8a5b
+        Assert(outcnt > 0, "outbuf must have enough space for EOBS");
1d8a5b
+        outcnt--;
1d8a5b
+    }
1d8a5b
+}
1d8a5b
+
1d8a5b
+static void close_stream(struct dfltcc_param_v0 *param)
1d8a5b
+{
1d8a5b
+    if (param->bcf) {
1d8a5b
+        bi_close_block(param);
1d8a5b
+    }
1d8a5b
+    send_bits(1, 3); /* BFINAL=1, BTYPE=00 */
1d8a5b
+    bi_windup();
1d8a5b
+    put_short(0x0000);
1d8a5b
+    put_short(0xFFFF);
1d8a5b
+}
1d8a5b
+
1d8a5b
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
1d8a5b
+
1d8a5b
+/* ===========================================================================
1d8a5b
+ * Compress ifd into ofd in hardware or fall back to software.
1d8a5b
+ */
1d8a5b
+int dfltcc_deflate(int pack_level)
1d8a5b
+{
1d8a5b
+    const char *s;
1d8a5b
+    unsigned long level_mask;
1d8a5b
+    unsigned long block_size;
1d8a5b
+    off_t block_threshold;
1d8a5b
+    struct dfltcc_param_v0 *param;
1d8a5b
+    int extra;
1d8a5b
+
1d8a5b
+    /* Check whether we can use hardware compression */
1d8a5b
+    if (!is_dfltcc_enabled() || getenv("SOURCE_DATE_EPOCH")) {
1d8a5b
+        return deflate(pack_level);
1d8a5b
+    }
1d8a5b
+#ifndef DFLTCC_LEVEL_MASK
1d8a5b
+#define DFLTCC_LEVEL_MASK 0x2
1d8a5b
+#endif
1d8a5b
+    s = getenv("DFLTCC_LEVEL_MASK");
1d8a5b
+    level_mask = (s && *s) ? strtoul(s, NULL, 0) : DFLTCC_LEVEL_MASK;
1d8a5b
+    if ((level_mask & (1 << pack_level)) == 0) {
1d8a5b
+        return deflate(pack_level);
1d8a5b
+    }
1d8a5b
+    dfltcc_qaf(&ctx.af);
1d8a5b
+    if (!is_bit_set(ctx.af.fns, DFLTCC_CMPR) ||
1d8a5b
+        !is_bit_set(ctx.af.fns, DFLTCC_GDHT) ||
1d8a5b
+        !is_bit_set(ctx.af.fmts, DFLTCC_FMT0)) {
1d8a5b
+        return deflate(pack_level);
1d8a5b
+    }
1d8a5b
+
1d8a5b
+    /* Initialize tuning parameters */
1d8a5b
+#ifndef DFLTCC_BLOCK_SIZE
1d8a5b
+#define DFLTCC_BLOCK_SIZE 1048576
1d8a5b
+#endif
1d8a5b
+    s = getenv("DFLTCC_BLOCK_SIZE");
1d8a5b
+    block_size = (s && *s) ? strtoul(s, NULL, 0) : DFLTCC_BLOCK_SIZE;
1d8a5b
+    (void)block_size;
1d8a5b
+#ifndef DFLTCC_FIRST_FHT_BLOCK_SIZE
1d8a5b
+#define DFLTCC_FIRST_FHT_BLOCK_SIZE 4096
1d8a5b
+#endif
1d8a5b
+    s = getenv("DFLTCC_FIRST_FHT_BLOCK_SIZE");
1d8a5b
+    block_threshold = (s && *s) ? strtoul(s, NULL, 0) :
1d8a5b
+                                  DFLTCC_FIRST_FHT_BLOCK_SIZE;
1d8a5b
+
1d8a5b
+    /* Compress ifd into ofd in a loop */
1d8a5b
+    param = init_param(&ctx.param);
1d8a5b
+    while (1) {
1d8a5b
+        /* Flush the output data */
1d8a5b
+        if (outcnt > OUTBUFSIZ - 8) {
1d8a5b
+            flush_outbuf();
1d8a5b
+        }
1d8a5b
+
1d8a5b
+        /* Close the block */
1d8a5b
+        if (param->bcf && total_in == block_threshold && !param->cf) {
1d8a5b
+            close_block(param);
1d8a5b
+            block_threshold += block_size;
1d8a5b
+        }
1d8a5b
+
1d8a5b
+        /* Read the input data */
1d8a5b
+        if (inptr == insize) {
1d8a5b
+            if (fill_inbuf(1) == EOF && !param->cf) {
1d8a5b
+                break;
1d8a5b
+            }
1d8a5b
+            inptr = 0;
1d8a5b
+        }
1d8a5b
+
1d8a5b
+        /* Temporarily mask some input data */
1d8a5b
+        extra = MAX(0, total_in + (insize - inptr) - block_threshold);
1d8a5b
+        insize -= extra;
1d8a5b
+
1d8a5b
+        /* Start a new block */
1d8a5b
+        if (!param->bcf) {
1d8a5b
+            if (total_in == 0 && block_threshold > 0) {
1d8a5b
+                param->htt = HTT_FIXED;
1d8a5b
+            } else {
1d8a5b
+                param->htt = HTT_DYNAMIC;
1d8a5b
+                dfltcc_gdht(param);
1d8a5b
+            }
1d8a5b
+        }
1d8a5b
+
1d8a5b
+        /* Compress inbuf into outbuf */
1d8a5b
+        dfltcc_cmpr_xpnd(param, DFLTCC_CMPR);
1d8a5b
+
1d8a5b
+        /* Unmask the input data */
1d8a5b
+        insize += extra;
1d8a5b
+
1d8a5b
+        /* Continue the block */
1d8a5b
+        param->bcf = 1;
1d8a5b
+    }
1d8a5b
+    close_stream(param);
1d8a5b
+    setcrc(__builtin_bswap32(param->cv));
1d8a5b
+    return 0;
1d8a5b
+}
1d8a5b
+
1d8a5b
+/* ===========================================================================
1d8a5b
+ * Decompress ifd into ofd in hardware or fall back to software.
1d8a5b
+ */
1d8a5b
+int dfltcc_inflate(void)
1d8a5b
+{
1d8a5b
+    struct dfltcc_param_v0 *param;
1d8a5b
+    dfltcc_cc cc;
1d8a5b
+
1d8a5b
+    /* Check whether we can use hardware decompression */
1d8a5b
+    if (!is_dfltcc_enabled()) {
1d8a5b
+        return inflate();
1d8a5b
+    }
1d8a5b
+    dfltcc_qaf(&ctx.af);
1d8a5b
+    if (!is_bit_set(ctx.af.fns, DFLTCC_XPND)) {
1d8a5b
+        return inflate();
1d8a5b
+    }
1d8a5b
+
1d8a5b
+    /* Decompress ifd into ofd in a loop */
1d8a5b
+    param = init_param(&ctx.param);
1d8a5b
+    while (1) {
1d8a5b
+        /* Perform I/O */
1d8a5b
+        if (outcnt == OUTBUFSIZ) {
1d8a5b
+            flush_outbuf();
1d8a5b
+        }
1d8a5b
+        if (inptr == insize) {
1d8a5b
+            if (fill_inbuf(1) == EOF) {
1d8a5b
+                /* Premature EOF */
1d8a5b
+                return 2;
1d8a5b
+            }
1d8a5b
+            inptr = 0;
1d8a5b
+        }
1d8a5b
+        /* Decompress inbuf into outbuf */
1d8a5b
+        cc = dfltcc_cmpr_xpnd(param, DFLTCC_XPND);
1d8a5b
+        if (cc == DFLTCC_CC_OK) {
1d8a5b
+            /* The entire deflate stream has been successfully decompressed */
1d8a5b
+            break;
1d8a5b
+        }
1d8a5b
+        if (cc == DFLTCC_CC_OP2_CORRUPT && param->oesc != 0) {
1d8a5b
+            /* The deflate stream is corrupted */
1d8a5b
+            return 2;
1d8a5b
+        }
1d8a5b
+        /* There must be more data to decompress */
1d8a5b
+    }
1d8a5b
+    if (param->sbb != 0) {
1d8a5b
+        /* The deflate stream has ended in the middle of a byte - go to the next
1d8a5b
+         * byte boundary, so that unzip() can read CRC and length.
1d8a5b
+         */
1d8a5b
+        inptr++;
1d8a5b
+    }
1d8a5b
+    setcrc(__builtin_bswap32(param->cv)); /* set CRC value for unzip() */
1d8a5b
+    flush_outbuf(); /* update bytes_out for unzip() */
1d8a5b
+    return 0;
1d8a5b
+}
1d8a5b
diff --git a/gzip.c b/gzip.c
1d8a5b
index 3ddfb7f..4fffc4f 100644
1d8a5b
--- a/gzip.c
1d8a5b
+++ b/gzip.c
1d8a5b
@@ -128,9 +128,21 @@ static char const *const license_msg[] = {
1d8a5b
 
1d8a5b
                 /* global buffers */
1d8a5b
 
1d8a5b
+#ifdef IBM_Z_DFLTCC
1d8a5b
+/* DEFLATE COMPRESSION CALL works faster with page-aligned input buffers */
1d8a5b
+__attribute__((aligned(4096)))
1d8a5b
+#endif
1d8a5b
 DECLARE(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
1d8a5b
+#ifdef IBM_Z_DFLTCC
1d8a5b
+/* DEFLATE COMPRESSION CALL works faster with page-aligned output buffers */
1d8a5b
+__attribute__((aligned(4096)))
1d8a5b
+#endif
1d8a5b
 DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
1d8a5b
 DECLARE(ush, d_buf,  DIST_BUFSIZE);
1d8a5b
+#ifdef IBM_Z_DFLTCC
1d8a5b
+/* DEFLATE COMPRESSION CALL works only with page-aligned windows */
1d8a5b
+__attribute__((aligned(4096)))
1d8a5b
+#endif
1d8a5b
 DECLARE(uch, window, 2L*WSIZE);
1d8a5b
 #ifndef MAXSEG_64K
1d8a5b
     DECLARE(ush, tab_prefix, 1L<
1d8a5b
diff --git a/gzip.h b/gzip.h
1d8a5b
index 46bbac9..0c59cc2 100644
1d8a5b
--- a/gzip.h
1d8a5b
+++ b/gzip.h
1d8a5b
@@ -74,7 +74,10 @@ extern int method;         /* compression method *   /
1d8a5b
  */
1d8a5b
 
1d8a5b
 #ifndef	INBUFSIZ
1d8a5b
-#  ifdef SMALL_MEM
1d8a5b
+#  ifdef IBM_Z_DFLTCC
1d8a5b
+/* DEFLATE COMPRESSION CALL works faster with larger input buffers */
1d8a5b
+#    define INBUFSIZ  0x40000
1d8a5b
+#  elif defined SMALL_MEM
1d8a5b
 #    define INBUFSIZ  0x2000  /* input buffer size */
1d8a5b
 #  else
1d8a5b
 #    define INBUFSIZ  0x8000  /* input buffer size */
1d8a5b
@@ -83,7 +86,10 @@ extern int method;         /* compression method */
1d8a5b
 #define INBUF_EXTRA  64     /* required by unlzw() */
1d8a5b
 
1d8a5b
 #ifndef	OUTBUFSIZ
1d8a5b
-#  ifdef SMALL_MEM
1d8a5b
+#  ifdef IBM_Z_DFLTCC
1d8a5b
+/* DEFLATE COMPRESSION CALL works faster with larger output buffers */
1d8a5b
+#    define OUTBUFSIZ   0x40000
1d8a5b
+#  elif defined SMALL_MEM
1d8a5b
 #    define OUTBUFSIZ   8192  /* output buffer size */
1d8a5b
 #  else
1d8a5b
 #    define OUTBUFSIZ  16384  /* output buffer size */
1d8a5b
@@ -275,8 +281,8 @@ extern int unlzh      (int in, int out);
1d8a5b
 extern noreturn void abort_gzip (void);
1d8a5b
 
1d8a5b
         /* in deflate.c */
1d8a5b
-extern void lm_init (int pack_level, ush *flags);
1d8a5b
-extern off_t deflate (void);
1d8a5b
+extern void lm_init (int pack_level);
1d8a5b
+extern off_t deflate (int pack_level);
1d8a5b
 
1d8a5b
         /* in trees.c */
1d8a5b
 extern void ct_init     (ush *attr, int *method);
1d8a5b
@@ -284,6 +290,8 @@ extern int  ct_tally    (int dist, int lc);
1d8a5b
 extern off_t flush_block (char *buf, ulg stored_len, int pad, int eof);
1d8a5b
 
1d8a5b
         /* in bits.c */
1d8a5b
+extern unsigned short bi_buf;
1d8a5b
+extern int            bi_valid;
1d8a5b
 extern void     bi_init    (file_t zipfile);
1d8a5b
 extern void     send_bits  (int value, int length);
1d8a5b
 extern unsigned bi_reverse (unsigned value, int length) _GL_ATTRIBUTE_CONST;
1d8a5b
@@ -293,7 +301,9 @@ extern int     (*read_buf) (char *buf, unsigned size);
1d8a5b
 
1d8a5b
         /* in util.c: */
1d8a5b
 extern int copy           (int in, int out);
1d8a5b
-extern ulg  updcrc        (uch *s, unsigned n);
1d8a5b
+extern ulg  updcrc        (const uch *s, unsigned n);
1d8a5b
+extern ulg  getcrc        (void) _GL_ATTRIBUTE_PURE;
1d8a5b
+extern void setcrc        (ulg c);
1d8a5b
 extern void clear_bufs    (void);
1d8a5b
 extern int  fill_inbuf    (int eof_ok);
1d8a5b
 extern void flush_outbuf  (void);
1d8a5b
@@ -315,3 +325,9 @@ extern void fprint_off    (FILE *, off_t, int);
1d8a5b
 
1d8a5b
         /* in inflate.c */
1d8a5b
 extern int inflate (void);
1d8a5b
+
1d8a5b
+        /* in dfltcc.c */
1d8a5b
+#ifdef IBM_Z_DFLTCC
1d8a5b
+extern int dfltcc_deflate (int pack_level);
1d8a5b
+extern int dfltcc_inflate (void);
1d8a5b
+#endif
1d8a5b
diff --git a/tests/znew-k b/tests/znew-k
1d8a5b
index eeb7b29..d43246b 100755
1d8a5b
--- a/tests/znew-k
1d8a5b
+++ b/tests/znew-k
1d8a5b
@@ -29,12 +29,13 @@ chmod +x compress || framework_failure_
1d8a5b
 # Note that the basename must have a length of 6 or greater.
1d8a5b
 # Otherwise, "test -f $name" below would fail.
1d8a5b
 name=123456.Z
1d8a5b
+gzname=123456.gz
1d8a5b
 
1d8a5b
 printf '%1012977s' ' ' | gzip -c > $name || framework_failure_
1d8a5b
 
1d8a5b
 fail=0
1d8a5b
 
1d8a5b
 znew -K $name || fail=1
1d8a5b
-test -f $name || fail=1
1d8a5b
+test -f $name || test -f $gzname || fail=1
1d8a5b
 
1d8a5b
 Exit $fail
1d8a5b
diff --git a/unzip.c b/unzip.c
1d8a5b
index a7255d4..86ef664 100644
1d8a5b
--- a/unzip.c
1d8a5b
+++ b/unzip.c
1d8a5b
@@ -129,7 +129,11 @@ int unzip(in, out)
1d8a5b
     /* Decompress */
1d8a5b
     if (method == DEFLATED)  {
1d8a5b
 
1d8a5b
+#ifdef IBM_Z_DFLTCC
1d8a5b
+        int res = dfltcc_inflate();
1d8a5b
+#else
1d8a5b
         int res = inflate();
1d8a5b
+#endif
1d8a5b
 
1d8a5b
         if (res == 3) {
1d8a5b
             xalloc_die ();
1d8a5b
diff --git a/util.c b/util.c
1d8a5b
index 41e50d7..dc00f4a 100644
1d8a5b
--- a/util.c
1d8a5b
+++ b/util.c
1d8a5b
@@ -96,6 +96,11 @@ static const ulg crc_32_tab[] = {
1d8a5b
   0x2d02ef8dL
1d8a5b
 };
1d8a5b
 
1d8a5b
+/* ========================================================================
1d8a5b
+ * Shift register contents
1d8a5b
+ */
1d8a5b
+static ulg crc = (ulg)0xffffffffL;
1d8a5b
+
1d8a5b
 /* ===========================================================================
1d8a5b
  * Copy input to output unchanged: zcat == cat with --force.
1d8a5b
  * IN assertion: insize bytes have already been read in inbuf and inptr bytes
1d8a5b
@@ -126,13 +131,11 @@ int copy(in, out)
1d8a5b
  * Return the current crc in either case.
1d8a5b
  */
1d8a5b
 ulg updcrc(s, n)
1d8a5b
-    uch *s;                 /* pointer to bytes to pump through */
1d8a5b
+    const uch *s;           /* pointer to bytes to pump through */
1d8a5b
     unsigned n;             /* number of bytes in s[] */
1d8a5b
 {
1d8a5b
     register ulg c;         /* temporary variable */
1d8a5b
 
1d8a5b
-    static ulg crc = (ulg)0xffffffffL; /* shift register contents */
1d8a5b
-
1d8a5b
     if (s == NULL) {
1d8a5b
         c = 0xffffffffL;
1d8a5b
     } else {
1d8a5b
@@ -145,6 +148,23 @@ ulg updcrc(s, n)
1d8a5b
     return c ^ 0xffffffffL;       /* (instead of ~c for 64-bit machines) */
1d8a5b
 }
1d8a5b
 
1d8a5b
+/* ===========================================================================
1d8a5b
+ * Return a current CRC value.
1d8a5b
+ */
1d8a5b
+ulg getcrc()
1d8a5b
+{
1d8a5b
+    return crc ^ 0xffffffffL;
1d8a5b
+}
1d8a5b
+
1d8a5b
+/* ===========================================================================
1d8a5b
+ * Set a new CRC value.
1d8a5b
+ */
1d8a5b
+void setcrc(c)
1d8a5b
+    ulg c;
1d8a5b
+{
1d8a5b
+    crc = c ^ 0xffffffffL;
1d8a5b
+}
1d8a5b
+
1d8a5b
 /* ===========================================================================
1d8a5b
  * Clear input and output buffers
1d8a5b
  */
1d8a5b
@@ -238,7 +258,9 @@ void flush_outbuf()
1d8a5b
 {
1d8a5b
     if (outcnt == 0) return;
1d8a5b
 
1d8a5b
-    write_buf(ofd, (char *)outbuf, outcnt);
1d8a5b
+    if (!test) {
1d8a5b
+        write_buf(ofd, (char *)outbuf, outcnt);
1d8a5b
+    }
1d8a5b
     bytes_out += (off_t)outcnt;
1d8a5b
     outcnt = 0;
1d8a5b
 }
1d8a5b
diff --git a/zip.c b/zip.c
1d8a5b
index 1bd4c78..ace7e5e 100644
1d8a5b
--- a/zip.c
1d8a5b
+++ b/zip.c
1d8a5b
@@ -23,9 +23,12 @@
1d8a5b
 #include "tailor.h"
1d8a5b
 #include "gzip.h"
1d8a5b
 
1d8a5b
-local ulg crc;       /* crc on uncompressed file data */
1d8a5b
 off_t header_bytes;   /* number of bytes in gzip header */
1d8a5b
 
1d8a5b
+#define FAST 4
1d8a5b
+#define SLOW 2
1d8a5b
+/* speed options for the general purpose bit flag */
1d8a5b
+
1d8a5b
 /* ===========================================================================
1d8a5b
  * Deflate in to out.
1d8a5b
  * IN assertions: the input and output buffers are cleared.
1d8a5b
@@ -68,11 +71,15 @@ int zip(in, out)
1d8a5b
     put_long (stamp);
1d8a5b
 
1d8a5b
     /* Write deflated file to zip file */
1d8a5b
-    crc = updcrc(0, 0);
1d8a5b
+    updcrc(NULL, 0);
1d8a5b
 
1d8a5b
     bi_init(out);
1d8a5b
     ct_init(&attr, &method);
1d8a5b
-    lm_init(level, &deflate_flags);
1d8a5b
+    if (level == 1) {
1d8a5b
+        deflate_flags |= FAST;
1d8a5b
+    } else if (level == 9) {
1d8a5b
+        deflate_flags |= SLOW;
1d8a5b
+    }
1d8a5b
 
1d8a5b
     put_byte((uch)deflate_flags); /* extra flags */
1d8a5b
     put_byte(OS_CODE);            /* OS identifier */
1d8a5b
@@ -85,7 +92,11 @@ int zip(in, out)
1d8a5b
     }
1d8a5b
     header_bytes = (off_t)outcnt;
1d8a5b
 
1d8a5b
-    (void)deflate();
1d8a5b
+#ifdef IBM_Z_DFLTCC
1d8a5b
+    (void)dfltcc_deflate(level);
1d8a5b
+#else
1d8a5b
+    (void)deflate(level);
1d8a5b
+#endif
1d8a5b
 
1d8a5b
 #ifndef NO_SIZE_CHECK
1d8a5b
   /* Check input size
1d8a5b
@@ -98,7 +109,7 @@ int zip(in, out)
1d8a5b
 #endif
1d8a5b
 
1d8a5b
     /* Write the crc and uncompressed size */
1d8a5b
-    put_long(crc);
1d8a5b
+    put_long(getcrc());
1d8a5b
     put_long((ulg)bytes_in);
1d8a5b
     header_bytes += 2*4;
1d8a5b
 
1d8a5b
@@ -126,7 +137,7 @@ int file_read(buf, size)
1d8a5b
         read_error();
1d8a5b
     }
1d8a5b
 
1d8a5b
-    crc = updcrc((uch*)buf, len);
1d8a5b
+    updcrc((uch*)buf, len);
1d8a5b
     bytes_in += (off_t)len;
1d8a5b
     return (int)len;
1d8a5b
 }
1d8a5b
2.21.0