home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / flash078.zip / flashsource-r0_7_8.zip / libpng / pnggccrd.c < prev    next >
Text File  |  2001-04-27  |  231KB  |  5,181 lines

  1. /* pnggccrd.c - mixed C/assembler version of utilities to read a PNG file
  2.  *
  3.  * For Intel x86 CPU (Pentium-MMX or later) and GNU C compiler.
  4.  *
  5.  *     See http://www.intel.com/drg/pentiumII/appnotes/916/916.htm
  6.  *     and http://www.intel.com/drg/pentiumII/appnotes/923/923.htm
  7.  *     for Intel's performance analysis of the MMX vs. non-MMX code.
  8.  *
  9.  * libpng version 1.0.11 - April 27, 2001
  10.  * For conditions of distribution and use, see copyright notice in png.h
  11.  * Copyright (c) 1998-2001 Glenn Randers-Pehrson
  12.  * Copyright (c) 1998, Intel Corporation
  13.  *
  14.  * Based on MSVC code contributed by Nirav Chhatrapati, Intel Corp., 1998.
  15.  * Interface to libpng contributed by Gilles Vollant, 1999.
  16.  * GNU C port by Greg Roelofs, 1999-2001.
  17.  *
  18.  * Lines 2350-4300 converted in place with intel2gas 1.3.1:
  19.  *
  20.  *   intel2gas -mdI pnggccrd.c.partially-msvc -o pnggccrd.c
  21.  *
  22.  * and then cleaned up by hand.  See http://hermes.terminal.at/intel2gas/ .
  23.  *
  24.  * NOTE:  A sufficiently recent version of GNU as (or as.exe under DOS/Windows)
  25.  *        is required to assemble the newer MMX instructions such as movq.
  26.  *        For djgpp, see
  27.  *
  28.  *           ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bnu281b.zip
  29.  *
  30.  *        (or a later version in the same directory).  For Linux, check your
  31.  *        distribution's web site(s) or try these links:
  32.  *
  33.  *           http://rufus.w3.org/linux/RPM/binutils.html
  34.  *           http://www.debian.org/Packages/stable/devel/binutils.html
  35.  *           ftp://ftp.slackware.com/pub/linux/slackware/slackware/slakware/d1/
  36.  *             binutils.tgz
  37.  *
  38.  *        For other platforms, see the main GNU site:
  39.  *
  40.  *           ftp://ftp.gnu.org/pub/gnu/binutils/
  41.  *
  42.  *        Version 2.5.2l.15 is definitely too old...
  43.  */
  44.  
  45. /*
  46.  * TEMPORARY PORTING NOTES AND CHANGELOG (mostly by Greg Roelofs)
  47.  * =====================================
  48.  *
  49.  * 19991006:
  50.  *  - fixed sign error in post-MMX cleanup code (16- & 32-bit cases)
  51.  *
  52.  * 19991007:
  53.  *  - additional optimizations (possible or definite):
  54.  *     x [DONE] write MMX code for 64-bit case (pixel_bytes == 8) [not tested]
  55.  *     - write MMX code for 48-bit case (pixel_bytes == 6)
  56.  *     - figure out what's up with 24-bit case (pixel_bytes == 3):
  57.  *        why subtract 8 from width_mmx in the pass 4/5 case?
  58.  *        (only width_mmx case) (near line 1606)
  59.  *     x [DONE] replace pixel_bytes within each block with the true
  60.  *        constant value (or are compilers smart enough to do that?)
  61.  *     - rewrite all MMX interlacing code so it's aligned with
  62.  *        the *beginning* of the row buffer, not the end.  This
  63.  *        would not only allow one to eliminate half of the memory
  64.  *        writes for odd passes (that is, pass == odd), it may also
  65.  *        eliminate some unaligned-data-access exceptions (assuming
  66.  *        there's a penalty for not aligning 64-bit accesses on
  67.  *        64-bit boundaries).  The only catch is that the "leftover"
  68.  *        pixel(s) at the end of the row would have to be saved,
  69.  *        but there are enough unused MMX registers in every case,
  70.  *        so this is not a problem.  A further benefit is that the
  71.  *        post-MMX cleanup code (C code) in at least some of the
  72.  *        cases could be done within the assembler block.
  73.  *  x [DONE] the "v3 v2 v1 v0 v7 v6 v5 v4" comments are confusing,
  74.  *     inconsistent, and don't match the MMX Programmer's Reference
  75.  *     Manual conventions anyway.  They should be changed to
  76.  *     "b7 b6 b5 b4 b3 b2 b1 b0," where b0 indicates the byte that
  77.  *     was lowest in memory (e.g., corresponding to a left pixel)
  78.  *     and b7 is the byte that was highest (e.g., a right pixel).
  79.  *
  80.  * 19991016:
  81.  *  - Brennan's Guide notwithstanding, gcc under Linux does *not*
  82.  *     want globals prefixed by underscores when referencing them--
  83.  *     i.e., if the variable is const4, then refer to it as const4,
  84.  *     not _const4.  This seems to be a djgpp-specific requirement.
  85.  *     Also, such variables apparently *must* be declared outside
  86.  *     of functions; neither static nor automatic variables work if
  87.  *     defined within the scope of a single function, but both
  88.  *     static and truly global (multi-module) variables work fine.
  89.  *
  90.  * 19991023:
  91.  *  - fixed png_combine_row() non-MMX replication bug (odd passes only?)
  92.  *  - switched from string-concatenation-with-macros to cleaner method of
  93.  *     renaming global variables for djgpp--i.e., always use prefixes in
  94.  *     inlined assembler code (== strings) and conditionally rename the
  95.  *     variables, not the other way around.  Hence _const4, _mask8_0, etc.
  96.  *
  97.  * 19991024:
  98.  *  - fixed mmxsupport()/png_do_read_interlace() first-row bug
  99.  *     This one was severely weird:  even though mmxsupport() doesn't touch
  100.  *     ebx (where "row" pointer was stored), it nevertheless managed to zero
  101.  *     the register (even in static/non-fPIC code--see below), which in turn
  102.  *     caused png_do_read_interlace() to return prematurely on the first row of
  103.  *     interlaced images (i.e., without expanding the interlaced pixels).
  104.  *     Inspection of the generated assembly code didn't turn up any clues,
  105.  *     although it did point at a minor optimization (i.e., get rid of
  106.  *     mmx_supported_local variable and just use eax).  Possibly the CPUID
  107.  *     instruction is more destructive than it looks?  (Not yet checked.)
  108.  *  - "info gcc" was next to useless, so compared fPIC and non-fPIC assembly
  109.  *     listings...  Apparently register spillage has to do with ebx, since
  110.  *     it's used to index the global offset table.  Commenting it out of the
  111.  *     input-reg lists in png_combine_row() eliminated compiler barfage, so
  112.  *     ifdef'd with __PIC__ macro:  if defined, use a global for unmask
  113.  *
  114.  * 19991107:
  115.  *  - verified CPUID clobberage:  12-char string constant ("GenuineIntel",
  116.  *     "AuthenticAMD", etc.) placed in ebx:ecx:edx.  Still need to polish.
  117.  *
  118.  * 19991120:
  119.  *  - made "diff" variable (now "_dif") global to simplify conversion of
  120.  *     filtering routines (running out of regs, sigh).  "diff" is still used
  121.  *     in interlacing routines, however.
  122.  *  - fixed up both versions of mmxsupport() (ORIG_THAT_USED_TO_CLOBBER_EBX
  123.  *     macro determines which is used); original not yet tested.
  124.  *
  125.  * 20000213:
  126.  *  - when compiling with gcc, be sure to use  -fomit-frame-pointer
  127.  *
  128.  * 20000319:
  129.  *  - fixed a register-name typo in png_do_read_interlace(), default (MMX) case,
  130.  *     pass == 4 or 5, that caused visible corruption of interlaced images
  131.  *
  132.  * 20000623:
  133.  *  - Various problems were reported with gcc 2.95.2 in the Cygwin environment,
  134.  *     many of the form "forbidden register 0 (ax) was spilled for class AREG."
  135.  *     This is explained at http://gcc.gnu.org/fom_serv/cache/23.html, and
  136.  *     Chuck Wilson supplied a patch involving dummy output registers.  See
  137.  *     http://sourceforge.net/bugs/?func=detailbug&bug_id=108741&group_id=5624
  138.  *     for the original (anonymous) SourceForge bug report.
  139.  *
  140.  * 20000706:
  141.  *  - Chuck Wilson passed along these remaining gcc 2.95.2 errors:
  142.  *       pnggccrd.c: In function `png_combine_row':
  143.  *       pnggccrd.c:525: more than 10 operands in `asm'
  144.  *       pnggccrd.c:669: more than 10 operands in `asm'
  145.  *       pnggccrd.c:828: more than 10 operands in `asm'
  146.  *       pnggccrd.c:994: more than 10 operands in `asm'
  147.  *       pnggccrd.c:1177: more than 10 operands in `asm'
  148.  *     They are all the same problem and can be worked around by using the
  149.  *     global _unmask variable unconditionally, not just in the -fPIC case.
  150.  *     Reportedly earlier versions of gcc also have the problem with more than
  151.  *     10 operands; they just don't report it.  Much strangeness ensues, etc.
  152.  *
  153.  * 20000729:
  154.  *  - enabled png_read_filter_row_mmx_up() (shortest remaining unconverted
  155.  *     MMX routine); began converting png_read_filter_row_mmx_sub()
  156.  *  - to finish remaining sections:
  157.  *     - clean up indentation and comments
  158.  *     - preload local variables
  159.  *     - add output and input regs (order of former determines numerical
  160.  *        mapping of latter)
  161.  *     - avoid all usage of ebx (including bx, bh, bl) register [20000823]
  162.  *     - remove "$" from addressing of Shift and Mask variables [20000823]
  163.  *
  164.  * 20000731:
  165.  *  - global union vars causing segfaults in png_read_filter_row_mmx_sub()?
  166.  *
  167.  * 20000822:
  168.  *  - ARGH, stupid png_read_filter_row_mmx_sub() segfault only happens with
  169.  *     shared-library (-fPIC) version!  Code works just fine as part of static
  170.  *     library.  Damn damn damn damn damn, should have tested that sooner.
  171.  *     ebx is getting clobbered again (explicitly this time); need to save it
  172.  *     on stack or rewrite asm code to avoid using it altogether.  Blargh!
  173.  *
  174.  * 20000823:
  175.  *  - first section was trickiest; all remaining sections have ebx -> edx now.
  176.  *     (-fPIC works again.)  Also added missing underscores to various Shift*
  177.  *     and *Mask* globals and got rid of leading "$" signs.
  178.  *
  179.  * 20000826:
  180.  *  - added visual separators to help navigate microscopic printed copies
  181.  *     (http://pobox.com/~newt/code/gpr-latest.zip, mode 10); started working
  182.  *     on png_read_filter_row_mmx_avg()
  183.  *
  184.  * 20000828:
  185.  *  - finished png_read_filter_row_mmx_avg():  only Paeth left! (930 lines...)
  186.  *     What the hell, did png_read_filter_row_mmx_paeth(), too.  Comments not
  187.  *     cleaned up/shortened in either routine, but functionality is complete
  188.  *     and seems to be working fine.
  189.  *
  190.  * 20000829:
  191.  *  - ahhh, figured out last(?) bit of gcc/gas asm-fu:  if register is listed
  192.  *     as an input reg (with dummy output variables, etc.), then it *cannot*
  193.  *     also appear in the clobber list or gcc 2.95.2 will barf.  The solution
  194.  *     is simple enough...
  195.  *
  196.  * 20000914:
  197.  *  - bug in png_read_filter_row_mmx_avg():  16-bit grayscale not handled
  198.  *     correctly (but 48-bit RGB just fine)
  199.  *
  200.  * 20000916:
  201.  *  - fixed bug in png_read_filter_row_mmx_avg(), bpp == 2 case; three errors:
  202.  *     - "_ShiftBpp.use = 24;"      should have been   "_ShiftBpp.use = 16;"
  203.  *     - "_ShiftRem.use = 40;"      should have been   "_ShiftRem.use = 48;"
  204.  *     - "psllq _ShiftRem, %%mm2"   should have been   "psrlq _ShiftRem, %%mm2"
  205.  *
  206.  * 20010103:
  207.  *  - renamed mmxsupport() to png_mmx_support(), with auto-set of mmx_supported,
  208.  *     and made it public
  209.  *
  210.  * 20010104:
  211.  *  - removed dependency on png_read_filter_row_c() (C code already duplicated
  212.  *     within MMX version of png_read_filter_row()) so no longer necessary to
  213.  *     compile it into pngrutil.o
  214.  *
  215.  * 20010310:
  216.  *  - fixed buffer-overrun bug in png_combine_row() C code (non-MMX)
  217.  *
  218.  * STILL TO DO:
  219.  *     - test png_do_read_interlace() 64-bit case (pixel_bytes == 8)
  220.  *     - write MMX code for 48-bit case (pixel_bytes == 6)
  221.  *     - figure out what's up with 24-bit case (pixel_bytes == 3):
  222.  *        why subtract 8 from width_mmx in the pass 4/5 case?
  223.  *        (only width_mmx case) (near line 1606)
  224.  *     - rewrite all MMX interlacing code so it's aligned with beginning
  225.  *        of the row buffer, not the end (see 19991007 for details)
  226.  *     x pick one version of mmxsupport() and get rid of the other
  227.  *     - add error messages to any remaining bogus default cases
  228.  *     - enable pixel_depth == 8 cases in png_read_filter_row()? (test speed)
  229.  *     - add support for runtime enable/disable/query of various MMX routines
  230.  */
  231.  
  232. /*
  233. #ifndef PNG_DEBUG
  234. #  define PNG_DEBUG 0
  235. #endif
  236. */
  237.  
  238. #define PNG_INTERNAL
  239. #include "png.h"
  240.  
  241. #if defined(PNG_USE_PNGGCCRD)
  242.  
  243. int PNGAPI png_mmx_support(void);
  244.  
  245. #ifdef PNG_USE_LOCAL_ARRAYS
  246. static const int FARDATA png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
  247. static const int FARDATA png_pass_inc[7]   = {8, 8, 4, 4, 2, 2, 1};
  248. static const int FARDATA png_pass_width[7] = {8, 4, 4, 2, 2, 1, 1};
  249. #endif
  250.  
  251. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
  252. /* djgpp, Win32, and Cygwin add their own underscores to global variables,
  253.  * so define them without: */
  254. #if defined(__DJGPP__) || defined(WIN32) || defined(__CYGWIN__)
  255. #  define _mmx_supported  mmx_supported
  256. #  define _unmask         unmask
  257. #  define _const4         const4
  258. #  define _const6         const6
  259. #  define _mask8_0        mask8_0
  260. #  define _mask16_1       mask16_1
  261. #  define _mask16_0       mask16_0
  262. #  define _mask24_2       mask24_2
  263. #  define _mask24_1       mask24_1
  264. #  define _mask24_0       mask24_0
  265. #  define _mask32_3       mask32_3
  266. #  define _mask32_2       mask32_2
  267. #  define _mask32_1       mask32_1
  268. #  define _mask32_0       mask32_0
  269. #  define _mask48_5       mask48_5
  270. #  define _mask48_4       mask48_4
  271. #  define _mask48_3       mask48_3
  272. #  define _mask48_2       mask48_2
  273. #  define _mask48_1       mask48_1
  274. #  define _mask48_0       mask48_0
  275. #  define _FullLength     FullLength
  276. #  define _MMXLength      MMXLength
  277. #  define _dif            dif
  278. #  define _LBCarryMask    LBCarryMask
  279. #  define _HBClearMask    HBClearMask
  280. #  define _ActiveMask     ActiveMask
  281. #  define _ActiveMask2    ActiveMask2
  282. #  define _ActiveMaskEnd  ActiveMaskEnd
  283. #  define _ShiftBpp       ShiftBpp
  284. #  define _ShiftRem       ShiftRem
  285. #  define _patemp         patemp
  286. #  define _pbtemp         pbtemp
  287. #  define _pctemp         pctemp
  288. #endif
  289.  
  290.  
  291. /* These constants are used in the inlined MMX assembly code.
  292.    Ignore gcc's "At top level: defined but not used" warnings. */
  293.  
  294. /* GRR 20000706:  originally _unmask was needed only when compiling with -fPIC,
  295.  *  since that case uses the %ebx register for indexing the Global Offset Table
  296.  *  and there were no other registers available.  But gcc 2.95 and later emit
  297.  *  "more than 10 operands in `asm'" errors when %ebx is used to preload unmask
  298.  *  in the non-PIC case, so we'll just use the global unconditionally now.
  299.  */
  300. static int _unmask;
  301.  
  302. static unsigned long long _mask8_0  = 0x0102040810204080LL;
  303.  
  304. static unsigned long long _mask16_1 = 0x0101020204040808LL;
  305. static unsigned long long _mask16_0 = 0x1010202040408080LL;
  306.  
  307. static unsigned long long _mask24_2 = 0x0101010202020404LL;
  308. static unsigned long long _mask24_1 = 0x0408080810101020LL;
  309. static unsigned long long _mask24_0 = 0x2020404040808080LL;
  310.  
  311. static unsigned long long _mask32_3 = 0x0101010102020202LL;
  312. static unsigned long long _mask32_2 = 0x0404040408080808LL;
  313. static unsigned long long _mask32_1 = 0x1010101020202020LL;
  314. static unsigned long long _mask32_0 = 0x4040404080808080LL;
  315.  
  316. static unsigned long long _mask48_5 = 0x0101010101010202LL;
  317. static unsigned long long _mask48_4 = 0x0202020204040404LL;
  318. static unsigned long long _mask48_3 = 0x0404080808080808LL;
  319. static unsigned long long _mask48_2 = 0x1010101010102020LL;
  320. static unsigned long long _mask48_1 = 0x2020202040404040LL;
  321. static unsigned long long _mask48_0 = 0x4040808080808080LL;
  322.  
  323. static unsigned long long _const4   = 0x0000000000FFFFFFLL;
  324. //static unsigned long long _const5 = 0x000000FFFFFF0000LL;     // NOT USED
  325. static unsigned long long _const6   = 0x00000000000000FFLL;
  326.  
  327. // These are used in the row-filter routines and should/would be local
  328. //  variables if not for gcc addressing limitations.
  329.  
  330. static png_uint_32  _FullLength;
  331. static png_uint_32  _MMXLength;
  332. static int          _dif;
  333. static int          _patemp;    // temp variables for Paeth routine
  334. static int          _pbtemp;
  335. static int          _pctemp;
  336. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  337.  
  338. static int _mmx_supported = 2;
  339.  
  340. /*===========================================================================*/
  341. /*                                                                           */
  342. /*                       P N G _ C O M B I N E _ R O W                       */
  343. /*                                                                           */
  344. /*===========================================================================*/
  345.  
  346. #if defined(PNG_HAVE_ASSEMBLER_COMBINE_ROW)
  347.  
  348. #define BPP2  2
  349. #define BPP3  3        /* bytes per pixel (a.k.a. pixel_bytes) */
  350. #define BPP4  4
  351. #define BPP6  6        /* (defined only to help avoid cut-and-paste errors) */
  352. #define BPP8  8
  353.  
  354. /* Combines the row recently read in with the previous row.
  355.    This routine takes care of alpha and transparency if requested.
  356.    This routine also handles the two methods of progressive display
  357.    of interlaced images, depending on the mask value.
  358.    The mask value describes which pixels are to be combined with
  359.    the row.  The pattern always repeats every 8 pixels, so just 8
  360.    bits are needed.  A one indicates the pixel is to be combined; a
  361.    zero indicates the pixel is to be skipped.  This is in addition
  362.    to any alpha or transparency value associated with the pixel.
  363.    If you want all pixels to be combined, pass 0xff (255) in mask. */
  364.  
  365. /* Use this routine for the x86 platform - it uses a faster MMX routine
  366.    if the machine supports MMX. */
  367.  
  368. void /* PRIVATE */
  369. png_combine_row(png_structp png_ptr, png_bytep row, int mask)
  370. {
  371.    png_debug(1, "in png_combine_row (pnggccrd.c)\n");
  372.  
  373.    if (_mmx_supported == 2) {
  374.        png_mmx_support();
  375.    }
  376.  
  377.    if (mask == 0xff)
  378.    {
  379.       png_debug(2,"mask == 0xff:  doing single png_memcpy()\n");
  380.       png_memcpy(row, png_ptr->row_buf + 1,
  381.        (png_size_t)((png_ptr->width * png_ptr->row_info.pixel_depth + 7) >> 3));
  382.    }
  383.    else   /* (png_combine_row() is never called with mask == 0) */
  384.    {
  385.       switch (png_ptr->row_info.pixel_depth)
  386.       {
  387.          case 1:        /* png_ptr->row_info.pixel_depth */
  388.          {
  389.             png_bytep sp;
  390.             png_bytep dp;
  391.             int s_inc, s_start, s_end;
  392.             int m;
  393.             int shift;
  394.             png_uint_32 i;
  395.  
  396.             sp = png_ptr->row_buf + 1;
  397.             dp = row;
  398.             m = 0x80;
  399. #if defined(PNG_READ_PACKSWAP_SUPPORTED)
  400.             if (png_ptr->transformations & PNG_PACKSWAP)
  401.             {
  402.                 s_start = 0;
  403.                 s_end = 7;
  404.                 s_inc = 1;
  405.             }
  406.             else
  407. #endif
  408.             {
  409.                 s_start = 7;
  410.                 s_end = 0;
  411.                 s_inc = -1;
  412.             }
  413.  
  414.             shift = s_start;
  415.  
  416.             for (i = 0; i < png_ptr->width; i++)
  417.             {
  418.                if (m & mask)
  419.                {
  420.                   int value;
  421.  
  422.                   value = (*sp >> shift) & 0x1;
  423.                   *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
  424.                   *dp |= (png_byte)(value << shift);
  425.                }
  426.  
  427.                if (shift == s_end)
  428.                {
  429.                   shift = s_start;
  430.                   sp++;
  431.                   dp++;
  432.                }
  433.                else
  434.                   shift += s_inc;
  435.  
  436.                if (m == 1)
  437.                   m = 0x80;
  438.                else
  439.                   m >>= 1;
  440.             }
  441.             break;
  442.          }
  443.  
  444.          case 2:        /* png_ptr->row_info.pixel_depth */
  445.          {
  446.             png_bytep sp;
  447.             png_bytep dp;
  448.             int s_start, s_end, s_inc;
  449.             int m;
  450.             int shift;
  451.             png_uint_32 i;
  452.             int value;
  453.  
  454.             sp = png_ptr->row_buf + 1;
  455.             dp = row;
  456.             m = 0x80;
  457. #if defined(PNG_READ_PACKSWAP_SUPPORTED)
  458.             if (png_ptr->transformations & PNG_PACKSWAP)
  459.             {
  460.                s_start = 0;
  461.                s_end = 6;
  462.                s_inc = 2;
  463.             }
  464.             else
  465. #endif
  466.             {
  467.                s_start = 6;
  468.                s_end = 0;
  469.                s_inc = -2;
  470.             }
  471.  
  472.             shift = s_start;
  473.  
  474.             for (i = 0; i < png_ptr->width; i++)
  475.             {
  476.                if (m & mask)
  477.                {
  478.                   value = (*sp >> shift) & 0x3;
  479.                   *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
  480.                   *dp |= (png_byte)(value << shift);
  481.                }
  482.  
  483.                if (shift == s_end)
  484.                {
  485.                   shift = s_start;
  486.                   sp++;
  487.                   dp++;
  488.                }
  489.                else
  490.                   shift += s_inc;
  491.                if (m == 1)
  492.                   m = 0x80;
  493.                else
  494.                   m >>= 1;
  495.             }
  496.             break;
  497.          }
  498.  
  499.          case 4:        /* png_ptr->row_info.pixel_depth */
  500.          {
  501.             png_bytep sp;
  502.             png_bytep dp;
  503.             int s_start, s_end, s_inc;
  504.             int m;
  505.             int shift;
  506.             png_uint_32 i;
  507.             int value;
  508.  
  509.             sp = png_ptr->row_buf + 1;
  510.             dp = row;
  511.             m = 0x80;
  512. #if defined(PNG_READ_PACKSWAP_SUPPORTED)
  513.             if (png_ptr->transformations & PNG_PACKSWAP)
  514.             {
  515.                s_start = 0;
  516.                s_end = 4;
  517.                s_inc = 4;
  518.             }
  519.             else
  520. #endif
  521.             {
  522.                s_start = 4;
  523.                s_end = 0;
  524.                s_inc = -4;
  525.             }
  526.             shift = s_start;
  527.  
  528.             for (i = 0; i < png_ptr->width; i++)
  529.             {
  530.                if (m & mask)
  531.                {
  532.                   value = (*sp >> shift) & 0xf;
  533.                   *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
  534.                   *dp |= (png_byte)(value << shift);
  535.                }
  536.  
  537.                if (shift == s_end)
  538.                {
  539.                   shift = s_start;
  540.                   sp++;
  541.                   dp++;
  542.                }
  543.                else
  544.                   shift += s_inc;
  545.                if (m == 1)
  546.                   m = 0x80;
  547.                else
  548.                   m >>= 1;
  549.             }
  550.             break;
  551.          }
  552.  
  553.          case 8:        /* png_ptr->row_info.pixel_depth */
  554.          {
  555.             png_bytep srcptr;
  556.             png_bytep dstptr;
  557.  
  558. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
  559.             if ( _mmx_supported  )
  560.             {
  561.                png_uint_32 len;
  562.                int diff;
  563.                int dummy_value_a;   // fix 'forbidden register spilled' error
  564.                int dummy_value_d;
  565.                int dummy_value_c;
  566.                int dummy_value_S;
  567.                int dummy_value_D;
  568.                _unmask = ~mask;            // global variable for -fPIC version
  569.                srcptr = png_ptr->row_buf + 1;
  570.                dstptr = row;
  571.                len  = png_ptr->width &~7;  // reduce to multiple of 8
  572.                diff = (int) (png_ptr->width & 7);  // amount lost
  573.  
  574.                __asm__ __volatile__ (
  575.                   "movd      _unmask, %%mm7  \n\t" // load bit pattern
  576.                   "psubb     %%mm6, %%mm6    \n\t" // zero mm6
  577.                   "punpcklbw %%mm7, %%mm7    \n\t"
  578.                   "punpcklwd %%mm7, %%mm7    \n\t"
  579.                   "punpckldq %%mm7, %%mm7    \n\t" // fill reg with 8 masks
  580.  
  581.                   "movq      _mask8_0, %%mm0 \n\t"
  582.                   "pand      %%mm7, %%mm0    \n\t" // nonzero if keep byte
  583.                   "pcmpeqb   %%mm6, %%mm0    \n\t" // zeros->1s, v versa
  584.  
  585. // preload        "movl      len, %%ecx      \n\t" // load length of line
  586. // preload        "movl      srcptr, %%esi   \n\t" // load source
  587. // preload        "movl      dstptr, %%edi   \n\t" // load dest
  588.  
  589.                   "cmpl      $0, %%ecx       \n\t" // len == 0 ?
  590.                   "je        mainloop8end    \n\t"
  591.  
  592.                 "mainloop8:                  \n\t"
  593.                   "movq      (%%esi), %%mm4  \n\t" // *srcptr
  594.                   "pand      %%mm0, %%mm4    \n\t"
  595.                   "movq      %%mm0, %%mm6    \n\t"
  596.                   "pandn     (%%edi), %%mm6  \n\t" // *dstptr
  597.                   "por       %%mm6, %%mm4    \n\t"
  598.                   "movq      %%mm4, (%%edi)  \n\t"
  599.                   "addl      $8, %%esi       \n\t" // inc by 8 bytes processed
  600.                   "addl      $8, %%edi       \n\t"
  601.                   "subl      $8, %%ecx       \n\t" // dec by 8 pixels processed
  602.                   "ja        mainloop8       \n\t"
  603.  
  604.                 "mainloop8end:               \n\t"
  605. // preload        "movl      diff, %%ecx     \n\t" // (diff is in eax)
  606.                   "movl      %%eax, %%ecx    \n\t"
  607.                   "cmpl      $0, %%ecx       \n\t"
  608.                   "jz        end8            \n\t"
  609. // preload        "movl      mask, %%edx     \n\t"
  610.                   "sall      $24, %%edx      \n\t" // make low byte, high byte
  611.  
  612.                 "secondloop8:                \n\t"
  613.                   "sall      %%edx           \n\t" // move high bit to CF
  614.                   "jnc       skip8           \n\t" // if CF = 0
  615.                   "movb      (%%esi), %%al   \n\t"
  616.                   "movb      %%al, (%%edi)   \n\t"
  617.  
  618.                 "skip8:                      \n\t"
  619.                   "incl      %%esi           \n\t"
  620.                   "incl      %%edi           \n\t"
  621.                   "decl      %%ecx           \n\t"
  622.                   "jnz       secondloop8     \n\t"
  623.  
  624.                 "end8:                       \n\t"
  625.                   "EMMS                      \n\t"  // DONE
  626.  
  627.                   : "=a" (dummy_value_a),           // output regs (dummy)
  628.                     "=d" (dummy_value_d),
  629.                     "=c" (dummy_value_c),
  630.                     "=S" (dummy_value_S),
  631.                     "=D" (dummy_value_D)
  632.  
  633.                   : "3" (srcptr),      // esi       // input regs
  634.                     "4" (dstptr),      // edi
  635.                     "0" (diff),        // eax
  636. // was (unmask)     "b"    RESERVED    // ebx       // Global Offset Table idx
  637.                     "2" (len),         // ecx
  638.                     "1" (mask)         // edx
  639.  
  640. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  641.                   : "%mm0", "%mm4", "%mm6", "%mm7"  // clobber list
  642. #endif
  643.                );
  644.             }
  645.             else /* mmx _not supported - Use modified C routine */
  646. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  647.             {
  648.                register png_uint_32 i;
  649.                png_uint_32 initial_val = png_pass_start[png_ptr->pass];
  650.                  /* png.c:  png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
  651.                register int stride = png_pass_inc[png_ptr->pass];
  652.                  /* png.c:  png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
  653.                register int rep_bytes = png_pass_width[png_ptr->pass];
  654.                  /* png.c:  png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
  655.                png_uint_32 len = png_ptr->width &~7;  /* reduce to mult. of 8 */
  656.                int diff = (int) (png_ptr->width & 7); /* amount lost */
  657.                register png_uint_32 final_val = len;  /* GRR bugfix */
  658.  
  659.                srcptr = png_ptr->row_buf + 1 + initial_val;
  660.                dstptr = row + initial_val;
  661.  
  662.                for (i = initial_val; i < final_val; i += stride)
  663.                {
  664.                   png_memcpy(dstptr, srcptr, rep_bytes);
  665.                   srcptr += stride;
  666.                   dstptr += stride;
  667.                }
  668.                if (diff)  /* number of leftover pixels:  3 for pngtest */
  669.                {
  670.                   final_val+=diff /* *BPP1 */ ;
  671.                   for (; i < final_val; i += stride)
  672.                   {
  673.                      if (rep_bytes > (int)(final_val-i))
  674.                         rep_bytes = (int)(final_val-i);
  675.                      png_memcpy(dstptr, srcptr, rep_bytes);
  676.                      srcptr += stride;
  677.                      dstptr += stride;
  678.                   }
  679.                }
  680.  
  681.             } /* end of else (_mmx_supported) */
  682.  
  683.             break;
  684.          }       /* end 8 bpp */
  685.  
  686.          case 16:       /* png_ptr->row_info.pixel_depth */
  687.          {
  688.             png_bytep srcptr;
  689.             png_bytep dstptr;
  690.  
  691. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
  692.             if ( _mmx_supported )
  693.             {
  694.                png_uint_32 len;
  695.                int diff;
  696.                int dummy_value_a;   // fix 'forbidden register spilled' error
  697.                int dummy_value_d;
  698.                int dummy_value_c;
  699.                int dummy_value_S;
  700.                int dummy_value_D;
  701.                _unmask = ~mask;            // global variable for -fPIC version
  702.                srcptr = png_ptr->row_buf + 1;
  703.                dstptr = row;
  704.                len  = png_ptr->width &~7;  // reduce to multiple of 8
  705.                diff = (int) (png_ptr->width & 7); // amount lost //
  706.  
  707.                __asm__ __volatile__ (
  708.                   "movd      _unmask, %%mm7   \n\t" // load bit pattern
  709.                   "psubb     %%mm6, %%mm6     \n\t" // zero mm6
  710.                   "punpcklbw %%mm7, %%mm7     \n\t"
  711.                   "punpcklwd %%mm7, %%mm7     \n\t"
  712.                   "punpckldq %%mm7, %%mm7     \n\t" // fill reg with 8 masks
  713.  
  714.                   "movq      _mask16_0, %%mm0 \n\t"
  715.                   "movq      _mask16_1, %%mm1 \n\t"
  716.  
  717.                   "pand      %%mm7, %%mm0     \n\t"
  718.                   "pand      %%mm7, %%mm1     \n\t"
  719.  
  720.                   "pcmpeqb   %%mm6, %%mm0     \n\t"
  721.                   "pcmpeqb   %%mm6, %%mm1     \n\t"
  722.  
  723. // preload        "movl      len, %%ecx       \n\t" // load length of line
  724. // preload        "movl      srcptr, %%esi    \n\t" // load source
  725. // preload        "movl      dstptr, %%edi    \n\t" // load dest
  726.  
  727.                   "cmpl      $0, %%ecx        \n\t"
  728.                   "jz        mainloop16end    \n\t"
  729.  
  730.                 "mainloop16:                  \n\t"
  731.                   "movq      (%%esi), %%mm4   \n\t"
  732.                   "pand      %%mm0, %%mm4     \n\t"
  733.                   "movq      %%mm0, %%mm6     \n\t"
  734.                   "movq      (%%edi), %%mm7   \n\t"
  735.                   "pandn     %%mm7, %%mm6     \n\t"
  736.                   "por       %%mm6, %%mm4     \n\t"
  737.                   "movq      %%mm4, (%%edi)   \n\t"
  738.  
  739.                   "movq      8(%%esi), %%mm5  \n\t"
  740.                   "pand      %%mm1, %%mm5     \n\t"
  741.                   "movq      %%mm1, %%mm7     \n\t"
  742.                   "movq      8(%%edi), %%mm6  \n\t"
  743.                   "pandn     %%mm6, %%mm7     \n\t"
  744.                   "por       %%mm7, %%mm5     \n\t"
  745.                   "movq      %%mm5, 8(%%edi)  \n\t"
  746.  
  747.                   "addl      $16, %%esi       \n\t" // inc by 16 bytes processed
  748.                   "addl      $16, %%edi       \n\t"
  749.                   "subl      $8, %%ecx        \n\t" // dec by 8 pixels processed
  750.                   "ja        mainloop16       \n\t"
  751.  
  752.                 "mainloop16end:               \n\t"
  753. // preload        "movl      diff, %%ecx      \n\t" // (diff is in eax)
  754.                   "movl      %%eax, %%ecx     \n\t"
  755.                   "cmpl      $0, %%ecx        \n\t"
  756.                   "jz        end16            \n\t"
  757. // preload        "movl      mask, %%edx      \n\t"
  758.                   "sall      $24, %%edx       \n\t" // make low byte, high byte
  759.  
  760.                 "secondloop16:                \n\t"
  761.                   "sall      %%edx            \n\t" // move high bit to CF
  762.                   "jnc       skip16           \n\t" // if CF = 0
  763.                   "movw      (%%esi), %%ax    \n\t"
  764.                   "movw      %%ax, (%%edi)    \n\t"
  765.  
  766.                 "skip16:                      \n\t"
  767.                   "addl      $2, %%esi        \n\t"
  768.                   "addl      $2, %%edi        \n\t"
  769.                   "decl      %%ecx            \n\t"
  770.                   "jnz       secondloop16     \n\t"
  771.  
  772.                 "end16:                       \n\t"
  773.                   "EMMS                       \n\t" // DONE
  774.  
  775.                   : "=a" (dummy_value_a),           // output regs (dummy)
  776.                     "=c" (dummy_value_c),
  777.                     "=d" (dummy_value_d),
  778.                     "=S" (dummy_value_S),
  779.                     "=D" (dummy_value_D)
  780.  
  781.                   : "0" (diff),        // eax       // input regs
  782. // was (unmask)     " "    RESERVED    // ebx       // Global Offset Table idx
  783.                     "1" (len),         // ecx
  784.                     "2" (mask),        // edx
  785.                     "3" (srcptr),      // esi
  786.                     "4" (dstptr)       // edi
  787.  
  788. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  789.                   : "%mm0", "%mm1", "%mm4"          // clobber list
  790.                   , "%mm5", "%mm6", "%mm7"
  791. #endif
  792.                );
  793.             }
  794.             else /* mmx _not supported - Use modified C routine */
  795. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  796.             {
  797.                register png_uint_32 i;
  798.                png_uint_32 initial_val = BPP2 * png_pass_start[png_ptr->pass];
  799.                  /* png.c:  png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
  800.                register int stride = BPP2 * png_pass_inc[png_ptr->pass];
  801.                  /* png.c:  png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
  802.                register int rep_bytes = BPP2 * png_pass_width[png_ptr->pass];
  803.                  /* png.c:  png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
  804.                png_uint_32 len = png_ptr->width &~7;  /* reduce to mult. of 8 */
  805.                int diff = (int) (png_ptr->width & 7); /* amount lost */
  806.                register png_uint_32 final_val = BPP2 * len;   /* GRR bugfix */
  807.  
  808.                srcptr = png_ptr->row_buf + 1 + initial_val;
  809.                dstptr = row + initial_val;
  810.  
  811.                for (i = initial_val; i < final_val; i += stride)
  812.                {
  813.                   png_memcpy(dstptr, srcptr, rep_bytes);
  814.                   srcptr += stride;
  815.                   dstptr += stride;
  816.                }
  817.                if (diff)  /* number of leftover pixels:  3 for pngtest */
  818.                {
  819.                   final_val+=diff*BPP2;
  820.                   for (; i < final_val; i += stride)
  821.                   {
  822.                      if (rep_bytes > (int)(final_val-i))
  823.                         rep_bytes = (int)(final_val-i);
  824.                      png_memcpy(dstptr, srcptr, rep_bytes);
  825.                      srcptr += stride;
  826.                      dstptr += stride;
  827.                   }
  828.                }
  829.             } /* end of else (_mmx_supported) */
  830.  
  831.             break;
  832.          }       /* end 16 bpp */
  833.  
  834.          case 24:       /* png_ptr->row_info.pixel_depth */
  835.          {
  836.             png_bytep srcptr;
  837.             png_bytep dstptr;
  838.  
  839. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
  840.             if ( _mmx_supported )
  841.             {
  842.                png_uint_32 len;
  843.                int diff;
  844.                int dummy_value_a;   // fix 'forbidden register spilled' error
  845.                int dummy_value_d;
  846.                int dummy_value_c;
  847.                int dummy_value_S;
  848.                int dummy_value_D;
  849.                _unmask = ~mask;            // global variable for -fPIC version
  850.                srcptr = png_ptr->row_buf + 1;
  851.                dstptr = row;
  852.                len  = png_ptr->width &~7;  // reduce to multiple of 8
  853.                diff = (int) (png_ptr->width & 7); // amount lost //
  854.  
  855.                __asm__ __volatile__ (
  856.                   "movd      _unmask, %%mm7   \n\t" // load bit pattern
  857.                   "psubb     %%mm6, %%mm6     \n\t" // zero mm6
  858.                   "punpcklbw %%mm7, %%mm7     \n\t"
  859.                   "punpcklwd %%mm7, %%mm7     \n\t"
  860.                   "punpckldq %%mm7, %%mm7     \n\t" // fill reg with 8 masks
  861.  
  862.                   "movq      _mask24_0, %%mm0 \n\t"
  863.                   "movq      _mask24_1, %%mm1 \n\t"
  864.                   "movq      _mask24_2, %%mm2 \n\t"
  865.  
  866.                   "pand      %%mm7, %%mm0     \n\t"
  867.                   "pand      %%mm7, %%mm1     \n\t"
  868.                   "pand      %%mm7, %%mm2     \n\t"
  869.  
  870.                   "pcmpeqb   %%mm6, %%mm0     \n\t"
  871.                   "pcmpeqb   %%mm6, %%mm1     \n\t"
  872.                   "pcmpeqb   %%mm6, %%mm2     \n\t"
  873.  
  874. // preload        "movl      len, %%ecx       \n\t" // load length of line
  875. // preload        "movl      srcptr, %%esi    \n\t" // load source
  876. // preload        "movl      dstptr, %%edi    \n\t" // load dest
  877.  
  878.                   "cmpl      $0, %%ecx        \n\t"
  879.                   "jz        mainloop24end    \n\t"
  880.  
  881.                 "mainloop24:                  \n\t"
  882.                   "movq      (%%esi), %%mm4   \n\t"
  883.                   "pand      %%mm0, %%mm4     \n\t"
  884.                   "movq      %%mm0, %%mm6     \n\t"
  885.                   "movq      (%%edi), %%mm7   \n\t"
  886.                   "pandn     %%mm7, %%mm6     \n\t"
  887.                   "por       %%mm6, %%mm4     \n\t"
  888.                   "movq      %%mm4, (%%edi)   \n\t"
  889.  
  890.                   "movq      8(%%esi), %%mm5  \n\t"
  891.                   "pand      %%mm1, %%mm5     \n\t"
  892.                   "movq      %%mm1, %%mm7     \n\t"
  893.                   "movq      8(%%edi), %%mm6  \n\t"
  894.                   "pandn     %%mm6, %%mm7     \n\t"
  895.                   "por       %%mm7, %%mm5     \n\t"
  896.                   "movq      %%mm5, 8(%%edi)  \n\t"
  897.  
  898.                   "movq      16(%%esi), %%mm6 \n\t"
  899.                   "pand      %%mm2, %%mm6     \n\t"
  900.                   "movq      %%mm2, %%mm4     \n\t"
  901.                   "movq      16(%%edi), %%mm7 \n\t"
  902.                   "pandn     %%mm7, %%mm4     \n\t"
  903.                   "por       %%mm4, %%mm6     \n\t"
  904.                   "movq      %%mm6, 16(%%edi) \n\t"
  905.  
  906.                   "addl      $24, %%esi       \n\t" // inc by 24 bytes processed
  907.                   "addl      $24, %%edi       \n\t"
  908.                   "subl      $8, %%ecx        \n\t" // dec by 8 pixels processed
  909.  
  910.                   "ja        mainloop24       \n\t"
  911.  
  912.                 "mainloop24end:               \n\t"
  913. // preload        "movl      diff, %%ecx      \n\t" // (diff is in eax)
  914.                   "movl      %%eax, %%ecx     \n\t"
  915.                   "cmpl      $0, %%ecx        \n\t"
  916.                   "jz        end24            \n\t"
  917. // preload        "movl      mask, %%edx      \n\t"
  918.                   "sall      $24, %%edx       \n\t" // make low byte, high byte
  919.  
  920.                 "secondloop24:                \n\t"
  921.                   "sall      %%edx            \n\t" // move high bit to CF
  922.                   "jnc       skip24           \n\t" // if CF = 0
  923.                   "movw      (%%esi), %%ax    \n\t"
  924.                   "movw      %%ax, (%%edi)    \n\t"
  925.                   "xorl      %%eax, %%eax     \n\t"
  926.                   "movb      2(%%esi), %%al   \n\t"
  927.                   "movb      %%al, 2(%%edi)   \n\t"
  928.  
  929.                 "skip24:                      \n\t"
  930.                   "addl      $3, %%esi        \n\t"
  931.                   "addl      $3, %%edi        \n\t"
  932.                   "decl      %%ecx            \n\t"
  933.                   "jnz       secondloop24     \n\t"
  934.  
  935.                 "end24:                       \n\t"
  936.                   "EMMS                       \n\t" // DONE
  937.  
  938.                   : "=a" (dummy_value_a),           // output regs (dummy)
  939.                     "=d" (dummy_value_d),
  940.                     "=c" (dummy_value_c),
  941.                     "=S" (dummy_value_S),
  942.                     "=D" (dummy_value_D)
  943.  
  944.                   : "3" (srcptr),      // esi       // input regs
  945.                     "4" (dstptr),      // edi
  946.                     "0" (diff),        // eax
  947. // was (unmask)     "b"    RESERVED    // ebx       // Global Offset Table idx
  948.                     "2" (len),         // ecx
  949.                     "1" (mask)         // edx
  950.  
  951. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  952.                   : "%mm0", "%mm1", "%mm2"          // clobber list
  953.                   , "%mm4", "%mm5", "%mm6", "%mm7"
  954. #endif
  955.                );
  956.             }
  957.             else /* mmx _not supported - Use modified C routine */
  958. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  959.             {
  960.                register png_uint_32 i;
  961.                png_uint_32 initial_val = BPP3 * png_pass_start[png_ptr->pass];
  962.                  /* png.c:  png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
  963.                register int stride = BPP3 * png_pass_inc[png_ptr->pass];
  964.                  /* png.c:  png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
  965.                register int rep_bytes = BPP3 * png_pass_width[png_ptr->pass];
  966.                  /* png.c:  png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
  967.                png_uint_32 len = png_ptr->width &~7;  /* reduce to mult. of 8 */
  968.                int diff = (int) (png_ptr->width & 7); /* amount lost */
  969.                register png_uint_32 final_val = BPP3 * len;   /* GRR bugfix */
  970.  
  971.                srcptr = png_ptr->row_buf + 1 + initial_val;
  972.                dstptr = row + initial_val;
  973.  
  974.                for (i = initial_val; i < final_val; i += stride)
  975.                {
  976.                   png_memcpy(dstptr, srcptr, rep_bytes);
  977.                   srcptr += stride;
  978.                   dstptr += stride;
  979.                }
  980.                if (diff)  /* number of leftover pixels:  3 for pngtest */
  981.                {
  982.                   final_val+=diff*BPP3;
  983.                   for (; i < final_val; i += stride)
  984.                   {
  985.                      if (rep_bytes > (int)(final_val-i))
  986.                         rep_bytes = (int)(final_val-i);
  987.                      png_memcpy(dstptr, srcptr, rep_bytes);
  988.                      srcptr += stride;
  989.                      dstptr += stride;
  990.                   }
  991.                }
  992.             } /* end of else (_mmx_supported) */
  993.  
  994.             break;
  995.          }       /* end 24 bpp */
  996.  
  997.          case 32:       /* png_ptr->row_info.pixel_depth */
  998.          {
  999.             png_bytep srcptr;
  1000.             png_bytep dstptr;
  1001.  
  1002. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
  1003.             if ( _mmx_supported )
  1004.             {
  1005.                png_uint_32 len;
  1006.                int diff;
  1007.                int dummy_value_a;   // fix 'forbidden register spilled' error
  1008.                int dummy_value_d;
  1009.                int dummy_value_c;
  1010.                int dummy_value_S;
  1011.                int dummy_value_D;
  1012.                _unmask = ~mask;            // global variable for -fPIC version
  1013.                srcptr = png_ptr->row_buf + 1;
  1014.                dstptr = row;
  1015.                len  = png_ptr->width &~7;  // reduce to multiple of 8
  1016.                diff = (int) (png_ptr->width & 7); // amount lost //
  1017.  
  1018.                __asm__ __volatile__ (
  1019.                   "movd      _unmask, %%mm7   \n\t" // load bit pattern
  1020.                   "psubb     %%mm6, %%mm6     \n\t" // zero mm6
  1021.                   "punpcklbw %%mm7, %%mm7     \n\t"
  1022.                   "punpcklwd %%mm7, %%mm7     \n\t"
  1023.                   "punpckldq %%mm7, %%mm7     \n\t" // fill reg with 8 masks
  1024.  
  1025.                   "movq      _mask32_0, %%mm0 \n\t"
  1026.                   "movq      _mask32_1, %%mm1 \n\t"
  1027.                   "movq      _mask32_2, %%mm2 \n\t"
  1028.                   "movq      _mask32_3, %%mm3 \n\t"
  1029.  
  1030.                   "pand      %%mm7, %%mm0     \n\t"
  1031.                   "pand      %%mm7, %%mm1     \n\t"
  1032.                   "pand      %%mm7, %%mm2     \n\t"
  1033.                   "pand      %%mm7, %%mm3     \n\t"
  1034.  
  1035.                   "pcmpeqb   %%mm6, %%mm0     \n\t"
  1036.                   "pcmpeqb   %%mm6, %%mm1     \n\t"
  1037.                   "pcmpeqb   %%mm6, %%mm2     \n\t"
  1038.                   "pcmpeqb   %%mm6, %%mm3     \n\t"
  1039.  
  1040. // preload        "movl      len, %%ecx       \n\t" // load length of line
  1041. // preload        "movl      srcptr, %%esi    \n\t" // load source
  1042. // preload        "movl      dstptr, %%edi    \n\t" // load dest
  1043.  
  1044.                   "cmpl      $0, %%ecx        \n\t" // lcr
  1045.                   "jz        mainloop32end    \n\t"
  1046.  
  1047.                 "mainloop32:                  \n\t"
  1048.                   "movq      (%%esi), %%mm4   \n\t"
  1049.                   "pand      %%mm0, %%mm4     \n\t"
  1050.                   "movq      %%mm0, %%mm6     \n\t"
  1051.                   "movq      (%%edi), %%mm7   \n\t"
  1052.                   "pandn     %%mm7, %%mm6     \n\t"
  1053.                   "por       %%mm6, %%mm4     \n\t"
  1054.                   "movq      %%mm4, (%%edi)   \n\t"
  1055.  
  1056.                   "movq      8(%%esi), %%mm5  \n\t"
  1057.                   "pand      %%mm1, %%mm5     \n\t"
  1058.                   "movq      %%mm1, %%mm7     \n\t"
  1059.                   "movq      8(%%edi), %%mm6  \n\t"
  1060.                   "pandn     %%mm6, %%mm7     \n\t"
  1061.                   "por       %%mm7, %%mm5     \n\t"
  1062.                   "movq      %%mm5, 8(%%edi)  \n\t"
  1063.  
  1064.                   "movq      16(%%esi), %%mm6 \n\t"
  1065.                   "pand      %%mm2, %%mm6     \n\t"
  1066.                   "movq      %%mm2, %%mm4     \n\t"
  1067.                   "movq      16(%%edi), %%mm7 \n\t"
  1068.                   "pandn     %%mm7, %%mm4     \n\t"
  1069.                   "por       %%mm4, %%mm6     \n\t"
  1070.                   "movq      %%mm6, 16(%%edi) \n\t"
  1071.  
  1072.                   "movq      24(%%esi), %%mm7 \n\t"
  1073.                   "pand      %%mm3, %%mm7     \n\t"
  1074.                   "movq      %%mm3, %%mm5     \n\t"
  1075.                   "movq      24(%%edi), %%mm4 \n\t"
  1076.                   "pandn     %%mm4, %%mm5     \n\t"
  1077.                   "por       %%mm5, %%mm7     \n\t"
  1078.                   "movq      %%mm7, 24(%%edi) \n\t"
  1079.  
  1080.                   "addl      $32, %%esi       \n\t" // inc by 32 bytes processed
  1081.                   "addl      $32, %%edi       \n\t"
  1082.                   "subl      $8, %%ecx        \n\t" // dec by 8 pixels processed
  1083.                   "ja        mainloop32       \n\t"
  1084.  
  1085.                 "mainloop32end:               \n\t"
  1086. // preload        "movl      diff, %%ecx      \n\t" // (diff is in eax)
  1087.                   "movl      %%eax, %%ecx     \n\t"
  1088.                   "cmpl      $0, %%ecx        \n\t"
  1089.                   "jz        end32            \n\t"
  1090. // preload        "movl      mask, %%edx      \n\t"
  1091.                   "sall      $24, %%edx       \n\t" // low byte => high byte
  1092.  
  1093.                 "secondloop32:                \n\t"
  1094.                   "sall      %%edx            \n\t" // move high bit to CF
  1095.                   "jnc       skip32           \n\t" // if CF = 0
  1096.                   "movl      (%%esi), %%eax   \n\t"
  1097.                   "movl      %%eax, (%%edi)   \n\t"
  1098.  
  1099.                 "skip32:                      \n\t"
  1100.                   "addl      $4, %%esi        \n\t"
  1101.                   "addl      $4, %%edi        \n\t"
  1102.                   "decl      %%ecx            \n\t"
  1103.                   "jnz       secondloop32     \n\t"
  1104.  
  1105.                 "end32:                       \n\t"
  1106.                   "EMMS                       \n\t" // DONE
  1107.  
  1108.                   : "=a" (dummy_value_a),           // output regs (dummy)
  1109.                     "=d" (dummy_value_d),
  1110.                     "=c" (dummy_value_c),
  1111.                     "=S" (dummy_value_S),
  1112.                     "=D" (dummy_value_D)
  1113.  
  1114.                   : "3" (srcptr),      // esi       // input regs
  1115.                     "4" (dstptr),      // edi
  1116.                     "0" (diff),        // eax
  1117. // was (unmask)     "b"    RESERVED    // ebx       // Global Offset Table idx
  1118.                     "2" (len),         // ecx
  1119.                     "1" (mask)         // edx
  1120.  
  1121. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  1122.                   : "%mm0", "%mm1", "%mm2", "%mm3"  // clobber list
  1123.                   , "%mm4", "%mm5", "%mm6", "%mm7"
  1124. #endif
  1125.                );
  1126.             }
  1127.             else /* mmx _not supported - Use modified C routine */
  1128. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  1129.             {
  1130.                register png_uint_32 i;
  1131.                png_uint_32 initial_val = BPP4 * png_pass_start[png_ptr->pass];
  1132.                  /* png.c:  png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
  1133.                register int stride = BPP4 * png_pass_inc[png_ptr->pass];
  1134.                  /* png.c:  png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
  1135.                register int rep_bytes = BPP4 * png_pass_width[png_ptr->pass];
  1136.                  /* png.c:  png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
  1137.                png_uint_32 len = png_ptr->width &~7;  /* reduce to mult. of 8 */
  1138.                int diff = (int) (png_ptr->width & 7); /* amount lost */
  1139.                register png_uint_32 final_val = BPP4 * len;   /* GRR bugfix */
  1140.  
  1141.                srcptr = png_ptr->row_buf + 1 + initial_val;
  1142.                dstptr = row + initial_val;
  1143.  
  1144.                for (i = initial_val; i < final_val; i += stride)
  1145.                {
  1146.                   png_memcpy(dstptr, srcptr, rep_bytes);
  1147.                   srcptr += stride;
  1148.                   dstptr += stride;
  1149.                }
  1150.                if (diff)  /* number of leftover pixels:  3 for pngtest */
  1151.                {
  1152.                   final_val+=diff*BPP4;
  1153.                   for (; i < final_val; i += stride)
  1154.                   {
  1155.                      if (rep_bytes > (int)(final_val-i))
  1156.                         rep_bytes = (int)(final_val-i);
  1157.                      png_memcpy(dstptr, srcptr, rep_bytes);
  1158.                      srcptr += stride;
  1159.                      dstptr += stride;
  1160.                   }
  1161.                }
  1162.             } /* end of else (_mmx_supported) */
  1163.  
  1164.             break;
  1165.          }       /* end 32 bpp */
  1166.  
  1167.          case 48:       /* png_ptr->row_info.pixel_depth */
  1168.          {
  1169.             png_bytep srcptr;
  1170.             png_bytep dstptr;
  1171.  
  1172. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
  1173.             if ( _mmx_supported )
  1174.             {
  1175.                png_uint_32 len;
  1176.                int diff;
  1177.                int dummy_value_a;   // fix 'forbidden register spilled' error
  1178.                int dummy_value_d;
  1179.                int dummy_value_c;
  1180.                int dummy_value_S;
  1181.                int dummy_value_D;
  1182.                _unmask = ~mask;            // global variable for -fPIC version
  1183.                srcptr = png_ptr->row_buf + 1;
  1184.                dstptr = row;
  1185.                len  = png_ptr->width &~7;  // reduce to multiple of 8
  1186.                diff = (int) (png_ptr->width & 7); // amount lost //
  1187.  
  1188.                __asm__ __volatile__ (
  1189.                   "movd      _unmask, %%mm7   \n\t" // load bit pattern
  1190.                   "psubb     %%mm6, %%mm6     \n\t" // zero mm6
  1191.                   "punpcklbw %%mm7, %%mm7     \n\t"
  1192.                   "punpcklwd %%mm7, %%mm7     \n\t"
  1193.                   "punpckldq %%mm7, %%mm7     \n\t" // fill reg with 8 masks
  1194.  
  1195.                   "movq      _mask48_0, %%mm0 \n\t"
  1196.                   "movq      _mask48_1, %%mm1 \n\t"
  1197.                   "movq      _mask48_2, %%mm2 \n\t"
  1198.                   "movq      _mask48_3, %%mm3 \n\t"
  1199.                   "movq      _mask48_4, %%mm4 \n\t"
  1200.                   "movq      _mask48_5, %%mm5 \n\t"
  1201.  
  1202.                   "pand      %%mm7, %%mm0     \n\t"
  1203.                   "pand      %%mm7, %%mm1     \n\t"
  1204.                   "pand      %%mm7, %%mm2     \n\t"
  1205.                   "pand      %%mm7, %%mm3     \n\t"
  1206.                   "pand      %%mm7, %%mm4     \n\t"
  1207.                   "pand      %%mm7, %%mm5     \n\t"
  1208.  
  1209.                   "pcmpeqb   %%mm6, %%mm0     \n\t"
  1210.                   "pcmpeqb   %%mm6, %%mm1     \n\t"
  1211.                   "pcmpeqb   %%mm6, %%mm2     \n\t"
  1212.                   "pcmpeqb   %%mm6, %%mm3     \n\t"
  1213.                   "pcmpeqb   %%mm6, %%mm4     \n\t"
  1214.                   "pcmpeqb   %%mm6, %%mm5     \n\t"
  1215.  
  1216. // preload        "movl      len, %%ecx       \n\t" // load length of line
  1217. // preload        "movl      srcptr, %%esi    \n\t" // load source
  1218. // preload        "movl      dstptr, %%edi    \n\t" // load dest
  1219.  
  1220.                   "cmpl      $0, %%ecx        \n\t"
  1221.                   "jz        mainloop48end    \n\t"
  1222.  
  1223.                 "mainloop48:                  \n\t"
  1224.                   "movq      (%%esi), %%mm7   \n\t"
  1225.                   "pand      %%mm0, %%mm7     \n\t"
  1226.                   "movq      %%mm0, %%mm6     \n\t"
  1227.                   "pandn     (%%edi), %%mm6   \n\t"
  1228.                   "por       %%mm6, %%mm7     \n\t"
  1229.                   "movq      %%mm7, (%%edi)   \n\t"
  1230.  
  1231.                   "movq      8(%%esi), %%mm6  \n\t"
  1232.                   "pand      %%mm1, %%mm6     \n\t"
  1233.                   "movq      %%mm1, %%mm7     \n\t"
  1234.                   "pandn     8(%%edi), %%mm7  \n\t"
  1235.                   "por       %%mm7, %%mm6     \n\t"
  1236.                   "movq      %%mm6, 8(%%edi)  \n\t"
  1237.  
  1238.                   "movq      16(%%esi), %%mm6 \n\t"
  1239.                   "pand      %%mm2, %%mm6     \n\t"
  1240.                   "movq      %%mm2, %%mm7     \n\t"
  1241.                   "pandn     16(%%edi), %%mm7 \n\t"
  1242.                   "por       %%mm7, %%mm6     \n\t"
  1243.                   "movq      %%mm6, 16(%%edi) \n\t"
  1244.  
  1245.                   "movq      24(%%esi), %%mm7 \n\t"
  1246.                   "pand      %%mm3, %%mm7     \n\t"
  1247.                   "movq      %%mm3, %%mm6     \n\t"
  1248.                   "pandn     24(%%edi), %%mm6 \n\t"
  1249.                   "por       %%mm6, %%mm7     \n\t"
  1250.                   "movq      %%mm7, 24(%%edi) \n\t"
  1251.  
  1252.                   "movq      32(%%esi), %%mm6 \n\t"
  1253.                   "pand      %%mm4, %%mm6     \n\t"
  1254.                   "movq      %%mm4, %%mm7     \n\t"
  1255.                   "pandn     32(%%edi), %%mm7 \n\t"
  1256.                   "por       %%mm7, %%mm6     \n\t"
  1257.                   "movq      %%mm6, 32(%%edi) \n\t"
  1258.  
  1259.                   "movq      40(%%esi), %%mm7 \n\t"
  1260.                   "pand      %%mm5, %%mm7     \n\t"
  1261.                   "movq      %%mm5, %%mm6     \n\t"
  1262.                   "pandn     40(%%edi), %%mm6 \n\t"
  1263.                   "por       %%mm6, %%mm7     \n\t"
  1264.                   "movq      %%mm7, 40(%%edi) \n\t"
  1265.  
  1266.                   "addl      $48, %%esi       \n\t" // inc by 48 bytes processed
  1267.                   "addl      $48, %%edi       \n\t"
  1268.                   "subl      $8, %%ecx        \n\t" // dec by 8 pixels processed
  1269.  
  1270.                   "ja        mainloop48       \n\t"
  1271.  
  1272.                 "mainloop48end:               \n\t"
  1273. // preload        "movl      diff, %%ecx      \n\t" // (diff is in eax)
  1274.                   "movl      %%eax, %%ecx     \n\t"
  1275.                   "cmpl      $0, %%ecx        \n\t"
  1276.                   "jz        end48            \n\t"
  1277. // preload        "movl      mask, %%edx      \n\t"
  1278.                   "sall      $24, %%edx       \n\t" // make low byte, high byte
  1279.  
  1280.                 "secondloop48:                \n\t"
  1281.                   "sall      %%edx            \n\t" // move high bit to CF
  1282.                   "jnc       skip48           \n\t" // if CF = 0
  1283.                   "movl      (%%esi), %%eax   \n\t"
  1284.                   "movl      %%eax, (%%edi)   \n\t"
  1285.  
  1286.                 "skip48:                      \n\t"
  1287.                   "addl      $4, %%esi        \n\t"
  1288.                   "addl      $4, %%edi        \n\t"
  1289.                   "decl      %%ecx            \n\t"
  1290.                   "jnz       secondloop48     \n\t"
  1291.  
  1292.                 "end48:                       \n\t"
  1293.                   "EMMS                       \n\t" // DONE
  1294.  
  1295.                   : "=a" (dummy_value_a),           // output regs (dummy)
  1296.                     "=d" (dummy_value_d),
  1297.                     "=c" (dummy_value_c),
  1298.                     "=S" (dummy_value_S),
  1299.                     "=D" (dummy_value_D)
  1300.  
  1301.                   : "3" (srcptr),      // esi       // input regs
  1302.                     "4" (dstptr),      // edi
  1303.                     "0" (diff),        // eax
  1304. // was (unmask)     "b"    RESERVED    // ebx       // Global Offset Table idx
  1305.                     "2" (len),         // ecx
  1306.                     "1" (mask)         // edx
  1307.  
  1308. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  1309.                   : "%mm0", "%mm1", "%mm2", "%mm3"  // clobber list
  1310.                   , "%mm4", "%mm5", "%mm6", "%mm7"
  1311. #endif
  1312.                );
  1313.             }
  1314.             else /* mmx _not supported - Use modified C routine */
  1315. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  1316.             {
  1317.                register png_uint_32 i;
  1318.                png_uint_32 initial_val = BPP6 * png_pass_start[png_ptr->pass];
  1319.                  /* png.c:  png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
  1320.                register int stride = BPP6 * png_pass_inc[png_ptr->pass];
  1321.                  /* png.c:  png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
  1322.                register int rep_bytes = BPP6 * png_pass_width[png_ptr->pass];
  1323.                  /* png.c:  png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
  1324.                png_uint_32 len = png_ptr->width &~7;  /* reduce to mult. of 8 */
  1325.                int diff = (int) (png_ptr->width & 7); /* amount lost */
  1326.                register png_uint_32 final_val = BPP6 * len;   /* GRR bugfix */
  1327.  
  1328.                srcptr = png_ptr->row_buf + 1 + initial_val;
  1329.                dstptr = row + initial_val;
  1330.  
  1331.                for (i = initial_val; i < final_val; i += stride)
  1332.                {
  1333.                   png_memcpy(dstptr, srcptr, rep_bytes);
  1334.                   srcptr += stride;
  1335.                   dstptr += stride;
  1336.                }
  1337.                if (diff)  /* number of leftover pixels:  3 for pngtest */
  1338.                {
  1339.                   final_val+=diff*BPP6;
  1340.                   for (; i < final_val; i += stride)
  1341.                   {
  1342.                      if (rep_bytes > (int)(final_val-i))
  1343.                         rep_bytes = (int)(final_val-i);
  1344.                      png_memcpy(dstptr, srcptr, rep_bytes);
  1345.                      srcptr += stride;
  1346.                      dstptr += stride;
  1347.                   }
  1348.                }
  1349.             } /* end of else (_mmx_supported) */
  1350.  
  1351.             break;
  1352.          }       /* end 48 bpp */
  1353.  
  1354.          case 64:       /* png_ptr->row_info.pixel_depth */
  1355.          {
  1356.             png_bytep srcptr;
  1357.             png_bytep dstptr;
  1358.             register png_uint_32 i;
  1359.             png_uint_32 initial_val = BPP8 * png_pass_start[png_ptr->pass];
  1360.               /* png.c:  png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
  1361.             register int stride = BPP8 * png_pass_inc[png_ptr->pass];
  1362.               /* png.c:  png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
  1363.             register int rep_bytes = BPP8 * png_pass_width[png_ptr->pass];
  1364.               /* png.c:  png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
  1365.             png_uint_32 len = png_ptr->width &~7;  /* reduce to mult. of 8 */
  1366.             int diff = (int) (png_ptr->width & 7); /* amount lost */
  1367.             register png_uint_32 final_val = BPP8 * len;   /* GRR bugfix */
  1368.  
  1369.             srcptr = png_ptr->row_buf + 1 + initial_val;
  1370.             dstptr = row + initial_val;
  1371.  
  1372.             for (i = initial_val; i < final_val; i += stride)
  1373.             {
  1374.                png_memcpy(dstptr, srcptr, rep_bytes);
  1375.                srcptr += stride;
  1376.                dstptr += stride;
  1377.             }
  1378.             if (diff)  /* number of leftover pixels:  3 for pngtest */
  1379.             {
  1380.                final_val+=diff*BPP8;
  1381.                for (; i < final_val; i += stride)
  1382.                {
  1383.                   if (rep_bytes > (int)(final_val-i))
  1384.                      rep_bytes = (int)(final_val-i);
  1385.                   png_memcpy(dstptr, srcptr, rep_bytes);
  1386.                   srcptr += stride;
  1387.                   dstptr += stride;
  1388.                }
  1389.             }
  1390.  
  1391.             break;
  1392.          }       /* end 64 bpp */
  1393.  
  1394.          default: /* png_ptr->row_info.pixel_depth != 1,2,4,8,16,24,32,48,64 */
  1395.          {
  1396.             /* this should never happen */
  1397.             fprintf(stderr,
  1398.               "libpng internal error:  png_ptr->row_info.pixel_depth = %d\n",
  1399.               png_ptr->row_info.pixel_depth);
  1400.             fflush(stderr);
  1401.             break;
  1402.          }
  1403.       } /* end switch (png_ptr->row_info.pixel_depth) */
  1404.  
  1405.    } /* end if (non-trivial mask) */
  1406.  
  1407. } /* end png_combine_row() */
  1408.  
  1409. #endif /* PNG_HAVE_ASSEMBLER_COMBINE_ROW */
  1410.  
  1411.  
  1412.  
  1413.  
  1414. /*===========================================================================*/
  1415. /*                                                                           */
  1416. /*                 P N G _ D O _ R E A D _ I N T E R L A C E                 */
  1417. /*                                                                           */
  1418. /*===========================================================================*/
  1419.  
  1420. #if defined(PNG_READ_INTERLACING_SUPPORTED)
  1421. #if defined(PNG_HAVE_ASSEMBLER_READ_INTERLACE)
  1422.  
  1423. /* png_do_read_interlace() is called after any 16-bit to 8-bit conversion
  1424.  * has taken place.  [GRR: what other steps come before and/or after?]
  1425.  */
  1426.  
  1427. void /* PRIVATE */
  1428. png_do_read_interlace(png_structp png_ptr)
  1429. {
  1430.    png_row_infop row_info = &(png_ptr->row_info);
  1431.    png_bytep row = png_ptr->row_buf + 1;
  1432.    int pass = png_ptr->pass;
  1433. #if defined(PNG_READ_PACKSWAP_SUPPORTED)
  1434.    png_uint_32 transformations = png_ptr->transformations;
  1435. #endif
  1436.  
  1437.    png_debug(1, "in png_do_read_interlace (pnggccrd.c)\n");
  1438.  
  1439.    if (_mmx_supported == 2) {
  1440.        png_mmx_support();
  1441.    }
  1442.  
  1443.    if (row != NULL && row_info != NULL)
  1444.    {
  1445.       png_uint_32 final_width;
  1446.  
  1447.       final_width = row_info->width * png_pass_inc[pass];
  1448.  
  1449.       switch (row_info->pixel_depth)
  1450.       {
  1451.          case 1:
  1452.          {
  1453.             png_bytep sp, dp;
  1454.             int sshift, dshift;
  1455.             int s_start, s_end, s_inc;
  1456.             png_byte v;
  1457.             png_uint_32 i;
  1458.             int j;
  1459.  
  1460.             sp = row + (png_size_t)((row_info->width - 1) >> 3);
  1461.             dp = row + (png_size_t)((final_width - 1) >> 3);
  1462. #if defined(PNG_READ_PACKSWAP_SUPPORTED)
  1463.             if (transformations & PNG_PACKSWAP)
  1464.             {
  1465.                sshift = (int)((row_info->width + 7) & 7);
  1466.                dshift = (int)((final_width + 7) & 7);
  1467.                s_start = 7;
  1468.                s_end = 0;
  1469.                s_inc = -1;
  1470.             }
  1471.             else
  1472. #endif
  1473.             {
  1474.                sshift = 7 - (int)((row_info->width + 7) & 7);
  1475.                dshift = 7 - (int)((final_width + 7) & 7);
  1476.                s_start = 0;
  1477.                s_end = 7;
  1478.                s_inc = 1;
  1479.             }
  1480.  
  1481.             for (i = row_info->width; i; i--)
  1482.             {
  1483.                v = (png_byte)((*sp >> sshift) & 0x1);
  1484.                for (j = 0; j < png_pass_inc[pass]; j++)
  1485.                {
  1486.                   *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
  1487.                   *dp |= (png_byte)(v << dshift);
  1488.                   if (dshift == s_end)
  1489.                   {
  1490.                      dshift = s_start;
  1491.                      dp--;
  1492.                   }
  1493.                   else
  1494.                      dshift += s_inc;
  1495.                }
  1496.                if (sshift == s_end)
  1497.                {
  1498.                   sshift = s_start;
  1499.                   sp--;
  1500.                }
  1501.                else
  1502.                   sshift += s_inc;
  1503.             }
  1504.             break;
  1505.          }
  1506.  
  1507.          case 2:
  1508.          {
  1509.             png_bytep sp, dp;
  1510.             int sshift, dshift;
  1511.             int s_start, s_end, s_inc;
  1512.             png_uint_32 i;
  1513.  
  1514.             sp = row + (png_size_t)((row_info->width - 1) >> 2);
  1515.             dp = row + (png_size_t)((final_width - 1) >> 2);
  1516. #if defined(PNG_READ_PACKSWAP_SUPPORTED)
  1517.             if (transformations & PNG_PACKSWAP)
  1518.             {
  1519.                sshift = (png_size_t)(((row_info->width + 3) & 3) << 1);
  1520.                dshift = (png_size_t)(((final_width + 3) & 3) << 1);
  1521.                s_start = 6;
  1522.                s_end = 0;
  1523.                s_inc = -2;
  1524.             }
  1525.             else
  1526. #endif
  1527.             {
  1528.                sshift = (png_size_t)((3 - ((row_info->width + 3) & 3)) << 1);
  1529.                dshift = (png_size_t)((3 - ((final_width + 3) & 3)) << 1);
  1530.                s_start = 0;
  1531.                s_end = 6;
  1532.                s_inc = 2;
  1533.             }
  1534.  
  1535.             for (i = row_info->width; i; i--)
  1536.             {
  1537.                png_byte v;
  1538.                int j;
  1539.  
  1540.                v = (png_byte)((*sp >> sshift) & 0x3);
  1541.                for (j = 0; j < png_pass_inc[pass]; j++)
  1542.                {
  1543.                   *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
  1544.                   *dp |= (png_byte)(v << dshift);
  1545.                   if (dshift == s_end)
  1546.                   {
  1547.                      dshift = s_start;
  1548.                      dp--;
  1549.                   }
  1550.                   else
  1551.                      dshift += s_inc;
  1552.                }
  1553.                if (sshift == s_end)
  1554.                {
  1555.                   sshift = s_start;
  1556.                   sp--;
  1557.                }
  1558.                else
  1559.                   sshift += s_inc;
  1560.             }
  1561.             break;
  1562.          }
  1563.  
  1564.          case 4:
  1565.          {
  1566.             png_bytep sp, dp;
  1567.             int sshift, dshift;
  1568.             int s_start, s_end, s_inc;
  1569.             png_uint_32 i;
  1570.  
  1571.             sp = row + (png_size_t)((row_info->width - 1) >> 1);
  1572.             dp = row + (png_size_t)((final_width - 1) >> 1);
  1573. #if defined(PNG_READ_PACKSWAP_SUPPORTED)
  1574.             if (transformations & PNG_PACKSWAP)
  1575.             {
  1576.                sshift = (png_size_t)(((row_info->width + 1) & 1) << 2);
  1577.                dshift = (png_size_t)(((final_width + 1) & 1) << 2);
  1578.                s_start = 4;
  1579.                s_end = 0;
  1580.                s_inc = -4;
  1581.             }
  1582.             else
  1583. #endif
  1584.             {
  1585.                sshift = (png_size_t)((1 - ((row_info->width + 1) & 1)) << 2);
  1586.                dshift = (png_size_t)((1 - ((final_width + 1) & 1)) << 2);
  1587.                s_start = 0;
  1588.                s_end = 4;
  1589.                s_inc = 4;
  1590.             }
  1591.  
  1592.             for (i = row_info->width; i; i--)
  1593.             {
  1594.                png_byte v;
  1595.                int j;
  1596.  
  1597.                v = (png_byte)((*sp >> sshift) & 0xf);
  1598.                for (j = 0; j < png_pass_inc[pass]; j++)
  1599.                {
  1600.                   *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
  1601.                   *dp |= (png_byte)(v << dshift);
  1602.                   if (dshift == s_end)
  1603.                   {
  1604.                      dshift = s_start;
  1605.                      dp--;
  1606.                   }
  1607.                   else
  1608.                      dshift += s_inc;
  1609.                }
  1610.                if (sshift == s_end)
  1611.                {
  1612.                   sshift = s_start;
  1613.                   sp--;
  1614.                }
  1615.                else
  1616.                   sshift += s_inc;
  1617.             }
  1618.             break;
  1619.          }
  1620.  
  1621.        /*====================================================================*/
  1622.  
  1623.          default: /* 8-bit or larger (this is where the routine is modified) */
  1624.          {
  1625. #if 0
  1626. //          static unsigned long long _const4 = 0x0000000000FFFFFFLL;  no good
  1627. //          static unsigned long long const4 = 0x0000000000FFFFFFLL;   no good
  1628. //          unsigned long long _const4 = 0x0000000000FFFFFFLL;         no good
  1629. //          unsigned long long const4 = 0x0000000000FFFFFFLL;          no good
  1630. #endif
  1631.             png_bytep sptr, dp;
  1632.             png_uint_32 i;
  1633.             png_size_t pixel_bytes;
  1634.             int width = (int)row_info->width;
  1635.  
  1636.             pixel_bytes = (row_info->pixel_depth >> 3);
  1637.  
  1638.             /* point sptr at the last pixel in the pre-expanded row: */
  1639.             sptr = row + (width - 1) * pixel_bytes;
  1640.  
  1641.             /* point dp at the last pixel position in the expanded row: */
  1642.             dp = row + (final_width - 1) * pixel_bytes;
  1643.  
  1644.             /* New code by Nirav Chhatrapati - Intel Corporation */
  1645.  
  1646. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
  1647.             if ( _mmx_supported )
  1648.             {
  1649.                //--------------------------------------------------------------
  1650.                if (pixel_bytes == 3)
  1651.                {
  1652.                   if (((pass == 0) || (pass == 1)) && width)
  1653.                   {
  1654.                      int dummy_value_c;   // fix 'forbidden register spilled'
  1655.                      int dummy_value_S;
  1656.                      int dummy_value_D;
  1657.  
  1658.                      __asm__ __volatile__ (
  1659.                         "subl $21, %%edi         \n\t"
  1660.                                      // (png_pass_inc[pass] - 1)*pixel_bytes
  1661.  
  1662.                      ".loop3_pass0:              \n\t"
  1663.                         "movd (%%esi), %%mm0     \n\t" // x x x x x 2 1 0
  1664.                         "pand _const4, %%mm0     \n\t" // z z z z z 2 1 0
  1665.                         "movq %%mm0, %%mm1       \n\t" // z z z z z 2 1 0
  1666.                         "psllq $16, %%mm0        \n\t" // z z z 2 1 0 z z
  1667.                         "movq %%mm0, %%mm2       \n\t" // z z z 2 1 0 z z
  1668.                         "psllq $24, %%mm0        \n\t" // 2 1 0 z z z z z
  1669.                         "psrlq $8, %%mm1         \n\t" // z z z z z z 2 1
  1670.                         "por %%mm2, %%mm0        \n\t" // 2 1 0 2 1 0 z z
  1671.                         "por %%mm1, %%mm0        \n\t" // 2 1 0 2 1 0 2 1
  1672.                         "movq %%mm0, %%mm3       \n\t" // 2 1 0 2 1 0 2 1
  1673.                         "psllq $16, %%mm0        \n\t" // 0 2 1 0 2 1 z z
  1674.                         "movq %%mm3, %%mm4       \n\t" // 2 1 0 2 1 0 2 1
  1675.                         "punpckhdq %%mm0, %%mm3  \n\t" // 0 2 1 0 2 1 0 2
  1676.                         "movq %%mm4, 16(%%edi)   \n\t"
  1677.                         "psrlq $32, %%mm0        \n\t" // z z z z 0 2 1 0
  1678.                         "movq %%mm3, 8(%%edi)    \n\t"
  1679.                         "punpckldq %%mm4, %%mm0  \n\t" // 1 0 2 1 0 2 1 0
  1680.                         "subl $3, %%esi          \n\t"
  1681.                         "movq %%mm0, (%%edi)     \n\t"
  1682.                         "subl $24, %%edi         \n\t"
  1683.                         "decl %%ecx              \n\t"
  1684.                         "jnz .loop3_pass0        \n\t"
  1685.                         "EMMS                    \n\t" // DONE
  1686.  
  1687.                         : "=c" (dummy_value_c),        // output regs (dummy)
  1688.                           "=S" (dummy_value_S),
  1689.                           "=D" (dummy_value_D)
  1690.  
  1691.                         : "1" (sptr),      // esi      // input regs
  1692.                           "2" (dp),        // edi
  1693.                           "0" (width)      // ecx
  1694. // doesn't work           "i" (0x0000000000FFFFFFLL)   // %1 (a.k.a. _const4)
  1695.  
  1696. #if 0  /* %mm0, ..., %mm4 not supported by gcc 2.7.2.3 or egcs 1.1 */
  1697.                         : "%mm0", "%mm1", "%mm2"       // clobber list
  1698.                         , "%mm3", "%mm4"
  1699. #endif
  1700.                      );
  1701.                   }
  1702.                   else if (((pass == 2) || (pass == 3)) && width)
  1703.                   {
  1704.                      int dummy_value_c;   // fix 'forbidden register spilled'
  1705.                      int dummy_value_S;
  1706.                      int dummy_value_D;
  1707.  
  1708.                      __asm__ __volatile__ (
  1709.                         "subl $9, %%edi          \n\t"
  1710.                                      // (png_pass_inc[pass] - 1)*pixel_bytes
  1711.  
  1712.                      ".loop3_pass2:              \n\t"
  1713.                         "movd (%%esi), %%mm0     \n\t" // x x x x x 2 1 0
  1714.                         "pand _const4, %%mm0     \n\t" // z z z z z 2 1 0
  1715.                         "movq %%mm0, %%mm1       \n\t" // z z z z z 2 1 0
  1716.                         "psllq $16, %%mm0        \n\t" // z z z 2 1 0 z z
  1717.                         "movq %%mm0, %%mm2       \n\t" // z z z 2 1 0 z z
  1718.                         "psllq $24, %%mm0        \n\t" // 2 1 0 z z z z z
  1719.                         "psrlq $8, %%mm1         \n\t" // z z z z z z 2 1
  1720.                         "por %%mm2, %%mm0        \n\t" // 2 1 0 2 1 0 z z
  1721.                         "por %%mm1, %%mm0        \n\t" // 2 1 0 2 1 0 2 1
  1722.                         "movq %%mm0, 4(%%edi)    \n\t"
  1723.                         "psrlq $16, %%mm0        \n\t" // z z 2 1 0 2 1 0
  1724.                         "subl $3, %%esi          \n\t"
  1725.                         "movd %%mm0, (%%edi)     \n\t"
  1726.                         "subl $12, %%edi         \n\t"
  1727.                         "decl %%ecx              \n\t"
  1728.                         "jnz .loop3_pass2        \n\t"
  1729.                         "EMMS                    \n\t" // DONE
  1730.  
  1731.                         : "=c" (dummy_value_c),        // output regs (dummy)
  1732.                           "=S" (dummy_value_S),
  1733.                           "=D" (dummy_value_D)
  1734.  
  1735.                         : "1" (sptr),      // esi      // input regs
  1736.                           "2" (dp),        // edi
  1737.                           "0" (width)      // ecx
  1738.  
  1739. #if 0  /* %mm0, ..., %mm2 not supported by gcc 2.7.2.3 or egcs 1.1 */
  1740.                         : "%mm0", "%mm1", "%mm2"       // clobber list
  1741. #endif
  1742.                      );
  1743.                   }
  1744.                   else if (width) /* && ((pass == 4) || (pass == 5)) */
  1745.                   {
  1746.                      int width_mmx = ((width >> 1) << 1) - 8;   // GRR:  huh?
  1747.                      if (width_mmx < 0)
  1748.                          width_mmx = 0;
  1749.                      width -= width_mmx;        // 8 or 9 pix, 24 or 27 bytes
  1750.                      if (width_mmx)
  1751.                      {
  1752.                         // png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
  1753.                         // sptr points at last pixel in pre-expanded row
  1754.                         // dp points at last pixel position in expanded row
  1755.                         int dummy_value_c;  // fix 'forbidden register spilled'
  1756.                         int dummy_value_S;
  1757.                         int dummy_value_D;
  1758.  
  1759.                         __asm__ __volatile__ (
  1760.                            "subl $3, %%esi          \n\t"
  1761.                            "subl $9, %%edi          \n\t"
  1762.                                         // (png_pass_inc[pass] + 1)*pixel_bytes
  1763.  
  1764.                         ".loop3_pass4:              \n\t"
  1765.                            "movq (%%esi), %%mm0     \n\t" // x x 5 4 3 2 1 0
  1766.                            "movq %%mm0, %%mm1       \n\t" // x x 5 4 3 2 1 0
  1767.                            "movq %%mm0, %%mm2       \n\t" // x x 5 4 3 2 1 0
  1768.                            "psllq $24, %%mm0        \n\t" // 4 3 2 1 0 z z z
  1769.                            "pand _const4, %%mm1     \n\t" // z z z z z 2 1 0
  1770.                            "psrlq $24, %%mm2        \n\t" // z z z x x 5 4 3
  1771.                            "por %%mm1, %%mm0        \n\t" // 4 3 2 1 0 2 1 0
  1772.                            "movq %%mm2, %%mm3       \n\t" // z z z x x 5 4 3
  1773.                            "psllq $8, %%mm2         \n\t" // z z x x 5 4 3 z
  1774.                            "movq %%mm0, (%%edi)     \n\t"
  1775.                            "psrlq $16, %%mm3        \n\t" // z z z z z x x 5
  1776.                            "pand _const6, %%mm3     \n\t" // z z z z z z z 5
  1777.                            "por %%mm3, %%mm2        \n\t" // z z x x 5 4 3 5
  1778.                            "subl $6, %%esi          \n\t"
  1779.                            "movd %%mm2, 8(%%edi)    \n\t"
  1780.                            "subl $12, %%edi         \n\t"
  1781.                            "subl $2, %%ecx          \n\t"
  1782.                            "jnz .loop3_pass4        \n\t"
  1783.                            "EMMS                    \n\t" // DONE
  1784.  
  1785.                            : "=c" (dummy_value_c),        // output regs (dummy)
  1786.                              "=S" (dummy_value_S),
  1787.                              "=D" (dummy_value_D)
  1788.  
  1789.                            : "1" (sptr),      // esi      // input regs
  1790.                              "2" (dp),        // edi
  1791.                              "0" (width_mmx)  // ecx
  1792.  
  1793. #if 0  /* %mm0, ..., %mm3 not supported by gcc 2.7.2.3 or egcs 1.1 */
  1794.                            : "%mm0", "%mm1"               // clobber list
  1795.                            , "%mm2", "%mm3"
  1796. #endif
  1797.                         );
  1798.                      }
  1799.  
  1800.                      sptr -= width_mmx*3;
  1801.                      dp -= width_mmx*6;
  1802.                      for (i = width; i; i--)
  1803.                      {
  1804.                         png_byte v[8];
  1805.                         int j;
  1806.  
  1807.                         png_memcpy(v, sptr, 3);
  1808.                         for (j = 0; j < png_pass_inc[pass]; j++)
  1809.                         {
  1810.                            png_memcpy(dp, v, 3);
  1811.                            dp -= 3;
  1812.                         }
  1813.                         sptr -= 3;
  1814.                      }
  1815.                   }
  1816.                } /* end of pixel_bytes == 3 */
  1817.  
  1818.                //--------------------------------------------------------------
  1819.                else if (pixel_bytes == 1)
  1820.                {
  1821.                   if (((pass == 0) || (pass == 1)) && width)
  1822.                   {
  1823.                      int width_mmx = ((width >> 2) << 2);
  1824.                      width -= width_mmx;        // 0-3 pixels => 0-3 bytes
  1825.                      if (width_mmx)
  1826.                      {
  1827.                         int dummy_value_c;  // fix 'forbidden register spilled'
  1828.                         int dummy_value_S;
  1829.                         int dummy_value_D;
  1830.  
  1831.                         __asm__ __volatile__ (
  1832.                            "subl $3, %%esi          \n\t"
  1833.                            "subl $31, %%edi         \n\t"
  1834.  
  1835.                         ".loop1_pass0:              \n\t"
  1836.                            "movd (%%esi), %%mm0     \n\t" // x x x x 3 2 1 0
  1837.                            "movq %%mm0, %%mm1       \n\t" // x x x x 3 2 1 0
  1838.                            "punpcklbw %%mm0, %%mm0  \n\t" // 3 3 2 2 1 1 0 0
  1839.                            "movq %%mm0, %%mm2       \n\t" // 3 3 2 2 1 1 0 0
  1840.                            "punpcklwd %%mm0, %%mm0  \n\t" // 1 1 1 1 0 0 0 0
  1841.                            "movq %%mm0, %%mm3       \n\t" // 1 1 1 1 0 0 0 0
  1842.                            "punpckldq %%mm0, %%mm0  \n\t" // 0 0 0 0 0 0 0 0
  1843.                            "punpckhdq %%mm3, %%mm3  \n\t" // 1 1 1 1 1 1 1 1
  1844.                            "movq %%mm0, (%%edi)     \n\t"
  1845.                            "punpckhwd %%mm2, %%mm2  \n\t" // 3 3 3 3 2 2 2 2
  1846.                            "movq %%mm3, 8(%%edi)    \n\t"
  1847.                            "movq %%mm2, %%mm4       \n\t" // 3 3 3 3 2 2 2 2
  1848.                            "punpckldq %%mm2, %%mm2  \n\t" // 2 2 2 2 2 2 2 2
  1849.                            "punpckhdq %%mm4, %%mm4  \n\t" // 3 3 3 3 3 3 3 3
  1850.                            "movq %%mm2, 16(%%edi)   \n\t"
  1851.                            "subl $4, %%esi          \n\t"
  1852.                            "movq %%mm4, 24(%%edi)   \n\t"
  1853.                            "subl $32, %%edi         \n\t"
  1854.                            "subl $4, %%ecx          \n\t"
  1855.                            "jnz .loop1_pass0        \n\t"
  1856.                            "EMMS                    \n\t" // DONE
  1857.  
  1858.                            : "=c" (dummy_value_c),        // output regs (dummy)
  1859.                              "=S" (dummy_value_S),
  1860.                              "=D" (dummy_value_D)
  1861.  
  1862.                            : "1" (sptr),      // esi      // input regs
  1863.                              "2" (dp),        // edi
  1864.                              "0" (width_mmx)  // ecx
  1865.  
  1866. #if 0  /* %mm0, ..., %mm4 not supported by gcc 2.7.2.3 or egcs 1.1 */
  1867.                            : "%mm0", "%mm1", "%mm2"       // clobber list
  1868.                            , "%mm3", "%mm4"
  1869. #endif
  1870.                         );
  1871.                      }
  1872.  
  1873.                      sptr -= width_mmx;
  1874.                      dp -= width_mmx*8;
  1875.                      for (i = width; i; i--)
  1876.                      {
  1877.                         int j;
  1878.  
  1879.                        /* I simplified this part in version 1.0.4e
  1880.                         * here and in several other instances where
  1881.                         * pixel_bytes == 1  -- GR-P
  1882.                         *
  1883.                         * Original code:
  1884.                         *
  1885.                         * png_byte v[8];
  1886.                         * png_memcpy(v, sptr, pixel_bytes);
  1887.                         * for (j = 0; j < png_pass_inc[pass]; j++)
  1888.                         * {
  1889.                         *    png_memcpy(dp, v, pixel_bytes);
  1890.                         *    dp -= pixel_bytes;
  1891.                         * }
  1892.                         * sptr -= pixel_bytes;
  1893.                         *
  1894.                         * Replacement code is in the next three lines:
  1895.                         */
  1896.  
  1897.                         for (j = 0; j < png_pass_inc[pass]; j++)
  1898.                         {
  1899.                            *dp-- = *sptr;
  1900.                         }
  1901.                         --sptr;
  1902.                      }
  1903.                   }
  1904.                   else if (((pass == 2) || (pass == 3)) && width)
  1905.                   {
  1906.                      int width_mmx = ((width >> 2) << 2);
  1907.                      width -= width_mmx;        // 0-3 pixels => 0-3 bytes
  1908.                      if (width_mmx)
  1909.                      {
  1910.                         int dummy_value_c;  // fix 'forbidden register spilled'
  1911.                         int dummy_value_S;
  1912.                         int dummy_value_D;
  1913.  
  1914.                         __asm__ __volatile__ (
  1915.                            "subl $3, %%esi          \n\t"
  1916.                            "subl $15, %%edi         \n\t"
  1917.  
  1918.                         ".loop1_pass2:              \n\t"
  1919.                            "movd (%%esi), %%mm0     \n\t" // x x x x 3 2 1 0
  1920.                            "punpcklbw %%mm0, %%mm0  \n\t" // 3 3 2 2 1 1 0 0
  1921.                            "movq %%mm0, %%mm1       \n\t" // 3 3 2 2 1 1 0 0
  1922.                            "punpcklwd %%mm0, %%mm0  \n\t" // 1 1 1 1 0 0 0 0
  1923.                            "punpckhwd %%mm1, %%mm1  \n\t" // 3 3 3 3 2 2 2 2
  1924.                            "movq %%mm0, (%%edi)     \n\t"
  1925.                            "subl $4, %%esi          \n\t"
  1926.                            "movq %%mm1, 8(%%edi)    \n\t"
  1927.                            "subl $16, %%edi         \n\t"
  1928.                            "subl $4, %%ecx          \n\t"
  1929.                            "jnz .loop1_pass2        \n\t"
  1930.                            "EMMS                    \n\t" // DONE
  1931.  
  1932.                            : "=c" (dummy_value_c),        // output regs (dummy)
  1933.                              "=S" (dummy_value_S),
  1934.                              "=D" (dummy_value_D)
  1935.  
  1936.                            : "1" (sptr),      // esi      // input regs
  1937.                              "2" (dp),        // edi
  1938.                              "0" (width_mmx)  // ecx
  1939.  
  1940. #if 0  /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
  1941.                            : "%mm0", "%mm1"               // clobber list
  1942. #endif
  1943.                         );
  1944.                      }
  1945.  
  1946.                      sptr -= width_mmx;
  1947.                      dp -= width_mmx*4;
  1948.                      for (i = width; i; i--)
  1949.                      {
  1950.                         int j;
  1951.  
  1952.                         for (j = 0; j < png_pass_inc[pass]; j++)
  1953.                         {
  1954.                            *dp-- = *sptr;
  1955.                         }
  1956.                         --sptr;
  1957.                      }
  1958.                   }
  1959.                   else if (width)  /* && ((pass == 4) || (pass == 5)) */
  1960.                   {
  1961.                      int width_mmx = ((width >> 3) << 3);
  1962.                      width -= width_mmx;        // 0-3 pixels => 0-3 bytes
  1963.                      if (width_mmx)
  1964.                      {
  1965.                         int dummy_value_c;  // fix 'forbidden register spilled'
  1966.                         int dummy_value_S;
  1967.                         int dummy_value_D;
  1968.  
  1969.                         __asm__ __volatile__ (
  1970.                            "subl $7, %%esi          \n\t"
  1971.                            "subl $15, %%edi         \n\t"
  1972.  
  1973.                         ".loop1_pass4:              \n\t"
  1974.                            "movq (%%esi), %%mm0     \n\t" // 7 6 5 4 3 2 1 0
  1975.                            "movq %%mm0, %%mm1       \n\t" // 7 6 5 4 3 2 1 0
  1976.                            "punpcklbw %%mm0, %%mm0  \n\t" // 3 3 2 2 1 1 0 0
  1977.                            "punpckhbw %%mm1, %%mm1  \n\t" // 7 7 6 6 5 5 4 4
  1978.                            "movq %%mm1, 8(%%edi)    \n\t"
  1979.                            "subl $8, %%esi          \n\t"
  1980.                            "movq %%mm0, (%%edi)     \n\t"
  1981.                            "subl $16, %%edi         \n\t"
  1982.                            "subl $8, %%ecx          \n\t"
  1983.                            "jnz .loop1_pass4        \n\t"
  1984.                            "EMMS                    \n\t" // DONE
  1985.  
  1986.                            : "=c" (dummy_value_c),        // output regs (none)
  1987.                              "=S" (dummy_value_S),
  1988.                              "=D" (dummy_value_D)
  1989.  
  1990.                            : "1" (sptr),      // esi      // input regs
  1991.                              "2" (dp),        // edi
  1992.                              "0" (width_mmx)  // ecx
  1993.  
  1994. #if 0  /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
  1995.                            : "%mm0", "%mm1"               // clobber list
  1996. #endif
  1997.                         );
  1998.                      }
  1999.  
  2000.                      sptr -= width_mmx;
  2001.                      dp -= width_mmx*2;
  2002.                      for (i = width; i; i--)
  2003.                      {
  2004.                         int j;
  2005.  
  2006.                         for (j = 0; j < png_pass_inc[pass]; j++)
  2007.                         {
  2008.                            *dp-- = *sptr;
  2009.                         }
  2010.                         --sptr;
  2011.                      }
  2012.                   }
  2013.                } /* end of pixel_bytes == 1 */
  2014.  
  2015.                //--------------------------------------------------------------
  2016.                else if (pixel_bytes == 2)
  2017.                {
  2018.                   if (((pass == 0) || (pass == 1)) && width)
  2019.                   {
  2020.                      int width_mmx = ((width >> 1) << 1);
  2021.                      width -= width_mmx;        // 0,1 pixels => 0,2 bytes
  2022.                      if (width_mmx)
  2023.                      {
  2024.                         int dummy_value_c;  // fix 'forbidden register spilled'
  2025.                         int dummy_value_S;
  2026.                         int dummy_value_D;
  2027.  
  2028.                         __asm__ __volatile__ (
  2029.                            "subl $2, %%esi          \n\t"
  2030.                            "subl $30, %%edi         \n\t"
  2031.  
  2032.                         ".loop2_pass0:              \n\t"
  2033.                            "movd (%%esi), %%mm0     \n\t" // x x x x 3 2 1 0
  2034.                            "punpcklwd %%mm0, %%mm0  \n\t" // 3 2 3 2 1 0 1 0
  2035.                            "movq %%mm0, %%mm1       \n\t" // 3 2 3 2 1 0 1 0
  2036.                            "punpckldq %%mm0, %%mm0  \n\t" // 1 0 1 0 1 0 1 0
  2037.                            "punpckhdq %%mm1, %%mm1  \n\t" // 3 2 3 2 3 2 3 2
  2038.                            "movq %%mm0, (%%edi)     \n\t"
  2039.                            "movq %%mm0, 8(%%edi)    \n\t"
  2040.                            "movq %%mm1, 16(%%edi)   \n\t"
  2041.                            "subl $4, %%esi          \n\t"
  2042.                            "movq %%mm1, 24(%%edi)   \n\t"
  2043.                            "subl $32, %%edi         \n\t"
  2044.                            "subl $2, %%ecx          \n\t"
  2045.                            "jnz .loop2_pass0        \n\t"
  2046.                            "EMMS                    \n\t" // DONE
  2047.  
  2048.                            : "=c" (dummy_value_c),        // output regs (dummy)
  2049.                              "=S" (dummy_value_S),
  2050.                              "=D" (dummy_value_D)
  2051.  
  2052.                            : "1" (sptr),      // esi      // input regs
  2053.                              "2" (dp),        // edi
  2054.                              "0" (width_mmx)  // ecx
  2055.  
  2056. #if 0  /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2057.                            : "%mm0", "%mm1"               // clobber list
  2058. #endif
  2059.                         );
  2060.                      }
  2061.  
  2062.                      sptr -= (width_mmx*2 - 2); // sign fixed
  2063.                      dp -= (width_mmx*16 - 2);  // sign fixed
  2064.                      for (i = width; i; i--)
  2065.                      {
  2066.                         png_byte v[8];
  2067.                         int j;
  2068.                         sptr -= 2;
  2069.                         png_memcpy(v, sptr, 2);
  2070.                         for (j = 0; j < png_pass_inc[pass]; j++)
  2071.                         {
  2072.                            dp -= 2;
  2073.                            png_memcpy(dp, v, 2);
  2074.                         }
  2075.                      }
  2076.                   }
  2077.                   else if (((pass == 2) || (pass == 3)) && width)
  2078.                   {
  2079.                      int width_mmx = ((width >> 1) << 1) ;
  2080.                      width -= width_mmx;        // 0,1 pixels => 0,2 bytes
  2081.                      if (width_mmx)
  2082.                      {
  2083.                         int dummy_value_c;  // fix 'forbidden register spilled'
  2084.                         int dummy_value_S;
  2085.                         int dummy_value_D;
  2086.  
  2087.                         __asm__ __volatile__ (
  2088.                            "subl $2, %%esi          \n\t"
  2089.                            "subl $14, %%edi         \n\t"
  2090.  
  2091.                         ".loop2_pass2:              \n\t"
  2092.                            "movd (%%esi), %%mm0     \n\t" // x x x x 3 2 1 0
  2093.                            "punpcklwd %%mm0, %%mm0  \n\t" // 3 2 3 2 1 0 1 0
  2094.                            "movq %%mm0, %%mm1       \n\t" // 3 2 3 2 1 0 1 0
  2095.                            "punpckldq %%mm0, %%mm0  \n\t" // 1 0 1 0 1 0 1 0
  2096.                            "punpckhdq %%mm1, %%mm1  \n\t" // 3 2 3 2 3 2 3 2
  2097.                            "movq %%mm0, (%%edi)     \n\t"
  2098.                            "subl $4, %%esi          \n\t"
  2099.                            "movq %%mm1, 8(%%edi)    \n\t"
  2100.                            "subl $16, %%edi         \n\t"
  2101.                            "subl $2, %%ecx          \n\t"
  2102.                            "jnz .loop2_pass2        \n\t"
  2103.                            "EMMS                    \n\t" // DONE
  2104.  
  2105.                            : "=c" (dummy_value_c),        // output regs (dummy)
  2106.                              "=S" (dummy_value_S),
  2107.                              "=D" (dummy_value_D)
  2108.  
  2109.                            : "1" (sptr),      // esi      // input regs
  2110.                              "2" (dp),        // edi
  2111.                              "0" (width_mmx)  // ecx
  2112.  
  2113. #if 0  /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2114.                            : "%mm0", "%mm1"               // clobber list
  2115. #endif
  2116.                         );
  2117.                      }
  2118.  
  2119.                      sptr -= (width_mmx*2 - 2); // sign fixed
  2120.                      dp -= (width_mmx*8 - 2);   // sign fixed
  2121.                      for (i = width; i; i--)
  2122.                      {
  2123.                         png_byte v[8];
  2124.                         int j;
  2125.                         sptr -= 2;
  2126.                         png_memcpy(v, sptr, 2);
  2127.                         for (j = 0; j < png_pass_inc[pass]; j++)
  2128.                         {
  2129.                            dp -= 2;
  2130.                            png_memcpy(dp, v, 2);
  2131.                         }
  2132.                      }
  2133.                   }
  2134.                   else if (width)  // pass == 4 or 5
  2135.                   {
  2136.                      int width_mmx = ((width >> 1) << 1) ;
  2137.                      width -= width_mmx;        // 0,1 pixels => 0,2 bytes
  2138.                      if (width_mmx)
  2139.                      {
  2140.                         int dummy_value_c;  // fix 'forbidden register spilled'
  2141.                         int dummy_value_S;
  2142.                         int dummy_value_D;
  2143.  
  2144.                         __asm__ __volatile__ (
  2145.                            "subl $2, %%esi          \n\t"
  2146.                            "subl $6, %%edi          \n\t"
  2147.  
  2148.                         ".loop2_pass4:              \n\t"
  2149.                            "movd (%%esi), %%mm0     \n\t" // x x x x 3 2 1 0
  2150.                            "punpcklwd %%mm0, %%mm0  \n\t" // 3 2 3 2 1 0 1 0
  2151.                            "subl $4, %%esi          \n\t"
  2152.                            "movq %%mm0, (%%edi)     \n\t"
  2153.                            "subl $8, %%edi          \n\t"
  2154.                            "subl $2, %%ecx          \n\t"
  2155.                            "jnz .loop2_pass4        \n\t"
  2156.                            "EMMS                    \n\t" // DONE
  2157.  
  2158.                            : "=c" (dummy_value_c),        // output regs (dummy)
  2159.                              "=S" (dummy_value_S),
  2160.                              "=D" (dummy_value_D)
  2161.  
  2162.                            : "1" (sptr),      // esi      // input regs
  2163.                              "2" (dp),        // edi
  2164.                              "0" (width_mmx)  // ecx
  2165.  
  2166. #if 0  /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2167.                            : "%mm0"                       // clobber list
  2168. #endif
  2169.                         );
  2170.                      }
  2171.  
  2172.                      sptr -= (width_mmx*2 - 2); // sign fixed
  2173.                      dp -= (width_mmx*4 - 2);   // sign fixed
  2174.                      for (i = width; i; i--)
  2175.                      {
  2176.                         png_byte v[8];
  2177.                         int j;
  2178.                         sptr -= 2;
  2179.                         png_memcpy(v, sptr, 2);
  2180.                         for (j = 0; j < png_pass_inc[pass]; j++)
  2181.                         {
  2182.                            dp -= 2;
  2183.                            png_memcpy(dp, v, 2);
  2184.                         }
  2185.                      }
  2186.                   }
  2187.                } /* end of pixel_bytes == 2 */
  2188.  
  2189.                //--------------------------------------------------------------
  2190.                else if (pixel_bytes == 4)
  2191.                {
  2192.                   if (((pass == 0) || (pass == 1)) && width)
  2193.                   {
  2194.                      int width_mmx = ((width >> 1) << 1);
  2195.                      width -= width_mmx;        // 0,1 pixels => 0,4 bytes
  2196.                      if (width_mmx)
  2197.                      {
  2198.                         int dummy_value_c;  // fix 'forbidden register spilled'
  2199.                         int dummy_value_S;
  2200.                         int dummy_value_D;
  2201.  
  2202.                         __asm__ __volatile__ (
  2203.                            "subl $4, %%esi          \n\t"
  2204.                            "subl $60, %%edi         \n\t"
  2205.  
  2206.                         ".loop4_pass0:              \n\t"
  2207.                            "movq (%%esi), %%mm0     \n\t" // 7 6 5 4 3 2 1 0
  2208.                            "movq %%mm0, %%mm1       \n\t" // 7 6 5 4 3 2 1 0
  2209.                            "punpckldq %%mm0, %%mm0  \n\t" // 3 2 1 0 3 2 1 0
  2210.                            "punpckhdq %%mm1, %%mm1  \n\t" // 7 6 5 4 7 6 5 4
  2211.                            "movq %%mm0, (%%edi)     \n\t"
  2212.                            "movq %%mm0, 8(%%edi)    \n\t"
  2213.                            "movq %%mm0, 16(%%edi)   \n\t"
  2214.                            "movq %%mm0, 24(%%edi)   \n\t"
  2215.                            "movq %%mm1, 32(%%edi)   \n\t"
  2216.                            "movq %%mm1, 40(%%edi)   \n\t"
  2217.                            "movq %%mm1, 48(%%edi)   \n\t"
  2218.                            "subl $8, %%esi          \n\t"
  2219.                            "movq %%mm1, 56(%%edi)   \n\t"
  2220.                            "subl $64, %%edi         \n\t"
  2221.                            "subl $2, %%ecx          \n\t"
  2222.                            "jnz .loop4_pass0        \n\t"
  2223.                            "EMMS                    \n\t" // DONE
  2224.  
  2225.                            : "=c" (dummy_value_c),        // output regs (dummy)
  2226.                              "=S" (dummy_value_S),
  2227.                              "=D" (dummy_value_D)
  2228.  
  2229.                            : "1" (sptr),      // esi      // input regs
  2230.                              "2" (dp),        // edi
  2231.                              "0" (width_mmx)  // ecx
  2232.  
  2233. #if 0  /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2234.                            : "%mm0", "%mm1"               // clobber list
  2235. #endif
  2236.                         );
  2237.                      }
  2238.  
  2239.                      sptr -= (width_mmx*4 - 4); // sign fixed
  2240.                      dp -= (width_mmx*32 - 4);  // sign fixed
  2241.                      for (i = width; i; i--)
  2242.                      {
  2243.                         png_byte v[8];
  2244.                         int j;
  2245.                         sptr -= 4;
  2246.                         png_memcpy(v, sptr, 4);
  2247.                         for (j = 0; j < png_pass_inc[pass]; j++)
  2248.                         {
  2249.                            dp -= 4;
  2250.                            png_memcpy(dp, v, 4);
  2251.                         }
  2252.                      }
  2253.                   }
  2254.                   else if (((pass == 2) || (pass == 3)) && width)
  2255.                   {
  2256.                      int width_mmx = ((width >> 1) << 1);
  2257.                      width -= width_mmx;        // 0,1 pixels => 0,4 bytes
  2258.                      if (width_mmx)
  2259.                      {
  2260.                         int dummy_value_c;  // fix 'forbidden register spilled'
  2261.                         int dummy_value_S;
  2262.                         int dummy_value_D;
  2263.  
  2264.                         __asm__ __volatile__ (
  2265.                            "subl $4, %%esi          \n\t"
  2266.                            "subl $28, %%edi         \n\t"
  2267.  
  2268.                         ".loop4_pass2:              \n\t"
  2269.                            "movq (%%esi), %%mm0     \n\t" // 7 6 5 4 3 2 1 0
  2270.                            "movq %%mm0, %%mm1       \n\t" // 7 6 5 4 3 2 1 0
  2271.                            "punpckldq %%mm0, %%mm0  \n\t" // 3 2 1 0 3 2 1 0
  2272.                            "punpckhdq %%mm1, %%mm1  \n\t" // 7 6 5 4 7 6 5 4
  2273.                            "movq %%mm0, (%%edi)     \n\t"
  2274.                            "movq %%mm0, 8(%%edi)    \n\t"
  2275.                            "movq %%mm1, 16(%%edi)   \n\t"
  2276.                            "movq %%mm1, 24(%%edi)   \n\t"
  2277.                            "subl $8, %%esi          \n\t"
  2278.                            "subl $32, %%edi         \n\t"
  2279.                            "subl $2, %%ecx          \n\t"
  2280.                            "jnz .loop4_pass2        \n\t"
  2281.                            "EMMS                    \n\t" // DONE
  2282.  
  2283.                            : "=c" (dummy_value_c),        // output regs (dummy)
  2284.                              "=S" (dummy_value_S),
  2285.                              "=D" (dummy_value_D)
  2286.  
  2287.                            : "1" (sptr),      // esi      // input regs
  2288.                              "2" (dp),        // edi
  2289.                              "0" (width_mmx)  // ecx
  2290.  
  2291. #if 0  /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2292.                            : "%mm0", "%mm1"               // clobber list
  2293. #endif
  2294.                         );
  2295.                      }
  2296.  
  2297.                      sptr -= (width_mmx*4 - 4); // sign fixed
  2298.                      dp -= (width_mmx*16 - 4);  // sign fixed
  2299.                      for (i = width; i; i--)
  2300.                      {
  2301.                         png_byte v[8];
  2302.                         int j;
  2303.                         sptr -= 4;
  2304.                         png_memcpy(v, sptr, 4);
  2305.                         for (j = 0; j < png_pass_inc[pass]; j++)
  2306.                         {
  2307.                            dp -= 4;
  2308.                            png_memcpy(dp, v, 4);
  2309.                         }
  2310.                      }
  2311.                   }
  2312.                   else if (width)  // pass == 4 or 5
  2313.                   {
  2314.                      int width_mmx = ((width >> 1) << 1) ;
  2315.                      width -= width_mmx;        // 0,1 pixels => 0,4 bytes
  2316.                      if (width_mmx)
  2317.                      {
  2318.                         int dummy_value_c;  // fix 'forbidden register spilled'
  2319.                         int dummy_value_S;
  2320.                         int dummy_value_D;
  2321.  
  2322.                         __asm__ __volatile__ (
  2323.                            "subl $4, %%esi          \n\t"
  2324.                            "subl $12, %%edi         \n\t"
  2325.  
  2326.                         ".loop4_pass4:              \n\t"
  2327.                            "movq (%%esi), %%mm0     \n\t" // 7 6 5 4 3 2 1 0
  2328.                            "movq %%mm0, %%mm1       \n\t" // 7 6 5 4 3 2 1 0
  2329.                            "punpckldq %%mm0, %%mm0  \n\t" // 3 2 1 0 3 2 1 0
  2330.                            "punpckhdq %%mm1, %%mm1  \n\t" // 7 6 5 4 7 6 5 4
  2331.                            "movq %%mm0, (%%edi)     \n\t"
  2332.                            "subl $8, %%esi          \n\t"
  2333.                            "movq %%mm1, 8(%%edi)    \n\t"
  2334.                            "subl $16, %%edi         \n\t"
  2335.                            "subl $2, %%ecx          \n\t"
  2336.                            "jnz .loop4_pass4        \n\t"
  2337.                            "EMMS                    \n\t" // DONE
  2338.  
  2339.                            : "=c" (dummy_value_c),        // output regs (dummy)
  2340.                              "=S" (dummy_value_S),
  2341.                              "=D" (dummy_value_D)
  2342.  
  2343.                            : "1" (sptr),      // esi      // input regs
  2344.                              "2" (dp),        // edi
  2345.                              "0" (width_mmx)  // ecx
  2346.  
  2347. #if 0  /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2348.                            : "%mm0", "%mm1"               // clobber list
  2349. #endif
  2350.                         );
  2351.                      }
  2352.  
  2353.                      sptr -= (width_mmx*4 - 4); // sign fixed
  2354.                      dp -= (width_mmx*8 - 4);   // sign fixed
  2355.                      for (i = width; i; i--)
  2356.                      {
  2357.                         png_byte v[8];
  2358.                         int j;
  2359.                         sptr -= 4;
  2360.                         png_memcpy(v, sptr, 4);
  2361.                         for (j = 0; j < png_pass_inc[pass]; j++)
  2362.                         {
  2363.                            dp -= 4;
  2364.                            png_memcpy(dp, v, 4);
  2365.                         }
  2366.                      }
  2367.                   }
  2368.                } /* end of pixel_bytes == 4 */
  2369.  
  2370.                //--------------------------------------------------------------
  2371.                else if (pixel_bytes == 8)
  2372.                {
  2373. // GRR TEST:  should work, but needs testing (special 64-bit version of rpng2?)
  2374.                   // GRR NOTE:  no need to combine passes here!
  2375.                   if (((pass == 0) || (pass == 1)) && width)
  2376.                   {
  2377.                      int dummy_value_c;  // fix 'forbidden register spilled'
  2378.                      int dummy_value_S;
  2379.                      int dummy_value_D;
  2380.  
  2381.                      // source is 8-byte RRGGBBAA
  2382.                      // dest is 64-byte RRGGBBAA RRGGBBAA RRGGBBAA RRGGBBAA ...
  2383.                      __asm__ __volatile__ (
  2384.                         "subl $56, %%edi         \n\t" // start of last block
  2385.  
  2386.                      ".loop8_pass0:              \n\t"
  2387.                         "movq (%%esi), %%mm0     \n\t" // 7 6 5 4 3 2 1 0
  2388.                         "movq %%mm0, (%%edi)     \n\t"
  2389.                         "movq %%mm0, 8(%%edi)    \n\t"
  2390.                         "movq %%mm0, 16(%%edi)   \n\t"
  2391.                         "movq %%mm0, 24(%%edi)   \n\t"
  2392.                         "movq %%mm0, 32(%%edi)   \n\t"
  2393.                         "movq %%mm0, 40(%%edi)   \n\t"
  2394.                         "movq %%mm0, 48(%%edi)   \n\t"
  2395.                         "subl $8, %%esi          \n\t"
  2396.                         "movq %%mm0, 56(%%edi)   \n\t"
  2397.                         "subl $64, %%edi         \n\t"
  2398.                         "decl %%ecx              \n\t"
  2399.                         "jnz .loop8_pass0        \n\t"
  2400.                         "EMMS                    \n\t" // DONE
  2401.  
  2402.                         : "=c" (dummy_value_c),        // output regs (dummy)
  2403.                           "=S" (dummy_value_S),
  2404.                           "=D" (dummy_value_D)
  2405.  
  2406.                         : "1" (sptr),      // esi      // input regs
  2407.                           "2" (dp),        // edi
  2408.                           "0" (width)      // ecx
  2409.  
  2410. #if 0  /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2411.                         : "%mm0"                       // clobber list
  2412. #endif
  2413.                      );
  2414.                   }
  2415.                   else if (((pass == 2) || (pass == 3)) && width)
  2416.                   {
  2417.                      // source is 8-byte RRGGBBAA
  2418.                      // dest is 32-byte RRGGBBAA RRGGBBAA RRGGBBAA RRGGBBAA
  2419.                      int width_mmx = ((width >> 1) << 1) ;
  2420.                      width -= width_mmx;
  2421.                      if (width_mmx)
  2422.                      {
  2423.                         int dummy_value_c;  // fix 'forbidden register spilled'
  2424.                         int dummy_value_S;
  2425.                         int dummy_value_D;
  2426.  
  2427.                         __asm__ __volatile__ (
  2428.                            "subl $24, %%edi         \n\t" // start of last block
  2429.  
  2430.                         ".loop8_pass2:              \n\t"
  2431.                            "movq (%%esi), %%mm0     \n\t" // 7 6 5 4 3 2 1 0
  2432.                            "movq %%mm0, (%%edi)     \n\t"
  2433.                            "movq %%mm0, 8(%%edi)    \n\t"
  2434.                            "movq %%mm0, 16(%%edi)   \n\t"
  2435.                            "subl $8, %%esi          \n\t"
  2436.                            "movq %%mm0, 24(%%edi)   \n\t"
  2437.                            "subl $32, %%edi         \n\t"
  2438.                            "decl %%ecx              \n\t"
  2439.                            "jnz .loop8_pass2        \n\t"
  2440.                            "EMMS                    \n\t" // DONE
  2441.  
  2442.                            : "=c" (dummy_value_c),        // output regs (dummy)
  2443.                              "=S" (dummy_value_S),
  2444.                              "=D" (dummy_value_D)
  2445.  
  2446.                            : "1" (sptr),      // esi      // input regs
  2447.                              "2" (dp),        // edi
  2448.                              "0" (width)      // ecx
  2449.  
  2450. #if 0  /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2451.                            : "%mm0"                       // clobber list
  2452. #endif
  2453.                         );
  2454.                      }
  2455.                   }
  2456.                   else if (width)  // pass == 4 or 5
  2457.                   {
  2458.                      // source is 8-byte RRGGBBAA
  2459.                      // dest is 16-byte RRGGBBAA RRGGBBAA
  2460.                      int width_mmx = ((width >> 1) << 1) ;
  2461.                      width -= width_mmx;
  2462.                      if (width_mmx)
  2463.                      {
  2464.                         int dummy_value_c;  // fix 'forbidden register spilled'
  2465.                         int dummy_value_S;
  2466.                         int dummy_value_D;
  2467.  
  2468.                         __asm__ __volatile__ (
  2469.                            "subl $8, %%edi          \n\t" // start of last block
  2470.  
  2471.                         ".loop8_pass4:              \n\t"
  2472.                            "movq (%%esi), %%mm0     \n\t" // 7 6 5 4 3 2 1 0
  2473.                            "movq %%mm0, (%%edi)     \n\t"
  2474.                            "subl $8, %%esi          \n\t"
  2475.                            "movq %%mm0, 8(%%edi)    \n\t"
  2476.                            "subl $16, %%edi         \n\t"
  2477.                            "decl %%ecx              \n\t"
  2478.                            "jnz .loop8_pass4        \n\t"
  2479.                            "EMMS                    \n\t" // DONE
  2480.  
  2481.                            : "=c" (dummy_value_c),        // output regs (dummy)
  2482.                              "=S" (dummy_value_S),
  2483.                              "=D" (dummy_value_D)
  2484.  
  2485.                            : "1" (sptr),      // esi      // input regs
  2486.                              "2" (dp),        // edi
  2487.                              "0" (width)      // ecx
  2488.  
  2489. #if 0  /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2490.                            : "%mm0"                       // clobber list
  2491. #endif
  2492.                         );
  2493.                      }
  2494.                   }
  2495.  
  2496.                } /* end of pixel_bytes == 8 */
  2497.  
  2498.                //--------------------------------------------------------------
  2499.                else if (pixel_bytes == 6)
  2500.                {
  2501.                   for (i = width; i; i--)
  2502.                   {
  2503.                      png_byte v[8];
  2504.                      int j;
  2505.                      png_memcpy(v, sptr, 6);
  2506.                      for (j = 0; j < png_pass_inc[pass]; j++)
  2507.                      {
  2508.                         png_memcpy(dp, v, 6);
  2509.                         dp -= 6;
  2510.                      }
  2511.                      sptr -= 6;
  2512.                   }
  2513.                } /* end of pixel_bytes == 6 */
  2514.  
  2515.                //--------------------------------------------------------------
  2516.                else
  2517.                {
  2518.                   for (i = width; i; i--)
  2519.                   {
  2520.                      png_byte v[8];
  2521.                      int j;
  2522.                      png_memcpy(v, sptr, pixel_bytes);
  2523.                      for (j = 0; j < png_pass_inc[pass]; j++)
  2524.                      {
  2525.                         png_memcpy(dp, v, pixel_bytes);
  2526.                         dp -= pixel_bytes;
  2527.                      }
  2528.                      sptr-= pixel_bytes;
  2529.                   }
  2530.                }
  2531.             } // end of _mmx_supported ========================================
  2532.  
  2533.             else /* MMX not supported:  use modified C code - takes advantage
  2534.                   *   of inlining of png_memcpy for a constant */
  2535.                  /* GRR 19991007:  does it?  or should pixel_bytes in each
  2536.                   *   block be replaced with immediate value (e.g., 1)? */
  2537.                  /* GRR 19991017:  replaced with constants in each case */
  2538. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  2539.             {
  2540.                if (pixel_bytes == 1)
  2541.                {
  2542.                   for (i = width; i; i--)
  2543.                   {
  2544.                      int j;
  2545.                      for (j = 0; j < png_pass_inc[pass]; j++)
  2546.                      {
  2547.                         *dp-- = *sptr;
  2548.                      }
  2549.                      --sptr;
  2550.                   }
  2551.                }
  2552.                else if (pixel_bytes == 3)
  2553.                {
  2554.                   for (i = width; i; i--)
  2555.                   {
  2556.                      png_byte v[8];
  2557.                      int j;
  2558.                      png_memcpy(v, sptr, 3);
  2559.                      for (j = 0; j < png_pass_inc[pass]; j++)
  2560.                      {
  2561.                         png_memcpy(dp, v, 3);
  2562.                         dp -= 3;
  2563.                      }
  2564.                      sptr -= 3;
  2565.                   }
  2566.                }
  2567.                else if (pixel_bytes == 2)
  2568.                {
  2569.                   for (i = width; i; i--)
  2570.                   {
  2571.                      png_byte v[8];
  2572.                      int j;
  2573.                      png_memcpy(v, sptr, 2);
  2574.                      for (j = 0; j < png_pass_inc[pass]; j++)
  2575.                      {
  2576.                         png_memcpy(dp, v, 2);
  2577.                         dp -= 2;
  2578.                      }
  2579.                      sptr -= 2;
  2580.                   }
  2581.                }
  2582.                else if (pixel_bytes == 4)
  2583.                {
  2584.                   for (i = width; i; i--)
  2585.                   {
  2586.                      png_byte v[8];
  2587.                      int j;
  2588.                      png_memcpy(v, sptr, 4);
  2589.                      for (j = 0; j < png_pass_inc[pass]; j++)
  2590.                      {
  2591. #ifdef PNG_DEBUG
  2592.                if (dp < row || dp+3 > row+png_ptr->row_buf_size)
  2593.                  {
  2594.                   printf("dp out of bounds: row=%d, dp=%d, rp=%d\n",row, dp,
  2595.                     row+png_ptr->row_buf_size);
  2596.                   printf("row_buf=%d\n",png_ptr->row_buf_size);
  2597.                  }
  2598. #endif
  2599.                         png_memcpy(dp, v, 4);
  2600.                         dp -= 4;
  2601.                      }
  2602.                      sptr -= 4;
  2603.                   }
  2604.                }
  2605.                else if (pixel_bytes == 6)
  2606.                {
  2607.                   for (i = width; i; i--)
  2608.                   {
  2609.                      png_byte v[8];
  2610.                      int j;
  2611.                      png_memcpy(v, sptr, 6);
  2612.                      for (j = 0; j < png_pass_inc[pass]; j++)
  2613.                      {
  2614.                         png_memcpy(dp, v, 6);
  2615.                         dp -= 6;
  2616.                      }
  2617.                      sptr -= 6;
  2618.                   }
  2619.                }
  2620.                else if (pixel_bytes == 8)
  2621.                {
  2622.                   for (i = width; i; i--)
  2623.                   {
  2624.                      png_byte v[8];
  2625.                      int j;
  2626.                      png_memcpy(v, sptr, 8);
  2627.                      for (j = 0; j < png_pass_inc[pass]; j++)
  2628.                      {
  2629.                         png_memcpy(dp, v, 8);
  2630.                         dp -= 8;
  2631.                      }
  2632.                      sptr -= 8;
  2633.                   }
  2634.                }
  2635.                else     /* GRR:  should never be reached */
  2636.                {
  2637.                   for (i = width; i; i--)
  2638.                   {
  2639.                      png_byte v[8];
  2640.                      int j;
  2641.                      png_memcpy(v, sptr, pixel_bytes);
  2642.                      for (j = 0; j < png_pass_inc[pass]; j++)
  2643.                      {
  2644.                         png_memcpy(dp, v, pixel_bytes);
  2645.                         dp -= pixel_bytes;
  2646.                      }
  2647.                      sptr -= pixel_bytes;
  2648.                   }
  2649.                }
  2650.  
  2651.             } /* end if (MMX not supported) */
  2652.             break;
  2653.          }
  2654.       } /* end switch (row_info->pixel_depth) */
  2655.  
  2656.       row_info->width = final_width;
  2657.       row_info->rowbytes = ((final_width *
  2658.          (png_uint_32)row_info->pixel_depth + 7) >> 3);
  2659.    }
  2660.  
  2661. } /* end png_do_read_interlace() */
  2662.  
  2663. #endif /* PNG_HAVE_ASSEMBLER_READ_INTERLACE */
  2664. #endif /* PNG_READ_INTERLACING_SUPPORTED */
  2665.  
  2666.  
  2667.  
  2668.  
  2669. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
  2670.  
  2671. // These variables are utilized in the functions below.  They are declared
  2672. // globally here to ensure alignment on 8-byte boundaries.
  2673.  
  2674. union uAll {
  2675.    long long use;
  2676.    double  align;
  2677. } _LBCarryMask = {0x0101010101010101LL},
  2678.   _HBClearMask = {0x7f7f7f7f7f7f7f7fLL},
  2679.   _ActiveMask, _ActiveMask2, _ActiveMaskEnd, _ShiftBpp, _ShiftRem;
  2680.  
  2681.  
  2682.  
  2683. //===========================================================================//
  2684. //                                                                           //
  2685. //           P N G _ R E A D _ F I L T E R _ R O W _ M M X _ A V G           //
  2686. //                                                                           //
  2687. //===========================================================================//
  2688.  
  2689. // Optimized code for PNG Average filter decoder
  2690.  
  2691. static void /* PRIVATE */
  2692. png_read_filter_row_mmx_avg(png_row_infop row_info, png_bytep row,
  2693.                             png_bytep prev_row)
  2694. {
  2695.    int bpp;
  2696.    int dummy_value_c;   // fix 'forbidden register 2 (cx) was spilled' error
  2697.    int dummy_value_S;
  2698.    int dummy_value_D;
  2699.  
  2700.    bpp = (row_info->pixel_depth + 7) >> 3;  // get # bytes per pixel
  2701.    _FullLength  = row_info->rowbytes;       // # of bytes to filter
  2702.  
  2703.    __asm__ __volatile__ (
  2704.       // initialize address pointers and offset
  2705. #ifdef __PIC__
  2706.       "pushl %%ebx                 \n\t" // save index to Global Offset Table
  2707. #endif
  2708. //pre "movl row, %%edi             \n\t" // edi:  Avg(x)
  2709.       "xorl %%ebx, %%ebx           \n\t" // ebx:  x
  2710.       "movl %%edi, %%edx           \n\t"
  2711. //pre "movl prev_row, %%esi        \n\t" // esi:  Prior(x)
  2712. //pre "subl bpp, %%edx             \n\t" // (bpp is preloaded into ecx)
  2713.       "subl %%ecx, %%edx           \n\t" // edx:  Raw(x-bpp)
  2714.  
  2715.       "xorl %%eax,%%eax            \n\t"
  2716.  
  2717.       // Compute the Raw value for the first bpp bytes
  2718.       //    Raw(x) = Avg(x) + (Prior(x)/2)
  2719.    "avg_rlp:                       \n\t"
  2720.       "movb (%%esi,%%ebx,),%%al    \n\t" // load al with Prior(x)
  2721.       "incl %%ebx                  \n\t"
  2722.       "shrb %%al                   \n\t" // divide by 2
  2723.       "addb -1(%%edi,%%ebx,),%%al  \n\t" // add Avg(x); -1 to offset inc ebx
  2724. //pre "cmpl bpp, %%ebx             \n\t" // (bpp is preloaded into ecx)
  2725.       "cmpl %%ecx, %%ebx           \n\t"
  2726.       "movb %%al,-1(%%edi,%%ebx,)  \n\t" // write Raw(x); -1 to offset inc ebx
  2727.       "jb avg_rlp                  \n\t" // mov does not affect flags
  2728.  
  2729.       // get # of bytes to alignment
  2730.       "movl %%edi, _dif            \n\t" // take start of row
  2731.       "addl %%ebx, _dif            \n\t" // add bpp
  2732.       "addl $0xf, _dif             \n\t" // add 7+8 to incr past alignment bdry
  2733.       "andl $0xfffffff8, _dif      \n\t" // mask to alignment boundary
  2734.       "subl %%edi, _dif            \n\t" // subtract from start => value ebx at
  2735.       "jz avg_go                   \n\t" //  alignment
  2736.  
  2737.       // fix alignment
  2738.       // Compute the Raw value for the bytes up to the alignment boundary
  2739.       //    Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
  2740.       "xorl %%ecx, %%ecx           \n\t"
  2741.  
  2742.    "avg_lp1:                       \n\t"
  2743.       "xorl %%eax, %%eax           \n\t"
  2744.       "movb (%%esi,%%ebx,), %%cl   \n\t" // load cl with Prior(x)
  2745.       "movb (%%edx,%%ebx,), %%al   \n\t" // load al with Raw(x-bpp)
  2746.       "addw %%cx, %%ax             \n\t"
  2747.       "incl %%ebx                  \n\t"
  2748.       "shrw %%ax                   \n\t" // divide by 2
  2749.       "addb -1(%%edi,%%ebx,), %%al \n\t" // add Avg(x); -1 to offset inc ebx
  2750.       "cmpl _dif, %%ebx            \n\t" // check if at alignment boundary
  2751.       "movb %%al, -1(%%edi,%%ebx,) \n\t" // write Raw(x); -1 to offset inc ebx
  2752.       "jb avg_lp1                  \n\t" // repeat until at alignment boundary
  2753.  
  2754.    "avg_go:                        \n\t"
  2755.       "movl _FullLength, %%eax     \n\t"
  2756.       "movl %%eax, %%ecx           \n\t"
  2757.       "subl %%ebx, %%eax           \n\t" // subtract alignment fix
  2758.       "andl $0x00000007, %%eax     \n\t" // calc bytes over mult of 8
  2759.       "subl %%eax, %%ecx           \n\t" // drop over bytes from original length
  2760.       "movl %%ecx, _MMXLength      \n\t"
  2761. #ifdef __PIC__
  2762.       "popl %%ebx                  \n\t" // restore index to Global Offset Table
  2763. #endif
  2764.  
  2765.       : "=c" (dummy_value_c),            // output regs (dummy)
  2766.         "=S" (dummy_value_S),
  2767.         "=D" (dummy_value_D)
  2768.  
  2769.       : "0" (bpp),       // ecx          // input regs
  2770.         "1" (prev_row),  // esi
  2771.         "2" (row)        // edi
  2772.  
  2773.       : "%eax", "%edx"                   // clobber list
  2774. #ifndef __PIC__
  2775.       , "%ebx"
  2776. #endif
  2777.       // GRR: INCLUDE "memory" as clobbered? (_dif, _MMXLength)
  2778.       // (seems to work fine without...)
  2779.    );
  2780.  
  2781.    // now do the math for the rest of the row
  2782.    switch (bpp)
  2783.    {
  2784.       case 3:
  2785.       {
  2786.          _ActiveMask.use  = 0x0000000000ffffffLL;
  2787.          _ShiftBpp.use = 24;    // == 3 * 8
  2788.          _ShiftRem.use = 40;    // == 64 - 24
  2789.  
  2790.          __asm__ __volatile__ (
  2791.             // re-init address pointers and offset
  2792.             "movq _ActiveMask, %%mm7      \n\t"
  2793.             "movl _dif, %%ecx             \n\t" // ecx:  x = offset to
  2794.             "movq _LBCarryMask, %%mm5     \n\t" //  alignment boundary
  2795. // preload  "movl row, %%edi              \n\t" // edi:  Avg(x)
  2796.             "movq _HBClearMask, %%mm4     \n\t"
  2797. // preload  "movl prev_row, %%esi         \n\t" // esi:  Prior(x)
  2798.  
  2799.             // prime the pump:  load the first Raw(x-bpp) data set
  2800.             "movq -8(%%edi,%%ecx,), %%mm2 \n\t" // load previous aligned 8 bytes
  2801.                                                 // (correct pos. in loop below)
  2802.          "avg_3lp:                        \n\t"
  2803.             "movq (%%edi,%%ecx,), %%mm0   \n\t" // load mm0 with Avg(x)
  2804.             "movq %%mm5, %%mm3            \n\t"
  2805.             "psrlq _ShiftRem, %%mm2       \n\t" // correct position Raw(x-bpp) data
  2806.             "movq (%%esi,%%ecx,), %%mm1   \n\t" // load mm1 with Prior(x)
  2807.             "movq %%mm7, %%mm6            \n\t"
  2808.             "pand %%mm1, %%mm3            \n\t" // get lsb for each prev_row byte
  2809.             "psrlq $1, %%mm1              \n\t" // divide prev_row bytes by 2
  2810.             "pand  %%mm4, %%mm1           \n\t" // clear invalid bit 7 of each byte
  2811.             "paddb %%mm1, %%mm0           \n\t" // add (Prev_row/2) to Avg for each byte
  2812.             // add 1st active group (Raw(x-bpp)/2) to average with LBCarry
  2813.             "movq %%mm3, %%mm1            \n\t" // now use mm1 for getting LBCarrys
  2814.             "pand %%mm2, %%mm1            \n\t" // get LBCarrys for each byte where both
  2815.                                // lsb's were == 1 (only valid for active group)
  2816.             "psrlq $1, %%mm2              \n\t" // divide raw bytes by 2
  2817.             "pand  %%mm4, %%mm2           \n\t" // clear invalid bit 7 of each byte
  2818.             "paddb %%mm1, %%mm2           \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte
  2819.             "pand %%mm6, %%mm2            \n\t" // leave only Active Group 1 bytes to add to Avg
  2820.             "paddb %%mm2, %%mm0           \n\t" // add (Raw/2) + LBCarrys to Avg for each Active
  2821.                                //  byte
  2822.             // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry
  2823.             "psllq _ShiftBpp, %%mm6       \n\t" // shift the mm6 mask to cover bytes 3-5
  2824.             "movq %%mm0, %%mm2            \n\t" // mov updated Raws to mm2
  2825.             "psllq _ShiftBpp, %%mm2       \n\t" // shift data to pos. correctly
  2826.             "movq %%mm3, %%mm1            \n\t" // now use mm1 for getting LBCarrys
  2827.             "pand %%mm2, %%mm1            \n\t" // get LBCarrys for each byte where both
  2828.                                // lsb's were == 1 (only valid for active group)
  2829.             "psrlq $1, %%mm2              \n\t" // divide raw bytes by 2
  2830.             "pand  %%mm4, %%mm2           \n\t" // clear invalid bit 7 of each byte
  2831.             "paddb %%mm1, %%mm2           \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte
  2832.             "pand %%mm6, %%mm2            \n\t" // leave only Active Group 2 bytes to add to Avg
  2833.             "paddb %%mm2, %%mm0           \n\t" // add (Raw/2) + LBCarrys to Avg for each Active
  2834.                                //  byte
  2835.  
  2836.             // add 3rd active group (Raw(x-bpp)/2) to average with _LBCarry
  2837.             "psllq _ShiftBpp, %%mm6       \n\t" // shift mm6 mask to cover last two
  2838.                                  // bytes
  2839.             "movq %%mm0, %%mm2            \n\t" // mov updated Raws to mm2
  2840.             "psllq _ShiftBpp, %%mm2       \n\t" // shift data to pos. correctly
  2841.                               // Data only needs to be shifted once here to
  2842.                               // get the correct x-bpp offset.
  2843.             "movq %%mm3, %%mm1            \n\t" // now use mm1 for getting LBCarrys
  2844.             "pand %%mm2, %%mm1            \n\t" // get LBCarrys for each byte where both
  2845.                               // lsb's were == 1 (only valid for active group)
  2846.             "psrlq $1, %%mm2              \n\t" // divide raw bytes by 2
  2847.             "pand  %%mm4, %%mm2           \n\t" // clear invalid bit 7 of each byte
  2848.             "paddb %%mm1, %%mm2           \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte
  2849.             "pand %%mm6, %%mm2            \n\t" // leave only Active Group 2 bytes to add to Avg
  2850.             "addl $8, %%ecx               \n\t"
  2851.             "paddb %%mm2, %%mm0           \n\t" // add (Raw/2) + LBCarrys to Avg for each Active
  2852.                                                 // byte
  2853.             // now ready to write back to memory
  2854.             "movq %%mm0, -8(%%edi,%%ecx,) \n\t"
  2855.             // move updated Raw(x) to use as Raw(x-bpp) for next loop
  2856.             "cmpl _MMXLength, %%ecx       \n\t"
  2857.             "movq %%mm0, %%mm2            \n\t" // mov updated Raw(x) to mm2
  2858.             "jb avg_3lp                   \n\t"
  2859.  
  2860.             : "=S" (dummy_value_S),             // output regs (dummy)
  2861.               "=D" (dummy_value_D)
  2862.  
  2863.             : "0" (prev_row),  // esi           // input regs
  2864.               "1" (row)        // edi
  2865.  
  2866.             : "%ecx"                            // clobber list
  2867. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2868.             , "%mm0", "%mm1", "%mm2", "%mm3"
  2869.             , "%mm4", "%mm5", "%mm6", "%mm7"
  2870. #endif
  2871.          );
  2872.       }
  2873.       break;  // end 3 bpp
  2874.  
  2875.       case 6:
  2876.       case 4:
  2877.       //case 7:   // who wrote this?  PNG doesn't support 5 or 7 bytes/pixel
  2878.       //case 5:   // GRR BOGUS
  2879.       {
  2880.          _ActiveMask.use  = 0xffffffffffffffffLL; // use shift below to clear
  2881.                                                   // appropriate inactive bytes
  2882.          _ShiftBpp.use = bpp << 3;
  2883.          _ShiftRem.use = 64 - _ShiftBpp.use;
  2884.  
  2885.          __asm__ __volatile__ (
  2886.             "movq _HBClearMask, %%mm4    \n\t"
  2887.  
  2888.             // re-init address pointers and offset
  2889.             "movl _dif, %%ecx            \n\t" // ecx:  x = offset to alignment boundary
  2890.  
  2891.             // load _ActiveMask and clear all bytes except for 1st active group
  2892.             "movq _ActiveMask, %%mm7     \n\t"
  2893. // preload  "movl row, %%edi             \n\t" // edi:  Avg(x)
  2894.             "psrlq _ShiftRem, %%mm7      \n\t"
  2895. // preload  "movl prev_row, %%esi        \n\t" // esi:  Prior(x)
  2896.             "movq %%mm7, %%mm6           \n\t"
  2897.             "movq _LBCarryMask, %%mm5    \n\t"
  2898.             "psllq _ShiftBpp, %%mm6      \n\t" // create mask for 2nd active group
  2899.  
  2900.             // prime the pump:  load the first Raw(x-bpp) data set
  2901.             "movq -8(%%edi,%%ecx,), %%mm2 \n\t" // load previous aligned 8 bytes
  2902.                                           // (we correct pos. in loop below)
  2903.          "avg_4lp:                       \n\t"
  2904.             "movq (%%edi,%%ecx,), %%mm0  \n\t"
  2905.             "psrlq _ShiftRem, %%mm2      \n\t" // shift data to pos. correctly
  2906.             "movq (%%esi,%%ecx,), %%mm1  \n\t"
  2907.             // add (Prev_row/2) to average
  2908.             "movq %%mm5, %%mm3           \n\t"
  2909.             "pand %%mm1, %%mm3           \n\t" // get lsb for each prev_row byte
  2910.             "psrlq $1, %%mm1             \n\t" // divide prev_row bytes by 2
  2911.             "pand  %%mm4, %%mm1          \n\t" // clear invalid bit 7 of each byte
  2912.             "paddb %%mm1, %%mm0          \n\t" // add (Prev_row/2) to Avg for each byte
  2913.             // add 1st active group (Raw(x-bpp)/2) to average with _LBCarry
  2914.             "movq %%mm3, %%mm1           \n\t" // now use mm1 for getting LBCarrys
  2915.             "pand %%mm2, %%mm1           \n\t" // get LBCarrys for each byte where both
  2916.                               // lsb's were == 1 (only valid for active group)
  2917.             "psrlq $1, %%mm2             \n\t" // divide raw bytes by 2
  2918.             "pand  %%mm4, %%mm2          \n\t" // clear invalid bit 7 of each byte
  2919.             "paddb %%mm1, %%mm2          \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte
  2920.             "pand %%mm7, %%mm2           \n\t" // leave only Active Group 1 bytes to add to Avg
  2921.             "paddb %%mm2, %%mm0          \n\t" // add (Raw/2) + LBCarrys to Avg for each Active
  2922.                               // byte
  2923.             // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry
  2924.             "movq %%mm0, %%mm2           \n\t" // mov updated Raws to mm2
  2925.             "psllq _ShiftBpp, %%mm2      \n\t" // shift data to pos. correctly
  2926.             "addl $8, %%ecx              \n\t"
  2927.             "movq %%mm3, %%mm1           \n\t" // now use mm1 for getting LBCarrys
  2928.             "pand %%mm2, %%mm1           \n\t" // get LBCarrys for each byte where both
  2929.                               // lsb's were == 1 (only valid for active group)
  2930.             "psrlq $1, %%mm2             \n\t" // divide raw bytes by 2
  2931.             "pand  %%mm4, %%mm2          \n\t" // clear invalid bit 7 of each byte
  2932.             "paddb %%mm1, %%mm2          \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte
  2933.             "pand %%mm6, %%mm2           \n\t" // leave only Active Group 2 bytes to add to Avg
  2934.             "paddb %%mm2, %%mm0          \n\t" // add (Raw/2) + LBCarrys to Avg for each Active
  2935.                               // byte
  2936.             "cmpl _MMXLength, %%ecx      \n\t"
  2937.             // now ready to write back to memory
  2938.             "movq %%mm0, -8(%%edi,%%ecx,) \n\t"
  2939.             // prep Raw(x-bpp) for next loop
  2940.             "movq %%mm0, %%mm2           \n\t" // mov updated Raws to mm2
  2941.             "jb avg_4lp                  \n\t"
  2942.  
  2943.             : "=S" (dummy_value_S),            // output regs (dummy)
  2944.               "=D" (dummy_value_D)
  2945.  
  2946.             : "0" (prev_row),  // esi          // input regs
  2947.               "1" (row)        // edi
  2948.  
  2949.             : "%ecx"                           // clobber list
  2950. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2951.             , "%mm0", "%mm1", "%mm2", "%mm3"
  2952.             , "%mm4", "%mm5", "%mm6", "%mm7"
  2953. #endif
  2954.          );
  2955.       }
  2956.       break;  // end 4,6 bpp
  2957.  
  2958.       case 2:
  2959.       {
  2960.          _ActiveMask.use  = 0x000000000000ffffLL;
  2961.          _ShiftBpp.use = 16;   // == 2 * 8
  2962.          _ShiftRem.use = 48;   // == 64 - 16
  2963.  
  2964.          __asm__ __volatile__ (
  2965.             // load _ActiveMask
  2966.             "movq _ActiveMask, %%mm7     \n\t"
  2967.             // re-init address pointers and offset
  2968.             "movl _dif, %%ecx            \n\t" // ecx:  x = offset to alignment boundary
  2969.             "movq _LBCarryMask, %%mm5    \n\t"
  2970. // preload  "movl row, %%edi             \n\t" // edi:  Avg(x)
  2971.             "movq _HBClearMask, %%mm4    \n\t"
  2972. // preload  "movl prev_row, %%esi        \n\t" // esi:  Prior(x)
  2973.  
  2974.             // prime the pump:  load the first Raw(x-bpp) data set
  2975.             "movq -8(%%edi,%%ecx,), %%mm2 \n\t" // load previous aligned 8 bytes
  2976.                               // (we correct pos. in loop below)
  2977.          "avg_2lp:                       \n\t"
  2978.             "movq (%%edi,%%ecx,), %%mm0  \n\t"
  2979.             "psrlq _ShiftRem, %%mm2      \n\t" // shift data to pos. correctly
  2980.             "movq (%%esi,%%ecx,), %%mm1  \n\t" //  (GRR BUGFIX:  was psllq)
  2981.             // add (Prev_row/2) to average
  2982.             "movq %%mm5, %%mm3           \n\t"
  2983.             "pand %%mm1, %%mm3           \n\t" // get lsb for each prev_row byte
  2984.             "psrlq $1, %%mm1             \n\t" // divide prev_row bytes by 2
  2985.             "pand  %%mm4, %%mm1          \n\t" // clear invalid bit 7 of each byte
  2986.             "movq %%mm7, %%mm6           \n\t"
  2987.             "paddb %%mm1, %%mm0          \n\t" // add (Prev_row/2) to Avg for each byte
  2988.  
  2989.             // add 1st active group (Raw(x-bpp)/2) to average with _LBCarry
  2990.             "movq %%mm3, %%mm1           \n\t" // now use mm1 for getting LBCarrys
  2991.             "pand %%mm2, %%mm1           \n\t" // get LBCarrys for each byte where both
  2992.                                                // lsb's were == 1 (only valid for active group)
  2993.             "psrlq $1, %%mm2             \n\t" // divide raw bytes by 2
  2994.             "pand  %%mm4, %%mm2          \n\t" // clear invalid bit 7 of each byte
  2995.             "paddb %%mm1, %%mm2          \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte
  2996.             "pand %%mm6, %%mm2           \n\t" // leave only Active Group 1 bytes to add to Avg
  2997.             "paddb %%mm2, %%mm0          \n\t" // add (Raw/2) + LBCarrys to Avg for each Active byte
  2998.  
  2999.             // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry
  3000.             "psllq _ShiftBpp, %%mm6      \n\t" // shift the mm6 mask to cover bytes 2 & 3
  3001.             "movq %%mm0, %%mm2           \n\t" // mov updated Raws to mm2
  3002.             "psllq _ShiftBpp, %%mm2      \n\t" // shift data to pos. correctly
  3003.             "movq %%mm3, %%mm1           \n\t" // now use mm1 for getting LBCarrys
  3004.             "pand %%mm2, %%mm1           \n\t" // get LBCarrys for each byte where both
  3005.                                                // lsb's were == 1 (only valid for active group)
  3006.             "psrlq $1, %%mm2             \n\t" // divide raw bytes by 2
  3007.             "pand  %%mm4, %%mm2          \n\t" // clear invalid bit 7 of each byte
  3008.             "paddb %%mm1, %%mm2          \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte
  3009.             "pand %%mm6, %%mm2           \n\t" // leave only Active Group 2 bytes to add to Avg
  3010.             "paddb %%mm2, %%mm0          \n\t" // add (Raw/2) + LBCarrys to Avg for each Active byte
  3011.  
  3012.             // add 3rd active group (Raw(x-bpp)/2) to average with _LBCarry
  3013.             "psllq _ShiftBpp, %%mm6      \n\t" // shift the mm6 mask to cover bytes 4 & 5
  3014.             "movq %%mm0, %%mm2           \n\t" // mov updated Raws to mm2
  3015.             "psllq _ShiftBpp, %%mm2      \n\t" // shift data to pos. correctly
  3016.             "movq %%mm3, %%mm1           \n\t" // now use mm1 for getting LBCarrys
  3017.             "pand %%mm2, %%mm1           \n\t" // get LBCarrys for each byte where both
  3018.                                                // lsb's were == 1 (only valid for active group)
  3019.             "psrlq $1, %%mm2             \n\t" // divide raw bytes by 2
  3020.             "pand  %%mm4, %%mm2          \n\t" // clear invalid bit 7 of each byte
  3021.             "paddb %%mm1, %%mm2          \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte
  3022.             "pand %%mm6, %%mm2           \n\t" // leave only Active Group 2 bytes to add to Avg
  3023.             "paddb %%mm2, %%mm0          \n\t" // add (Raw/2) + LBCarrys to Avg for each Active byte
  3024.  
  3025.             // add 4th active group (Raw(x-bpp)/2) to average with _LBCarry
  3026.             "psllq _ShiftBpp, %%mm6      \n\t" // shift the mm6 mask to cover bytes 6 & 7
  3027.             "movq %%mm0, %%mm2           \n\t" // mov updated Raws to mm2
  3028.             "psllq _ShiftBpp, %%mm2      \n\t" // shift data to pos. correctly
  3029.             "addl $8, %%ecx              \n\t"
  3030.             "movq %%mm3, %%mm1           \n\t" // now use mm1 for getting LBCarrys
  3031.             "pand %%mm2, %%mm1           \n\t" // get LBCarrys for each byte where both
  3032.                                                // lsb's were == 1 (only valid for active group)
  3033.             "psrlq $1, %%mm2             \n\t" // divide raw bytes by 2
  3034.             "pand  %%mm4, %%mm2          \n\t" // clear invalid bit 7 of each byte
  3035.             "paddb %%mm1, %%mm2          \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte
  3036.             "pand %%mm6, %%mm2           \n\t" // leave only Active Group 2 bytes to add to Avg
  3037.             "paddb %%mm2, %%mm0          \n\t" // add (Raw/2) + LBCarrys to Avg for each Active byte
  3038.  
  3039.             "cmpl _MMXLength, %%ecx      \n\t"
  3040.             // now ready to write back to memory
  3041.             "movq %%mm0, -8(%%edi,%%ecx,) \n\t"
  3042.             // prep Raw(x-bpp) for next loop
  3043.             "movq %%mm0, %%mm2           \n\t" // mov updated Raws to mm2
  3044.             "jb avg_2lp                  \n\t"
  3045.  
  3046.             : "=S" (dummy_value_S),            // output regs (dummy)
  3047.               "=D" (dummy_value_D)
  3048.  
  3049.             : "0" (prev_row),  // esi          // input regs
  3050.               "1" (row)        // edi
  3051.  
  3052.             : "%ecx"                           // clobber list
  3053. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  3054.             , "%mm0", "%mm1", "%mm2", "%mm3"
  3055.             , "%mm4", "%mm5", "%mm6", "%mm7"
  3056. #endif
  3057.          );
  3058.       }
  3059.       break;  // end 2 bpp
  3060.  
  3061.       case 1:
  3062.       {
  3063.          __asm__ __volatile__ (
  3064.             // re-init address pointers and offset
  3065. #ifdef __PIC__
  3066.             "pushl %%ebx                 \n\t" // save Global Offset Table index
  3067. #endif
  3068.             "movl _dif, %%ebx            \n\t" // ebx:  x = offset to alignment boundary
  3069. // preload  "movl row, %%edi             \n\t" // edi:  Avg(x)
  3070.             "cmpl _FullLength, %%ebx     \n\t" // test if offset at end of array
  3071.             "jnb avg_1end                \n\t"
  3072.             // do Paeth decode for remaining bytes
  3073. // preload  "movl prev_row, %%esi        \n\t" // esi:  Prior(x)
  3074.             "movl %%edi, %%edx           \n\t"
  3075. // preload  "subl bpp, %%edx             \n\t" // (bpp is preloaded into ecx)
  3076.             "subl %%ecx, %%edx           \n\t" // edx:  Raw(x-bpp)
  3077.             "xorl %%ecx, %%ecx           \n\t" // zero ecx before using cl & cx
  3078.                                                //  in loop below
  3079.          "avg_1lp:                       \n\t"
  3080.             // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
  3081.             "xorl %%eax, %%eax           \n\t"
  3082.             "movb (%%esi,%%ebx,), %%cl   \n\t" // load cl with Prior(x)
  3083.             "movb (%%edx,%%ebx,), %%al   \n\t" // load al with Raw(x-bpp)
  3084.             "addw %%cx, %%ax             \n\t"
  3085.             "incl %%ebx                  \n\t"
  3086.             "shrw %%ax                   \n\t" // divide by 2
  3087.             "addb -1(%%edi,%%ebx,), %%al \n\t" // add Avg(x); -1 to offset inc ebx
  3088.             "cmpl _FullLength, %%ebx     \n\t" // check if at end of array
  3089.             "movb %%al, -1(%%edi,%%ebx,) \n\t" // write back Raw(x);
  3090.                          // mov does not affect flags; -1 to offset inc ebx
  3091.             "jb avg_1lp                  \n\t"
  3092.  
  3093.          "avg_1end:                      \n\t"
  3094. #ifdef __PIC__
  3095.             "popl %%ebx                  \n\t" // Global Offset Table index
  3096. #endif
  3097.  
  3098.             : "=c" (dummy_value_c),            // output regs (dummy)
  3099.               "=S" (dummy_value_S),
  3100.               "=D" (dummy_value_D)
  3101.  
  3102.             : "0" (bpp),       // ecx          // input regs
  3103.               "1" (prev_row),  // esi
  3104.               "2" (row)        // edi
  3105.  
  3106.             : "%eax", "%edx"                   // clobber list
  3107. #ifndef __PIC__
  3108.             , "%ebx"
  3109. #endif
  3110.          );
  3111.       }
  3112.       return;  // end 1 bpp
  3113.  
  3114.       case 8:
  3115.       {
  3116.          __asm__ __volatile__ (
  3117.             // re-init address pointers and offset
  3118.             "movl _dif, %%ecx            \n\t" // ecx:  x == offset to alignment
  3119.             "movq _LBCarryMask, %%mm5    \n\t" //            boundary
  3120. // preload  "movl row, %%edi             \n\t" // edi:  Avg(x)
  3121.             "movq _HBClearMask, %%mm4    \n\t"
  3122. // preload  "movl prev_row, %%esi        \n\t" // esi:  Prior(x)
  3123.  
  3124.             // prime the pump:  load the first Raw(x-bpp) data set
  3125.             "movq -8(%%edi,%%ecx,), %%mm2 \n\t" // load previous aligned 8 bytes
  3126.                                       // (NO NEED to correct pos. in loop below)
  3127.  
  3128.          "avg_8lp:                       \n\t"
  3129.             "movq (%%edi,%%ecx,), %%mm0  \n\t"
  3130.             "movq %%mm5, %%mm3           \n\t"
  3131.             "movq (%%esi,%%ecx,), %%mm1  \n\t"
  3132.             "addl $8, %%ecx              \n\t"
  3133.             "pand %%mm1, %%mm3           \n\t" // get lsb for each prev_row byte
  3134.             "psrlq $1, %%mm1             \n\t" // divide prev_row bytes by 2
  3135.             "pand %%mm2, %%mm3           \n\t" // get LBCarrys for each byte
  3136.                                                //  where both lsb's were == 1
  3137.             "psrlq $1, %%mm2             \n\t" // divide raw bytes by 2
  3138.             "pand  %%mm4, %%mm1          \n\t" // clear invalid bit 7, each byte
  3139.             "paddb %%mm3, %%mm0          \n\t" // add LBCarrys to Avg, each byte
  3140.             "pand  %%mm4, %%mm2          \n\t" // clear invalid bit 7, each byte
  3141.             "paddb %%mm1, %%mm0          \n\t" // add (Prev_row/2) to Avg, each
  3142.             "paddb %%mm2, %%mm0          \n\t" // add (Raw/2) to Avg for each
  3143.             "cmpl _MMXLength, %%ecx      \n\t"
  3144.             "movq %%mm0, -8(%%edi,%%ecx,) \n\t"
  3145.             "movq %%mm0, %%mm2           \n\t" // reuse as Raw(x-bpp)
  3146.             "jb avg_8lp                  \n\t"
  3147.  
  3148.             : "=S" (dummy_value_S),            // output regs (dummy)
  3149.               "=D" (dummy_value_D)
  3150.  
  3151.             : "0" (prev_row),  // esi          // input regs
  3152.               "1" (row)        // edi
  3153.  
  3154.             : "%ecx"                           // clobber list
  3155. #if 0  /* %mm0, ..., %mm5 not supported by gcc 2.7.2.3 or egcs 1.1 */
  3156.             , "%mm0", "%mm1", "%mm2"
  3157.             , "%mm3", "%mm4", "%mm5"
  3158. #endif
  3159.          );
  3160.       }
  3161.       break;  // end 8 bpp
  3162.  
  3163.       default:                  // bpp greater than 8 (!= 1,2,3,4,[5],6,[7],8)
  3164.       {
  3165.  
  3166.          // GRR:  PRINT ERROR HERE:  SHOULD NEVER BE REACHED
  3167.          fprintf(stderr,
  3168.            "libpng:  internal logic error (png_read_filter_row_mmx_avg())\n");
  3169.  
  3170. #if 0
  3171.         __asm__ __volatile__ (
  3172.             "movq _LBCarryMask, %%mm5    \n\t"
  3173.             // re-init address pointers and offset
  3174.             "movl _dif, %%ebx            \n\t" // ebx:  x = offset to alignment boundary
  3175.             "movl row, %%edi             \n\t" // edi:  Avg(x)
  3176.             "movq _HBClearMask, %%mm4    \n\t"
  3177.             "movl %%edi, %%edx           \n\t"
  3178.             "movl prev_row, %%esi        \n\t" // esi:  Prior(x)
  3179.             "subl bpp, %%edx             \n\t" // edx:  Raw(x-bpp)
  3180.          "avg_Alp:                       \n\t"
  3181.             "movq (%%edi,%%ebx,), %%mm0  \n\t"
  3182.             "movq %%mm5, %%mm3           \n\t"
  3183.             "movq (%%esi,%%ebx,), %%mm1  \n\t"
  3184.             "pand %%mm1, %%mm3           \n\t" // get lsb for each prev_row byte
  3185.             "movq (%%edx,%%ebx,), %%mm2  \n\t"
  3186.             "psrlq $1, %%mm1             \n\t" // divide prev_row bytes by 2
  3187.             "pand %%mm2, %%mm3           \n\t" // get LBCarrys for each byte where both
  3188.                                 // lsb's were == 1
  3189.             "psrlq $1, %%mm2             \n\t" // divide raw bytes by 2
  3190.             "pand  %%mm4, %%mm1          \n\t" // clear invalid bit 7 of each byte
  3191.             "paddb %%mm3, %%mm0          \n\t" // add LBCarrys to Avg for each byte
  3192.             "pand  %%mm4, %%mm2          \n\t" // clear invalid bit 7 of each byte
  3193.             "paddb %%mm1, %%mm0          \n\t" // add (Prev_row/2) to Avg for each byte
  3194.             "addl $8, %%ebx              \n\t"
  3195.             "paddb %%mm2, %%mm0          \n\t" // add (Raw/2) to Avg for each byte
  3196.             "cmpl _MMXLength, %%ebx      \n\t"
  3197.             "movq %%mm0, -8(%%edi,%%ebx,) \n\t"
  3198.             "jb avg_Alp                  \n\t"
  3199.  
  3200.             : // FIXASM: output regs/vars go here, e.g.:  "=m" (memory_var)
  3201.  
  3202.             : // FIXASM: input regs, e.g.:  "c" (count), "S" (src), "D" (dest)
  3203.  
  3204.             : "%ebx", "%edx", "%edi", "%esi" // CHECKASM: clobber list
  3205.          );
  3206. #endif /* 0 - NEVER REACHED */
  3207.       }
  3208.       break;
  3209.  
  3210.    } // end switch (bpp)
  3211.  
  3212.    __asm__ __volatile__ (
  3213.       // MMX acceleration complete; now do clean-up
  3214.       // check if any remaining bytes left to decode
  3215. #ifdef __PIC__
  3216.       "pushl %%ebx                 \n\t" // save index to Global Offset Table
  3217. #endif
  3218.       "movl _MMXLength, %%ebx      \n\t" // ebx:  x == offset bytes after MMX
  3219. //pre "movl row, %%edi             \n\t" // edi:  Avg(x)
  3220.       "cmpl _FullLength, %%ebx     \n\t" // test if offset at end of array
  3221.       "jnb avg_end                 \n\t"
  3222.  
  3223.       // do Avg decode for remaining bytes
  3224. //pre "movl prev_row, %%esi        \n\t" // esi:  Prior(x)
  3225.       "movl %%edi, %%edx           \n\t"
  3226. //pre "subl bpp, %%edx             \n\t" // (bpp is preloaded into ecx)
  3227.       "subl %%ecx, %%edx           \n\t" // edx:  Raw(x-bpp)
  3228.       "xorl %%ecx, %%ecx           \n\t" // zero ecx before using cl & cx below
  3229.  
  3230.    "avg_lp2:                       \n\t"
  3231.       // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
  3232.       "xorl %%eax, %%eax           \n\t"
  3233.       "movb (%%esi,%%ebx,), %%cl   \n\t" // load cl with Prior(x)
  3234.       "movb (%%edx,%%ebx,), %%al   \n\t" // load al with Raw(x-bpp)
  3235.       "addw %%cx, %%ax             \n\t"
  3236.       "incl %%ebx                  \n\t"
  3237.       "shrw %%ax                   \n\t" // divide by 2
  3238.       "addb -1(%%edi,%%ebx,), %%al \n\t" // add Avg(x); -1 to offset inc ebx
  3239.       "cmpl _FullLength, %%ebx     \n\t" // check if at end of array
  3240.       "movb %%al, -1(%%edi,%%ebx,) \n\t" // write back Raw(x) [mov does not
  3241.       "jb avg_lp2                  \n\t" //  affect flags; -1 to offset inc ebx]
  3242.  
  3243.    "avg_end:                       \n\t"
  3244.       "EMMS                        \n\t" // end MMX; prep for poss. FP instrs.
  3245. #ifdef __PIC__
  3246.       "popl %%ebx                  \n\t" // restore index to Global Offset Table
  3247. #endif
  3248.  
  3249.       : "=c" (dummy_value_c),            // output regs (dummy)
  3250.         "=S" (dummy_value_S),
  3251.         "=D" (dummy_value_D)
  3252.  
  3253.       : "0" (bpp),       // ecx          // input regs
  3254.         "1" (prev_row),  // esi
  3255.         "2" (row)        // edi
  3256.  
  3257.       : "%eax", "%edx"                   // clobber list
  3258. #ifndef __PIC__
  3259.       , "%ebx"
  3260. #endif
  3261.    );
  3262.  
  3263. } /* end png_read_filter_row_mmx_avg() */
  3264.  
  3265.  
  3266.  
  3267.  
  3268. //===========================================================================//
  3269. //                                                                           //
  3270. //         P N G _ R E A D _ F I L T E R _ R O W _ M M X _ P A E T H         //
  3271. //                                                                           //
  3272. //===========================================================================//
  3273.  
  3274. // Optimized code for PNG Paeth filter decoder
  3275.  
  3276. static void /* PRIVATE */
  3277. png_read_filter_row_mmx_paeth(png_row_infop row_info, png_bytep row,
  3278.                               png_bytep prev_row)
  3279. {
  3280.    int bpp;
  3281.    int dummy_value_c;   // fix 'forbidden register 2 (cx) was spilled' error
  3282.    int dummy_value_S;
  3283.    int dummy_value_D;
  3284.  
  3285.    bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel
  3286.    _FullLength  = row_info->rowbytes; // # of bytes to filter
  3287.  
  3288.    __asm__ __volatile__ (
  3289. #ifdef __PIC__
  3290.       "pushl %%ebx                 \n\t" // save index to Global Offset Table
  3291. #endif
  3292.       "xorl %%ebx, %%ebx           \n\t" // ebx:  x offset
  3293. //pre "movl row, %%edi             \n\t"
  3294.       "xorl %%edx, %%edx           \n\t" // edx:  x-bpp offset
  3295. //pre "movl prev_row, %%esi        \n\t"
  3296.       "xorl %%eax, %%eax           \n\t"
  3297.  
  3298.       // Compute the Raw value for the first bpp bytes
  3299.       // Note: the formula works out to be always
  3300.       //   Paeth(x) = Raw(x) + Prior(x)      where x < bpp
  3301.    "paeth_rlp:                     \n\t"
  3302.       "movb (%%edi,%%ebx,), %%al   \n\t"
  3303.       "addb (%%esi,%%ebx,), %%al   \n\t"
  3304.       "incl %%ebx                  \n\t"
  3305. //pre "cmpl bpp, %%ebx             \n\t" (bpp is preloaded into ecx)
  3306.       "cmpl %%ecx, %%ebx           \n\t"
  3307.       "movb %%al, -1(%%edi,%%ebx,) \n\t"
  3308.       "jb paeth_rlp                \n\t"
  3309.       // get # of bytes to alignment
  3310.       "movl %%edi, _dif            \n\t" // take start of row
  3311.       "addl %%ebx, _dif            \n\t" // add bpp
  3312.       "xorl %%ecx, %%ecx           \n\t"
  3313.       "addl $0xf, _dif             \n\t" // add 7 + 8 to incr past alignment boundary
  3314.       "andl $0xfffffff8, _dif      \n\t" // mask to alignment boundary
  3315.       "subl %%edi, _dif            \n\t" // subtract from start ==> value ebx at alignment
  3316.       "jz paeth_go                 \n\t"
  3317.       // fix alignment
  3318.  
  3319.    "paeth_lp1:                     \n\t"
  3320.       "xorl %%eax, %%eax           \n\t"
  3321.       // pav = p - a = (a + b - c) - a = b - c
  3322.       "movb (%%esi,%%ebx,), %%al   \n\t" // load Prior(x) into al
  3323.       "movb (%%esi,%%edx,), %%cl   \n\t" // load Prior(x-bpp) into cl
  3324.       "subl %%ecx, %%eax           \n\t" // subtract Prior(x-bpp)
  3325.       "movl %%eax, _patemp         \n\t" // Save pav for later use
  3326.       "xorl %%eax, %%eax           \n\t"
  3327.       // pbv = p - b = (a + b - c) - b = a - c
  3328.       "movb (%%edi,%%edx,), %%al   \n\t" // load Raw(x-bpp) into al
  3329.       "subl %%ecx, %%eax           \n\t" // subtract Prior(x-bpp)
  3330.       "movl %%eax, %%ecx           \n\t"
  3331.       // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  3332.       "addl _patemp, %%eax         \n\t" // pcv = pav + pbv
  3333.       // pc = abs(pcv)
  3334.       "testl $0x80000000, %%eax    \n\t"
  3335.       "jz paeth_pca                \n\t"
  3336.       "negl %%eax                  \n\t" // reverse sign of neg values
  3337.  
  3338.    "paeth_pca:                     \n\t"
  3339.       "movl %%eax, _pctemp         \n\t" // save pc for later use
  3340.       // pb = abs(pbv)
  3341.       "testl $0x80000000, %%ecx    \n\t"
  3342.       "jz paeth_pba                \n\t"
  3343.       "negl %%ecx                  \n\t" // reverse sign of neg values
  3344.  
  3345.    "paeth_pba:                     \n\t"
  3346.       "movl %%ecx, _pbtemp         \n\t" // save pb for later use
  3347.       // pa = abs(pav)
  3348.       "movl _patemp, %%eax         \n\t"
  3349.       "testl $0x80000000, %%eax    \n\t"
  3350.       "jz paeth_paa                \n\t"
  3351.       "negl %%eax                  \n\t" // reverse sign of neg values
  3352.  
  3353.    "paeth_paa:                     \n\t"
  3354.       "movl %%eax, _patemp         \n\t" // save pa for later use
  3355.       // test if pa <= pb
  3356.       "cmpl %%ecx, %%eax           \n\t"
  3357.       "jna paeth_abb               \n\t"
  3358.       // pa > pb; now test if pb <= pc
  3359.       "cmpl _pctemp, %%ecx         \n\t"
  3360.       "jna paeth_bbc               \n\t"
  3361.       // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
  3362.       "movb (%%esi,%%edx,), %%cl   \n\t" // load Prior(x-bpp) into cl
  3363.       "jmp paeth_paeth             \n\t"
  3364.  
  3365.    "paeth_bbc:                     \n\t"
  3366.       // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
  3367.       "movb (%%esi,%%ebx,), %%cl   \n\t" // load Prior(x) into cl
  3368.       "jmp paeth_paeth             \n\t"
  3369.  
  3370.    "paeth_abb:                     \n\t"
  3371.       // pa <= pb; now test if pa <= pc
  3372.       "cmpl _pctemp, %%eax         \n\t"
  3373.       "jna paeth_abc               \n\t"
  3374.       // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
  3375.       "movb (%%esi,%%edx,), %%cl   \n\t" // load Prior(x-bpp) into cl
  3376.       "jmp paeth_paeth             \n\t"
  3377.  
  3378.    "paeth_abc:                     \n\t"
  3379.       // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
  3380.       "movb (%%edi,%%edx,), %%cl   \n\t" // load Raw(x-bpp) into cl
  3381.  
  3382.    "paeth_paeth:                   \n\t"
  3383.       "incl %%ebx                  \n\t"
  3384.       "incl %%edx                  \n\t"
  3385.       // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
  3386.       "addb %%cl, -1(%%edi,%%ebx,) \n\t"
  3387.       "cmpl _dif, %%ebx            \n\t"
  3388.       "jb paeth_lp1                \n\t"
  3389.  
  3390.    "paeth_go:                      \n\t"
  3391.       "movl _FullLength, %%ecx     \n\t"
  3392.       "movl %%ecx, %%eax           \n\t"
  3393.       "subl %%ebx, %%eax           \n\t" // subtract alignment fix
  3394.       "andl $0x00000007, %%eax     \n\t" // calc bytes over mult of 8
  3395.       "subl %%eax, %%ecx           \n\t" // drop over bytes from original length
  3396.       "movl %%ecx, _MMXLength      \n\t"
  3397. #ifdef __PIC__
  3398.       "popl %%ebx                  \n\t" // restore index to Global Offset Table
  3399. #endif
  3400.  
  3401.       : "=c" (dummy_value_c),            // output regs (dummy)
  3402.         "=S" (dummy_value_S),
  3403.         "=D" (dummy_value_D)
  3404.  
  3405.       : "0" (bpp),       // ecx          // input regs
  3406.         "1" (prev_row),  // esi
  3407.         "2" (row)        // edi
  3408.  
  3409.       : "%eax", "%edx"                   // clobber list
  3410. #ifndef __PIC__
  3411.       , "%ebx"
  3412. #endif
  3413.    );
  3414.  
  3415.    // now do the math for the rest of the row
  3416.    switch (bpp)
  3417.    {
  3418.       case 3:
  3419.       {
  3420.          _ActiveMask.use = 0x0000000000ffffffLL;
  3421.          _ActiveMaskEnd.use = 0xffff000000000000LL;
  3422.          _ShiftBpp.use = 24;    // == bpp(3) * 8
  3423.          _ShiftRem.use = 40;    // == 64 - 24
  3424.  
  3425.          __asm__ __volatile__ (
  3426.             "movl _dif, %%ecx            \n\t"
  3427. // preload  "movl row, %%edi             \n\t"
  3428. // preload  "movl prev_row, %%esi        \n\t"
  3429.             "pxor %%mm0, %%mm0           \n\t"
  3430.             // prime the pump:  load the first Raw(x-bpp) data set
  3431.             "movq -8(%%edi,%%ecx,), %%mm1 \n\t"
  3432.          "paeth_3lp:                     \n\t"
  3433.             "psrlq _ShiftRem, %%mm1      \n\t" // shift last 3 bytes to 1st 3 bytes
  3434.             "movq (%%esi,%%ecx,), %%mm2  \n\t" // load b=Prior(x)
  3435.             "punpcklbw %%mm0, %%mm1      \n\t" // unpack High bytes of a
  3436.             "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // prep c=Prior(x-bpp) bytes
  3437.             "punpcklbw %%mm0, %%mm2      \n\t" // unpack High bytes of b
  3438.             "psrlq _ShiftRem, %%mm3      \n\t" // shift last 3 bytes to 1st 3 bytes
  3439.             // pav = p - a = (a + b - c) - a = b - c
  3440.             "movq %%mm2, %%mm4           \n\t"
  3441.             "punpcklbw %%mm0, %%mm3      \n\t" // unpack High bytes of c
  3442.             // pbv = p - b = (a + b - c) - b = a - c
  3443.             "movq %%mm1, %%mm5           \n\t"
  3444.             "psubw %%mm3, %%mm4          \n\t"
  3445.             "pxor %%mm7, %%mm7           \n\t"
  3446.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  3447.             "movq %%mm4, %%mm6           \n\t"
  3448.             "psubw %%mm3, %%mm5          \n\t"
  3449.  
  3450.             // pa = abs(p-a) = abs(pav)
  3451.             // pb = abs(p-b) = abs(pbv)
  3452.             // pc = abs(p-c) = abs(pcv)
  3453.             "pcmpgtw %%mm4, %%mm0        \n\t" // create mask pav bytes < 0
  3454.             "paddw %%mm5, %%mm6          \n\t"
  3455.             "pand %%mm4, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3456.             "pcmpgtw %%mm5, %%mm7        \n\t" // create mask pbv bytes < 0
  3457.             "psubw %%mm0, %%mm4          \n\t"
  3458.             "pand %%mm5, %%mm7           \n\t" // only pbv bytes < 0 in mm0
  3459.             "psubw %%mm0, %%mm4          \n\t"
  3460.             "psubw %%mm7, %%mm5          \n\t"
  3461.             "pxor %%mm0, %%mm0           \n\t"
  3462.             "pcmpgtw %%mm6, %%mm0        \n\t" // create mask pcv bytes < 0
  3463.             "pand %%mm6, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3464.             "psubw %%mm7, %%mm5          \n\t"
  3465.             "psubw %%mm0, %%mm6          \n\t"
  3466.             //  test pa <= pb
  3467.             "movq %%mm4, %%mm7           \n\t"
  3468.             "psubw %%mm0, %%mm6          \n\t"
  3469.             "pcmpgtw %%mm5, %%mm7        \n\t" // pa > pb?
  3470.             "movq %%mm7, %%mm0           \n\t"
  3471.             // use mm7 mask to merge pa & pb
  3472.             "pand %%mm7, %%mm5           \n\t"
  3473.             // use mm0 mask copy to merge a & b
  3474.             "pand %%mm0, %%mm2           \n\t"
  3475.             "pandn %%mm4, %%mm7          \n\t"
  3476.             "pandn %%mm1, %%mm0          \n\t"
  3477.             "paddw %%mm5, %%mm7          \n\t"
  3478.             "paddw %%mm2, %%mm0          \n\t"
  3479.             //  test  ((pa <= pb)? pa:pb) <= pc
  3480.             "pcmpgtw %%mm6, %%mm7        \n\t" // pab > pc?
  3481.             "pxor %%mm1, %%mm1           \n\t"
  3482.             "pand %%mm7, %%mm3           \n\t"
  3483.             "pandn %%mm0, %%mm7          \n\t"
  3484.             "paddw %%mm3, %%mm7          \n\t"
  3485.             "pxor %%mm0, %%mm0           \n\t"
  3486.             "packuswb %%mm1, %%mm7       \n\t"
  3487.             "movq (%%esi,%%ecx,), %%mm3  \n\t" // load c=Prior(x-bpp)
  3488.             "pand _ActiveMask, %%mm7     \n\t"
  3489.             "movq %%mm3, %%mm2           \n\t" // load b=Prior(x) step 1
  3490.             "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor with Raw(x)
  3491.             "punpcklbw %%mm0, %%mm3      \n\t" // unpack High bytes of c
  3492.             "movq %%mm7, (%%edi,%%ecx,)  \n\t" // write back updated value
  3493.             "movq %%mm7, %%mm1           \n\t" // now mm1 will be used as Raw(x-bpp)
  3494.             // now do Paeth for 2nd set of bytes (3-5)
  3495.             "psrlq _ShiftBpp, %%mm2      \n\t" // load b=Prior(x) step 2
  3496.             "punpcklbw %%mm0, %%mm1      \n\t" // unpack High bytes of a
  3497.             "pxor %%mm7, %%mm7           \n\t"
  3498.             "punpcklbw %%mm0, %%mm2      \n\t" // unpack High bytes of b
  3499.             // pbv = p - b = (a + b - c) - b = a - c
  3500.             "movq %%mm1, %%mm5           \n\t"
  3501.             // pav = p - a = (a + b - c) - a = b - c
  3502.             "movq %%mm2, %%mm4           \n\t"
  3503.             "psubw %%mm3, %%mm5          \n\t"
  3504.             "psubw %%mm3, %%mm4          \n\t"
  3505.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) =
  3506.             //       pav + pbv = pbv + pav
  3507.             "movq %%mm5, %%mm6           \n\t"
  3508.             "paddw %%mm4, %%mm6          \n\t"
  3509.  
  3510.             // pa = abs(p-a) = abs(pav)
  3511.             // pb = abs(p-b) = abs(pbv)
  3512.             // pc = abs(p-c) = abs(pcv)
  3513.             "pcmpgtw %%mm5, %%mm0        \n\t" // create mask pbv bytes < 0
  3514.             "pcmpgtw %%mm4, %%mm7        \n\t" // create mask pav bytes < 0
  3515.             "pand %%mm5, %%mm0           \n\t" // only pbv bytes < 0 in mm0
  3516.             "pand %%mm4, %%mm7           \n\t" // only pav bytes < 0 in mm7
  3517.             "psubw %%mm0, %%mm5          \n\t"
  3518.             "psubw %%mm7, %%mm4          \n\t"
  3519.             "psubw %%mm0, %%mm5          \n\t"
  3520.             "psubw %%mm7, %%mm4          \n\t"
  3521.             "pxor %%mm0, %%mm0           \n\t"
  3522.             "pcmpgtw %%mm6, %%mm0        \n\t" // create mask pcv bytes < 0
  3523.             "pand %%mm6, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3524.             "psubw %%mm0, %%mm6          \n\t"
  3525.             //  test pa <= pb
  3526.             "movq %%mm4, %%mm7           \n\t"
  3527.             "psubw %%mm0, %%mm6          \n\t"
  3528.             "pcmpgtw %%mm5, %%mm7        \n\t" // pa > pb?
  3529.             "movq %%mm7, %%mm0           \n\t"
  3530.             // use mm7 mask to merge pa & pb
  3531.             "pand %%mm7, %%mm5           \n\t"
  3532.             // use mm0 mask copy to merge a & b
  3533.             "pand %%mm0, %%mm2           \n\t"
  3534.             "pandn %%mm4, %%mm7          \n\t"
  3535.             "pandn %%mm1, %%mm0          \n\t"
  3536.             "paddw %%mm5, %%mm7          \n\t"
  3537.             "paddw %%mm2, %%mm0          \n\t"
  3538.             //  test  ((pa <= pb)? pa:pb) <= pc
  3539.             "pcmpgtw %%mm6, %%mm7        \n\t" // pab > pc?
  3540.             "movq (%%esi,%%ecx,), %%mm2  \n\t" // load b=Prior(x)
  3541.             "pand %%mm7, %%mm3           \n\t"
  3542.             "pandn %%mm0, %%mm7          \n\t"
  3543.             "pxor %%mm1, %%mm1           \n\t"
  3544.             "paddw %%mm3, %%mm7          \n\t"
  3545.             "pxor %%mm0, %%mm0           \n\t"
  3546.             "packuswb %%mm1, %%mm7       \n\t"
  3547.             "movq %%mm2, %%mm3           \n\t" // load c=Prior(x-bpp) step 1
  3548.             "pand _ActiveMask, %%mm7     \n\t"
  3549.             "punpckhbw %%mm0, %%mm2      \n\t" // unpack High bytes of b
  3550.             "psllq _ShiftBpp, %%mm7      \n\t" // shift bytes to 2nd group of 3 bytes
  3551.              // pav = p - a = (a + b - c) - a = b - c
  3552.             "movq %%mm2, %%mm4           \n\t"
  3553.             "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor with Raw(x)
  3554.             "psllq _ShiftBpp, %%mm3      \n\t" // load c=Prior(x-bpp) step 2
  3555.             "movq %%mm7, (%%edi,%%ecx,)  \n\t" // write back updated value
  3556.             "movq %%mm7, %%mm1           \n\t"
  3557.             "punpckhbw %%mm0, %%mm3      \n\t" // unpack High bytes of c
  3558.             "psllq _ShiftBpp, %%mm1      \n\t" // shift bytes
  3559.                                     // now mm1 will be used as Raw(x-bpp)
  3560.             // now do Paeth for 3rd, and final, set of bytes (6-7)
  3561.             "pxor %%mm7, %%mm7           \n\t"
  3562.             "punpckhbw %%mm0, %%mm1      \n\t" // unpack High bytes of a
  3563.             "psubw %%mm3, %%mm4          \n\t"
  3564.             // pbv = p - b = (a + b - c) - b = a - c
  3565.             "movq %%mm1, %%mm5           \n\t"
  3566.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  3567.             "movq %%mm4, %%mm6           \n\t"
  3568.             "psubw %%mm3, %%mm5          \n\t"
  3569.             "pxor %%mm0, %%mm0           \n\t"
  3570.             "paddw %%mm5, %%mm6          \n\t"
  3571.  
  3572.             // pa = abs(p-a) = abs(pav)
  3573.             // pb = abs(p-b) = abs(pbv)
  3574.             // pc = abs(p-c) = abs(pcv)
  3575.             "pcmpgtw %%mm4, %%mm0        \n\t" // create mask pav bytes < 0
  3576.             "pcmpgtw %%mm5, %%mm7        \n\t" // create mask pbv bytes < 0
  3577.             "pand %%mm4, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3578.             "pand %%mm5, %%mm7           \n\t" // only pbv bytes < 0 in mm0
  3579.             "psubw %%mm0, %%mm4          \n\t"
  3580.             "psubw %%mm7, %%mm5          \n\t"
  3581.             "psubw %%mm0, %%mm4          \n\t"
  3582.             "psubw %%mm7, %%mm5          \n\t"
  3583.             "pxor %%mm0, %%mm0           \n\t"
  3584.             "pcmpgtw %%mm6, %%mm0        \n\t" // create mask pcv bytes < 0
  3585.             "pand %%mm6, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3586.             "psubw %%mm0, %%mm6          \n\t"
  3587.             //  test pa <= pb
  3588.             "movq %%mm4, %%mm7           \n\t"
  3589.             "psubw %%mm0, %%mm6          \n\t"
  3590.             "pcmpgtw %%mm5, %%mm7        \n\t" // pa > pb?
  3591.             "movq %%mm7, %%mm0           \n\t"
  3592.             // use mm0 mask copy to merge a & b
  3593.             "pand %%mm0, %%mm2           \n\t"
  3594.             // use mm7 mask to merge pa & pb
  3595.             "pand %%mm7, %%mm5           \n\t"
  3596.             "pandn %%mm1, %%mm0          \n\t"
  3597.             "pandn %%mm4, %%mm7          \n\t"
  3598.             "paddw %%mm2, %%mm0          \n\t"
  3599.             "paddw %%mm5, %%mm7          \n\t"
  3600.             //  test  ((pa <= pb)? pa:pb) <= pc
  3601.             "pcmpgtw %%mm6, %%mm7        \n\t" // pab > pc?
  3602.             "pand %%mm7, %%mm3           \n\t"
  3603.             "pandn %%mm0, %%mm7          \n\t"
  3604.             "paddw %%mm3, %%mm7          \n\t"
  3605.             "pxor %%mm1, %%mm1           \n\t"
  3606.             "packuswb %%mm7, %%mm1       \n\t"
  3607.             // step ecx to next set of 8 bytes and repeat loop til done
  3608.             "addl $8, %%ecx              \n\t"
  3609.             "pand _ActiveMaskEnd, %%mm1  \n\t"
  3610.             "paddb -8(%%edi,%%ecx,), %%mm1 \n\t" // add Paeth predictor with Raw(x)
  3611.  
  3612.             "cmpl _MMXLength, %%ecx      \n\t"
  3613.             "pxor %%mm0, %%mm0           \n\t" // pxor does not affect flags
  3614.             "movq %%mm1, -8(%%edi,%%ecx,) \n\t" // write back updated value
  3615.                                  // mm1 will be used as Raw(x-bpp) next loop
  3616.                            // mm3 ready to be used as Prior(x-bpp) next loop
  3617.             "jb paeth_3lp                \n\t"
  3618.  
  3619.             : "=S" (dummy_value_S),             // output regs (dummy)
  3620.               "=D" (dummy_value_D)
  3621.  
  3622.             : "0" (prev_row),  // esi           // input regs
  3623.               "1" (row)        // edi
  3624.  
  3625.             : "%ecx"                            // clobber list
  3626. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  3627.             , "%mm0", "%mm1", "%mm2", "%mm3"
  3628.             , "%mm4", "%mm5", "%mm6", "%mm7"
  3629. #endif
  3630.          );
  3631.       }
  3632.       break;  // end 3 bpp
  3633.  
  3634.       case 6:
  3635.       //case 7:   // GRR BOGUS
  3636.       //case 5:   // GRR BOGUS
  3637.       {
  3638.          _ActiveMask.use  = 0x00000000ffffffffLL;
  3639.          _ActiveMask2.use = 0xffffffff00000000LL;
  3640.          _ShiftBpp.use = bpp << 3;    // == bpp * 8
  3641.          _ShiftRem.use = 64 - _ShiftBpp.use;
  3642.  
  3643.          __asm__ __volatile__ (
  3644.             "movl _dif, %%ecx            \n\t"
  3645. // preload  "movl row, %%edi             \n\t"
  3646. // preload  "movl prev_row, %%esi        \n\t"
  3647.             // prime the pump:  load the first Raw(x-bpp) data set
  3648.             "movq -8(%%edi,%%ecx,), %%mm1 \n\t"
  3649.             "pxor %%mm0, %%mm0           \n\t"
  3650.  
  3651.          "paeth_6lp:                     \n\t"
  3652.             // must shift to position Raw(x-bpp) data
  3653.             "psrlq _ShiftRem, %%mm1      \n\t"
  3654.             // do first set of 4 bytes
  3655.             "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes
  3656.             "punpcklbw %%mm0, %%mm1      \n\t" // unpack Low bytes of a
  3657.             "movq (%%esi,%%ecx,), %%mm2  \n\t" // load b=Prior(x)
  3658.             "punpcklbw %%mm0, %%mm2      \n\t" // unpack Low bytes of b
  3659.             // must shift to position Prior(x-bpp) data
  3660.             "psrlq _ShiftRem, %%mm3      \n\t"
  3661.             // pav = p - a = (a + b - c) - a = b - c
  3662.             "movq %%mm2, %%mm4           \n\t"
  3663.             "punpcklbw %%mm0, %%mm3      \n\t" // unpack Low bytes of c
  3664.             // pbv = p - b = (a + b - c) - b = a - c
  3665.             "movq %%mm1, %%mm5           \n\t"
  3666.             "psubw %%mm3, %%mm4          \n\t"
  3667.             "pxor %%mm7, %%mm7           \n\t"
  3668.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  3669.             "movq %%mm4, %%mm6           \n\t"
  3670.             "psubw %%mm3, %%mm5          \n\t"
  3671.             // pa = abs(p-a) = abs(pav)
  3672.             // pb = abs(p-b) = abs(pbv)
  3673.             // pc = abs(p-c) = abs(pcv)
  3674.             "pcmpgtw %%mm4, %%mm0        \n\t" // create mask pav bytes < 0
  3675.             "paddw %%mm5, %%mm6          \n\t"
  3676.             "pand %%mm4, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3677.             "pcmpgtw %%mm5, %%mm7        \n\t" // create mask pbv bytes < 0
  3678.             "psubw %%mm0, %%mm4          \n\t"
  3679.             "pand %%mm5, %%mm7           \n\t" // only pbv bytes < 0 in mm0
  3680.             "psubw %%mm0, %%mm4          \n\t"
  3681.             "psubw %%mm7, %%mm5          \n\t"
  3682.             "pxor %%mm0, %%mm0           \n\t"
  3683.             "pcmpgtw %%mm6, %%mm0        \n\t" // create mask pcv bytes < 0
  3684.             "pand %%mm6, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3685.             "psubw %%mm7, %%mm5          \n\t"
  3686.             "psubw %%mm0, %%mm6          \n\t"
  3687.             //  test pa <= pb
  3688.             "movq %%mm4, %%mm7           \n\t"
  3689.             "psubw %%mm0, %%mm6          \n\t"
  3690.             "pcmpgtw %%mm5, %%mm7        \n\t" // pa > pb?
  3691.             "movq %%mm7, %%mm0           \n\t"
  3692.             // use mm7 mask to merge pa & pb
  3693.             "pand %%mm7, %%mm5           \n\t"
  3694.             // use mm0 mask copy to merge a & b
  3695.             "pand %%mm0, %%mm2           \n\t"
  3696.             "pandn %%mm4, %%mm7          \n\t"
  3697.             "pandn %%mm1, %%mm0          \n\t"
  3698.             "paddw %%mm5, %%mm7          \n\t"
  3699.             "paddw %%mm2, %%mm0          \n\t"
  3700.             //  test  ((pa <= pb)? pa:pb) <= pc
  3701.             "pcmpgtw %%mm6, %%mm7        \n\t" // pab > pc?
  3702.             "pxor %%mm1, %%mm1           \n\t"
  3703.             "pand %%mm7, %%mm3           \n\t"
  3704.             "pandn %%mm0, %%mm7          \n\t"
  3705.             "paddw %%mm3, %%mm7          \n\t"
  3706.             "pxor %%mm0, %%mm0           \n\t"
  3707.             "packuswb %%mm1, %%mm7       \n\t"
  3708.             "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // load c=Prior(x-bpp)
  3709.             "pand _ActiveMask, %%mm7     \n\t"
  3710.             "psrlq _ShiftRem, %%mm3      \n\t"
  3711.             "movq (%%esi,%%ecx,), %%mm2  \n\t" // load b=Prior(x) step 1
  3712.             "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor and Raw(x)
  3713.             "movq %%mm2, %%mm6           \n\t"
  3714.             "movq %%mm7, (%%edi,%%ecx,)  \n\t" // write back updated value
  3715.             "movq -8(%%edi,%%ecx,), %%mm1 \n\t"
  3716.             "psllq _ShiftBpp, %%mm6      \n\t"
  3717.             "movq %%mm7, %%mm5           \n\t"
  3718.             "psrlq _ShiftRem, %%mm1      \n\t"
  3719.             "por %%mm6, %%mm3            \n\t"
  3720.             "psllq _ShiftBpp, %%mm5      \n\t"
  3721.             "punpckhbw %%mm0, %%mm3      \n\t" // unpack High bytes of c
  3722.             "por %%mm5, %%mm1            \n\t"
  3723.             // do second set of 4 bytes
  3724.             "punpckhbw %%mm0, %%mm2      \n\t" // unpack High bytes of b
  3725.             "punpckhbw %%mm0, %%mm1      \n\t" // unpack High bytes of a
  3726.             // pav = p - a = (a + b - c) - a = b - c
  3727.             "movq %%mm2, %%mm4           \n\t"
  3728.             // pbv = p - b = (a + b - c) - b = a - c
  3729.             "movq %%mm1, %%mm5           \n\t"
  3730.             "psubw %%mm3, %%mm4          \n\t"
  3731.             "pxor %%mm7, %%mm7           \n\t"
  3732.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  3733.             "movq %%mm4, %%mm6           \n\t"
  3734.             "psubw %%mm3, %%mm5          \n\t"
  3735.             // pa = abs(p-a) = abs(pav)
  3736.             // pb = abs(p-b) = abs(pbv)
  3737.             // pc = abs(p-c) = abs(pcv)
  3738.             "pcmpgtw %%mm4, %%mm0        \n\t" // create mask pav bytes < 0
  3739.             "paddw %%mm5, %%mm6          \n\t"
  3740.             "pand %%mm4, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3741.             "pcmpgtw %%mm5, %%mm7        \n\t" // create mask pbv bytes < 0
  3742.             "psubw %%mm0, %%mm4          \n\t"
  3743.             "pand %%mm5, %%mm7           \n\t" // only pbv bytes < 0 in mm0
  3744.             "psubw %%mm0, %%mm4          \n\t"
  3745.             "psubw %%mm7, %%mm5          \n\t"
  3746.             "pxor %%mm0, %%mm0           \n\t"
  3747.             "pcmpgtw %%mm6, %%mm0        \n\t" // create mask pcv bytes < 0
  3748.             "pand %%mm6, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3749.             "psubw %%mm7, %%mm5          \n\t"
  3750.             "psubw %%mm0, %%mm6          \n\t"
  3751.             //  test pa <= pb
  3752.             "movq %%mm4, %%mm7           \n\t"
  3753.             "psubw %%mm0, %%mm6          \n\t"
  3754.             "pcmpgtw %%mm5, %%mm7        \n\t" // pa > pb?
  3755.             "movq %%mm7, %%mm0           \n\t"
  3756.             // use mm7 mask to merge pa & pb
  3757.             "pand %%mm7, %%mm5           \n\t"
  3758.             // use mm0 mask copy to merge a & b
  3759.             "pand %%mm0, %%mm2           \n\t"
  3760.             "pandn %%mm4, %%mm7          \n\t"
  3761.             "pandn %%mm1, %%mm0          \n\t"
  3762.             "paddw %%mm5, %%mm7          \n\t"
  3763.             "paddw %%mm2, %%mm0          \n\t"
  3764.             //  test  ((pa <= pb)? pa:pb) <= pc
  3765.             "pcmpgtw %%mm6, %%mm7        \n\t" // pab > pc?
  3766.             "pxor %%mm1, %%mm1           \n\t"
  3767.             "pand %%mm7, %%mm3           \n\t"
  3768.             "pandn %%mm0, %%mm7          \n\t"
  3769.             "pxor %%mm1, %%mm1           \n\t"
  3770.             "paddw %%mm3, %%mm7          \n\t"
  3771.             "pxor %%mm0, %%mm0           \n\t"
  3772.             // step ecx to next set of 8 bytes and repeat loop til done
  3773.             "addl $8, %%ecx              \n\t"
  3774.             "packuswb %%mm7, %%mm1       \n\t"
  3775.             "paddb -8(%%edi,%%ecx,), %%mm1 \n\t" // add Paeth predictor with Raw(x)
  3776.             "cmpl _MMXLength, %%ecx      \n\t"
  3777.             "movq %%mm1, -8(%%edi,%%ecx,) \n\t" // write back updated value
  3778.                                 // mm1 will be used as Raw(x-bpp) next loop
  3779.             "jb paeth_6lp                \n\t"
  3780.  
  3781.             : "=S" (dummy_value_S),             // output regs (dummy)
  3782.               "=D" (dummy_value_D)
  3783.  
  3784.             : "0" (prev_row),  // esi           // input regs
  3785.               "1" (row)        // edi
  3786.  
  3787.             : "%ecx"                            // clobber list
  3788. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  3789.             , "%mm0", "%mm1", "%mm2", "%mm3"
  3790.             , "%mm4", "%mm5", "%mm6", "%mm7"
  3791. #endif
  3792.          );
  3793.       }
  3794.       break;  // end 6 bpp
  3795.  
  3796.       case 4:
  3797.       {
  3798.          _ActiveMask.use  = 0x00000000ffffffffLL;
  3799.  
  3800.          __asm__ __volatile__ (
  3801.             "movl _dif, %%ecx            \n\t"
  3802. // preload  "movl row, %%edi             \n\t"
  3803. // preload  "movl prev_row, %%esi        \n\t"
  3804.             "pxor %%mm0, %%mm0           \n\t"
  3805.             // prime the pump:  load the first Raw(x-bpp) data set
  3806.             "movq -8(%%edi,%%ecx,), %%mm1 \n\t" // only time should need to read
  3807.                                      //  a=Raw(x-bpp) bytes
  3808.          "paeth_4lp:                     \n\t"
  3809.             // do first set of 4 bytes
  3810.             "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes
  3811.             "punpckhbw %%mm0, %%mm1      \n\t" // unpack Low bytes of a
  3812.             "movq (%%esi,%%ecx,), %%mm2  \n\t" // load b=Prior(x)
  3813.             "punpcklbw %%mm0, %%mm2      \n\t" // unpack High bytes of b
  3814.             // pav = p - a = (a + b - c) - a = b - c
  3815.             "movq %%mm2, %%mm4           \n\t"
  3816.             "punpckhbw %%mm0, %%mm3      \n\t" // unpack High bytes of c
  3817.             // pbv = p - b = (a + b - c) - b = a - c
  3818.             "movq %%mm1, %%mm5           \n\t"
  3819.             "psubw %%mm3, %%mm4          \n\t"
  3820.             "pxor %%mm7, %%mm7           \n\t"
  3821.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  3822.             "movq %%mm4, %%mm6           \n\t"
  3823.             "psubw %%mm3, %%mm5          \n\t"
  3824.             // pa = abs(p-a) = abs(pav)
  3825.             // pb = abs(p-b) = abs(pbv)
  3826.             // pc = abs(p-c) = abs(pcv)
  3827.             "pcmpgtw %%mm4, %%mm0        \n\t" // create mask pav bytes < 0
  3828.             "paddw %%mm5, %%mm6          \n\t"
  3829.             "pand %%mm4, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3830.             "pcmpgtw %%mm5, %%mm7        \n\t" // create mask pbv bytes < 0
  3831.             "psubw %%mm0, %%mm4          \n\t"
  3832.             "pand %%mm5, %%mm7           \n\t" // only pbv bytes < 0 in mm0
  3833.             "psubw %%mm0, %%mm4          \n\t"
  3834.             "psubw %%mm7, %%mm5          \n\t"
  3835.             "pxor %%mm0, %%mm0           \n\t"
  3836.             "pcmpgtw %%mm6, %%mm0        \n\t" // create mask pcv bytes < 0
  3837.             "pand %%mm6, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3838.             "psubw %%mm7, %%mm5          \n\t"
  3839.             "psubw %%mm0, %%mm6          \n\t"
  3840.             //  test pa <= pb
  3841.             "movq %%mm4, %%mm7           \n\t"
  3842.             "psubw %%mm0, %%mm6          \n\t"
  3843.             "pcmpgtw %%mm5, %%mm7        \n\t" // pa > pb?
  3844.             "movq %%mm7, %%mm0           \n\t"
  3845.             // use mm7 mask to merge pa & pb
  3846.             "pand %%mm7, %%mm5           \n\t"
  3847.             // use mm0 mask copy to merge a & b
  3848.             "pand %%mm0, %%mm2           \n\t"
  3849.             "pandn %%mm4, %%mm7          \n\t"
  3850.             "pandn %%mm1, %%mm0          \n\t"
  3851.             "paddw %%mm5, %%mm7          \n\t"
  3852.             "paddw %%mm2, %%mm0          \n\t"
  3853.             //  test  ((pa <= pb)? pa:pb) <= pc
  3854.             "pcmpgtw %%mm6, %%mm7        \n\t" // pab > pc?
  3855.             "pxor %%mm1, %%mm1           \n\t"
  3856.             "pand %%mm7, %%mm3           \n\t"
  3857.             "pandn %%mm0, %%mm7          \n\t"
  3858.             "paddw %%mm3, %%mm7          \n\t"
  3859.             "pxor %%mm0, %%mm0           \n\t"
  3860.             "packuswb %%mm1, %%mm7       \n\t"
  3861.             "movq (%%esi,%%ecx,), %%mm3  \n\t" // load c=Prior(x-bpp)
  3862.             "pand _ActiveMask, %%mm7     \n\t"
  3863.             "movq %%mm3, %%mm2           \n\t" // load b=Prior(x) step 1
  3864.             "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor with Raw(x)
  3865.             "punpcklbw %%mm0, %%mm3      \n\t" // unpack High bytes of c
  3866.             "movq %%mm7, (%%edi,%%ecx,)  \n\t" // write back updated value
  3867.             "movq %%mm7, %%mm1           \n\t" // now mm1 will be used as Raw(x-bpp)
  3868.             // do second set of 4 bytes
  3869.             "punpckhbw %%mm0, %%mm2      \n\t" // unpack Low bytes of b
  3870.             "punpcklbw %%mm0, %%mm1      \n\t" // unpack Low bytes of a
  3871.             // pav = p - a = (a + b - c) - a = b - c
  3872.             "movq %%mm2, %%mm4           \n\t"
  3873.             // pbv = p - b = (a + b - c) - b = a - c
  3874.             "movq %%mm1, %%mm5           \n\t"
  3875.             "psubw %%mm3, %%mm4          \n\t"
  3876.             "pxor %%mm7, %%mm7           \n\t"
  3877.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  3878.             "movq %%mm4, %%mm6           \n\t"
  3879.             "psubw %%mm3, %%mm5          \n\t"
  3880.             // pa = abs(p-a) = abs(pav)
  3881.             // pb = abs(p-b) = abs(pbv)
  3882.             // pc = abs(p-c) = abs(pcv)
  3883.             "pcmpgtw %%mm4, %%mm0        \n\t" // create mask pav bytes < 0
  3884.             "paddw %%mm5, %%mm6          \n\t"
  3885.             "pand %%mm4, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3886.             "pcmpgtw %%mm5, %%mm7        \n\t" // create mask pbv bytes < 0
  3887.             "psubw %%mm0, %%mm4          \n\t"
  3888.             "pand %%mm5, %%mm7           \n\t" // only pbv bytes < 0 in mm0
  3889.             "psubw %%mm0, %%mm4          \n\t"
  3890.             "psubw %%mm7, %%mm5          \n\t"
  3891.             "pxor %%mm0, %%mm0           \n\t"
  3892.             "pcmpgtw %%mm6, %%mm0        \n\t" // create mask pcv bytes < 0
  3893.             "pand %%mm6, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3894.             "psubw %%mm7, %%mm5          \n\t"
  3895.             "psubw %%mm0, %%mm6          \n\t"
  3896.             //  test pa <= pb
  3897.             "movq %%mm4, %%mm7           \n\t"
  3898.             "psubw %%mm0, %%mm6          \n\t"
  3899.             "pcmpgtw %%mm5, %%mm7        \n\t" // pa > pb?
  3900.             "movq %%mm7, %%mm0           \n\t"
  3901.             // use mm7 mask to merge pa & pb
  3902.             "pand %%mm7, %%mm5           \n\t"
  3903.             // use mm0 mask copy to merge a & b
  3904.             "pand %%mm0, %%mm2           \n\t"
  3905.             "pandn %%mm4, %%mm7          \n\t"
  3906.             "pandn %%mm1, %%mm0          \n\t"
  3907.             "paddw %%mm5, %%mm7          \n\t"
  3908.             "paddw %%mm2, %%mm0          \n\t"
  3909.             //  test  ((pa <= pb)? pa:pb) <= pc
  3910.             "pcmpgtw %%mm6, %%mm7        \n\t" // pab > pc?
  3911.             "pxor %%mm1, %%mm1           \n\t"
  3912.             "pand %%mm7, %%mm3           \n\t"
  3913.             "pandn %%mm0, %%mm7          \n\t"
  3914.             "pxor %%mm1, %%mm1           \n\t"
  3915.             "paddw %%mm3, %%mm7          \n\t"
  3916.             "pxor %%mm0, %%mm0           \n\t"
  3917.             // step ecx to next set of 8 bytes and repeat loop til done
  3918.             "addl $8, %%ecx              \n\t"
  3919.             "packuswb %%mm7, %%mm1       \n\t"
  3920.             "paddb -8(%%edi,%%ecx,), %%mm1 \n\t" // add predictor with Raw(x)
  3921.             "cmpl _MMXLength, %%ecx      \n\t"
  3922.             "movq %%mm1, -8(%%edi,%%ecx,) \n\t" // write back updated value
  3923.                                 // mm1 will be used as Raw(x-bpp) next loop
  3924.             "jb paeth_4lp                \n\t"
  3925.  
  3926.             : "=S" (dummy_value_S),             // output regs (dummy)
  3927.               "=D" (dummy_value_D)
  3928.  
  3929.             : "0" (prev_row),  // esi           // input regs
  3930.               "1" (row)        // edi
  3931.  
  3932.             : "%ecx"                            // clobber list
  3933. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  3934.             , "%mm0", "%mm1", "%mm2", "%mm3"
  3935.             , "%mm4", "%mm5", "%mm6", "%mm7"
  3936. #endif
  3937.          );
  3938.       }
  3939.       break;  // end 4 bpp
  3940.  
  3941.       case 8:                          // bpp == 8
  3942.       {
  3943.          _ActiveMask.use  = 0x00000000ffffffffLL;
  3944.  
  3945.          __asm__ __volatile__ (
  3946.             "movl _dif, %%ecx            \n\t"
  3947. // preload  "movl row, %%edi             \n\t"
  3948. // preload  "movl prev_row, %%esi        \n\t"
  3949.             "pxor %%mm0, %%mm0           \n\t"
  3950.             // prime the pump:  load the first Raw(x-bpp) data set
  3951.             "movq -8(%%edi,%%ecx,), %%mm1 \n\t" // only time should need to read
  3952.                                        //  a=Raw(x-bpp) bytes
  3953.          "paeth_8lp:                     \n\t"
  3954.             // do first set of 4 bytes
  3955.             "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes
  3956.             "punpcklbw %%mm0, %%mm1      \n\t" // unpack Low bytes of a
  3957.             "movq (%%esi,%%ecx,), %%mm2  \n\t" // load b=Prior(x)
  3958.             "punpcklbw %%mm0, %%mm2      \n\t" // unpack Low bytes of b
  3959.             // pav = p - a = (a + b - c) - a = b - c
  3960.             "movq %%mm2, %%mm4           \n\t"
  3961.             "punpcklbw %%mm0, %%mm3      \n\t" // unpack Low bytes of c
  3962.             // pbv = p - b = (a + b - c) - b = a - c
  3963.             "movq %%mm1, %%mm5           \n\t"
  3964.             "psubw %%mm3, %%mm4          \n\t"
  3965.             "pxor %%mm7, %%mm7           \n\t"
  3966.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  3967.             "movq %%mm4, %%mm6           \n\t"
  3968.             "psubw %%mm3, %%mm5          \n\t"
  3969.             // pa = abs(p-a) = abs(pav)
  3970.             // pb = abs(p-b) = abs(pbv)
  3971.             // pc = abs(p-c) = abs(pcv)
  3972.             "pcmpgtw %%mm4, %%mm0        \n\t" // create mask pav bytes < 0
  3973.             "paddw %%mm5, %%mm6          \n\t"
  3974.             "pand %%mm4, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3975.             "pcmpgtw %%mm5, %%mm7        \n\t" // create mask pbv bytes < 0
  3976.             "psubw %%mm0, %%mm4          \n\t"
  3977.             "pand %%mm5, %%mm7           \n\t" // only pbv bytes < 0 in mm0
  3978.             "psubw %%mm0, %%mm4          \n\t"
  3979.             "psubw %%mm7, %%mm5          \n\t"
  3980.             "pxor %%mm0, %%mm0           \n\t"
  3981.             "pcmpgtw %%mm6, %%mm0        \n\t" // create mask pcv bytes < 0
  3982.             "pand %%mm6, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3983.             "psubw %%mm7, %%mm5          \n\t"
  3984.             "psubw %%mm0, %%mm6          \n\t"
  3985.             //  test pa <= pb
  3986.             "movq %%mm4, %%mm7           \n\t"
  3987.             "psubw %%mm0, %%mm6          \n\t"
  3988.             "pcmpgtw %%mm5, %%mm7        \n\t" // pa > pb?
  3989.             "movq %%mm7, %%mm0           \n\t"
  3990.             // use mm7 mask to merge pa & pb
  3991.             "pand %%mm7, %%mm5           \n\t"
  3992.             // use mm0 mask copy to merge a & b
  3993.             "pand %%mm0, %%mm2           \n\t"
  3994.             "pandn %%mm4, %%mm7          \n\t"
  3995.             "pandn %%mm1, %%mm0          \n\t"
  3996.             "paddw %%mm5, %%mm7          \n\t"
  3997.             "paddw %%mm2, %%mm0          \n\t"
  3998.             //  test  ((pa <= pb)? pa:pb) <= pc
  3999.             "pcmpgtw %%mm6, %%mm7        \n\t" // pab > pc?
  4000.             "pxor %%mm1, %%mm1           \n\t"
  4001.             "pand %%mm7, %%mm3           \n\t"
  4002.             "pandn %%mm0, %%mm7          \n\t"
  4003.             "paddw %%mm3, %%mm7          \n\t"
  4004.             "pxor %%mm0, %%mm0           \n\t"
  4005.             "packuswb %%mm1, %%mm7       \n\t"
  4006.             "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes
  4007.             "pand _ActiveMask, %%mm7     \n\t"
  4008.             "movq (%%esi,%%ecx,), %%mm2  \n\t" // load b=Prior(x)
  4009.             "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor with Raw(x)
  4010.             "punpckhbw %%mm0, %%mm3      \n\t" // unpack High bytes of c
  4011.             "movq %%mm7, (%%edi,%%ecx,)  \n\t" // write back updated value
  4012.             "movq -8(%%edi,%%ecx,), %%mm1 \n\t" // read a=Raw(x-bpp) bytes
  4013.  
  4014.             // do second set of 4 bytes
  4015.             "punpckhbw %%mm0, %%mm2      \n\t" // unpack High bytes of b
  4016.             "punpckhbw %%mm0, %%mm1      \n\t" // unpack High bytes of a
  4017.             // pav = p - a = (a + b - c) - a = b - c
  4018.             "movq %%mm2, %%mm4           \n\t"
  4019.             // pbv = p - b = (a + b - c) - b = a - c
  4020.             "movq %%mm1, %%mm5           \n\t"
  4021.             "psubw %%mm3, %%mm4          \n\t"
  4022.             "pxor %%mm7, %%mm7           \n\t"
  4023.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  4024.             "movq %%mm4, %%mm6           \n\t"
  4025.             "psubw %%mm3, %%mm5          \n\t"
  4026.             // pa = abs(p-a) = abs(pav)
  4027.             // pb = abs(p-b) = abs(pbv)
  4028.             // pc = abs(p-c) = abs(pcv)
  4029.             "pcmpgtw %%mm4, %%mm0        \n\t" // create mask pav bytes < 0
  4030.             "paddw %%mm5, %%mm6          \n\t"
  4031.             "pand %%mm4, %%mm0           \n\t" // only pav bytes < 0 in mm7
  4032.             "pcmpgtw %%mm5, %%mm7        \n\t" // create mask pbv bytes < 0
  4033.             "psubw %%mm0, %%mm4          \n\t"
  4034.             "pand %%mm5, %%mm7           \n\t" // only pbv bytes < 0 in mm0
  4035.             "psubw %%mm0, %%mm4          \n\t"
  4036.             "psubw %%mm7, %%mm5          \n\t"
  4037.             "pxor %%mm0, %%mm0           \n\t"
  4038.             "pcmpgtw %%mm6, %%mm0        \n\t" // create mask pcv bytes < 0
  4039.             "pand %%mm6, %%mm0           \n\t" // only pav bytes < 0 in mm7
  4040.             "psubw %%mm7, %%mm5          \n\t"
  4041.             "psubw %%mm0, %%mm6          \n\t"
  4042.             //  test pa <= pb
  4043.             "movq %%mm4, %%mm7           \n\t"
  4044.             "psubw %%mm0, %%mm6          \n\t"
  4045.             "pcmpgtw %%mm5, %%mm7        \n\t" // pa > pb?
  4046.             "movq %%mm7, %%mm0           \n\t"
  4047.             // use mm7 mask to merge pa & pb
  4048.             "pand %%mm7, %%mm5           \n\t"
  4049.             // use mm0 mask copy to merge a & b
  4050.             "pand %%mm0, %%mm2           \n\t"
  4051.             "pandn %%mm4, %%mm7          \n\t"
  4052.             "pandn %%mm1, %%mm0          \n\t"
  4053.             "paddw %%mm5, %%mm7          \n\t"
  4054.             "paddw %%mm2, %%mm0          \n\t"
  4055.             //  test  ((pa <= pb)? pa:pb) <= pc
  4056.             "pcmpgtw %%mm6, %%mm7        \n\t" // pab > pc?
  4057.             "pxor %%mm1, %%mm1           \n\t"
  4058.             "pand %%mm7, %%mm3           \n\t"
  4059.             "pandn %%mm0, %%mm7          \n\t"
  4060.             "pxor %%mm1, %%mm1           \n\t"
  4061.             "paddw %%mm3, %%mm7          \n\t"
  4062.             "pxor %%mm0, %%mm0           \n\t"
  4063.             // step ecx to next set of 8 bytes and repeat loop til done
  4064.             "addl $8, %%ecx              \n\t"
  4065.             "packuswb %%mm7, %%mm1       \n\t"
  4066.             "paddb -8(%%edi,%%ecx,), %%mm1 \n\t" // add Paeth predictor with Raw(x)
  4067.             "cmpl _MMXLength, %%ecx      \n\t"
  4068.             "movq %%mm1, -8(%%edi,%%ecx,) \n\t" // write back updated value
  4069.                             // mm1 will be used as Raw(x-bpp) next loop
  4070.             "jb paeth_8lp                \n\t"
  4071.  
  4072.             : "=S" (dummy_value_S),             // output regs (dummy)
  4073.               "=D" (dummy_value_D)
  4074.  
  4075.             : "0" (prev_row),  // esi           // input regs
  4076.               "1" (row)        // edi
  4077.  
  4078.             : "%ecx"                            // clobber list
  4079. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  4080.             , "%mm0", "%mm1", "%mm2", "%mm3"
  4081.             , "%mm4", "%mm5", "%mm6", "%mm7"
  4082. #endif
  4083.          );
  4084.       }
  4085.       break;  // end 8 bpp
  4086.  
  4087.       case 1:                // bpp = 1
  4088.       case 2:                // bpp = 2
  4089.       default:               // bpp > 8
  4090.       {
  4091.          __asm__ __volatile__ (
  4092. #ifdef __PIC__
  4093.             "pushl %%ebx                 \n\t" // save Global Offset Table index
  4094. #endif
  4095.             "movl _dif, %%ebx            \n\t"
  4096.             "cmpl _FullLength, %%ebx     \n\t"
  4097.             "jnb paeth_dend              \n\t"
  4098.  
  4099. // preload  "movl row, %%edi             \n\t"
  4100. // preload  "movl prev_row, %%esi        \n\t"
  4101.             // do Paeth decode for remaining bytes
  4102.             "movl %%ebx, %%edx           \n\t"
  4103. // preload  "subl bpp, %%edx             \n\t" // (bpp is preloaded into ecx)
  4104.             "subl %%ecx, %%edx           \n\t" // edx = ebx - bpp
  4105.             "xorl %%ecx, %%ecx           \n\t" // zero ecx before using cl & cx
  4106.  
  4107.          "paeth_dlp:                     \n\t"
  4108.             "xorl %%eax, %%eax           \n\t"
  4109.             // pav = p - a = (a + b - c) - a = b - c
  4110.             "movb (%%esi,%%ebx,), %%al   \n\t" // load Prior(x) into al
  4111.             "movb (%%esi,%%edx,), %%cl   \n\t" // load Prior(x-bpp) into cl
  4112.             "subl %%ecx, %%eax           \n\t" // subtract Prior(x-bpp)
  4113.             "movl %%eax, _patemp         \n\t" // Save pav for later use
  4114.             "xorl %%eax, %%eax           \n\t"
  4115.             // pbv = p - b = (a + b - c) - b = a - c
  4116.             "movb (%%edi,%%edx,), %%al   \n\t" // load Raw(x-bpp) into al
  4117.             "subl %%ecx, %%eax           \n\t" // subtract Prior(x-bpp)
  4118.             "movl %%eax, %%ecx           \n\t"
  4119.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  4120.             "addl _patemp, %%eax         \n\t" // pcv = pav + pbv
  4121.             // pc = abs(pcv)
  4122.             "testl $0x80000000, %%eax    \n\t"
  4123.             "jz paeth_dpca               \n\t"
  4124.             "negl %%eax                  \n\t" // reverse sign of neg values
  4125.  
  4126.          "paeth_dpca:                    \n\t"
  4127.             "movl %%eax, _pctemp         \n\t" // save pc for later use
  4128.             // pb = abs(pbv)
  4129.             "testl $0x80000000, %%ecx    \n\t"
  4130.             "jz paeth_dpba               \n\t"
  4131.             "negl %%ecx                  \n\t" // reverse sign of neg values
  4132.  
  4133.          "paeth_dpba:                    \n\t"
  4134.             "movl %%ecx, _pbtemp         \n\t" // save pb for later use
  4135.             // pa = abs(pav)
  4136.             "movl _patemp, %%eax         \n\t"
  4137.             "testl $0x80000000, %%eax    \n\t"
  4138.             "jz paeth_dpaa               \n\t"
  4139.             "negl %%eax                  \n\t" // reverse sign of neg values
  4140.  
  4141.          "paeth_dpaa:                    \n\t"
  4142.             "movl %%eax, _patemp         \n\t" // save pa for later use
  4143.             // test if pa <= pb
  4144.             "cmpl %%ecx, %%eax           \n\t"
  4145.             "jna paeth_dabb              \n\t"
  4146.             // pa > pb; now test if pb <= pc
  4147.             "cmpl _pctemp, %%ecx         \n\t"
  4148.             "jna paeth_dbbc              \n\t"
  4149.             // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
  4150.             "movb (%%esi,%%edx,), %%cl   \n\t" // load Prior(x-bpp) into cl
  4151.             "jmp paeth_dpaeth            \n\t"
  4152.  
  4153.          "paeth_dbbc:                    \n\t"
  4154.             // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
  4155.             "movb (%%esi,%%ebx,), %%cl   \n\t" // load Prior(x) into cl
  4156.             "jmp paeth_dpaeth            \n\t"
  4157.  
  4158.          "paeth_dabb:                    \n\t"
  4159.             // pa <= pb; now test if pa <= pc
  4160.             "cmpl _pctemp, %%eax         \n\t"
  4161.             "jna paeth_dabc              \n\t"
  4162.             // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
  4163.             "movb (%%esi,%%edx,), %%cl   \n\t" // load Prior(x-bpp) into cl
  4164.             "jmp paeth_dpaeth            \n\t"
  4165.  
  4166.          "paeth_dabc:                    \n\t"
  4167.             // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
  4168.             "movb (%%edi,%%edx,), %%cl   \n\t" // load Raw(x-bpp) into cl
  4169.  
  4170.          "paeth_dpaeth:                  \n\t"
  4171.             "incl %%ebx                  \n\t"
  4172.             "incl %%edx                  \n\t"
  4173.             // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
  4174.             "addb %%cl, -1(%%edi,%%ebx,) \n\t"
  4175.             "cmpl _FullLength, %%ebx     \n\t"
  4176.             "jb paeth_dlp                \n\t"
  4177.  
  4178.          "paeth_dend:                    \n\t"
  4179. #ifdef __PIC__
  4180.             "popl %%ebx                  \n\t" // index to Global Offset Table
  4181. #endif
  4182.  
  4183.             : "=c" (dummy_value_c),            // output regs (dummy)
  4184.               "=S" (dummy_value_S),
  4185.               "=D" (dummy_value_D)
  4186.  
  4187.             : "0" (bpp),       // ecx          // input regs
  4188.               "1" (prev_row),  // esi
  4189.               "2" (row)        // edi
  4190.  
  4191.             : "%eax", "%edx"                   // clobber list
  4192. #ifndef __PIC__
  4193.             , "%ebx"
  4194. #endif
  4195.          );
  4196.       }
  4197.       return;                   // No need to go further with this one
  4198.  
  4199.    } // end switch (bpp)
  4200.  
  4201.    __asm__ __volatile__ (
  4202.       // MMX acceleration complete; now do clean-up
  4203.       // check if any remaining bytes left to decode
  4204. #ifdef __PIC__
  4205.       "pushl %%ebx                 \n\t" // save index to Global Offset Table
  4206. #endif
  4207.       "movl _MMXLength, %%ebx      \n\t"
  4208.       "cmpl _FullLength, %%ebx     \n\t"
  4209.       "jnb paeth_end               \n\t"
  4210. //pre "movl row, %%edi             \n\t"
  4211. //pre "movl prev_row, %%esi        \n\t"
  4212.       // do Paeth decode for remaining bytes
  4213.       "movl %%ebx, %%edx           \n\t"
  4214. //pre "subl bpp, %%edx             \n\t" // (bpp is preloaded into ecx)
  4215.       "subl %%ecx, %%edx           \n\t" // edx = ebx - bpp
  4216.       "xorl %%ecx, %%ecx           \n\t" // zero ecx before using cl & cx below
  4217.  
  4218.    "paeth_lp2:                     \n\t"
  4219.       "xorl %%eax, %%eax           \n\t"
  4220.       // pav = p - a = (a + b - c) - a = b - c
  4221.       "movb (%%esi,%%ebx,), %%al   \n\t" // load Prior(x) into al
  4222.       "movb (%%esi,%%edx,), %%cl   \n\t" // load Prior(x-bpp) into cl
  4223.       "subl %%ecx, %%eax           \n\t" // subtract Prior(x-bpp)
  4224.       "movl %%eax, _patemp         \n\t" // Save pav for later use
  4225.       "xorl %%eax, %%eax           \n\t"
  4226.       // pbv = p - b = (a + b - c) - b = a - c
  4227.       "movb (%%edi,%%edx,), %%al   \n\t" // load Raw(x-bpp) into al
  4228.       "subl %%ecx, %%eax           \n\t" // subtract Prior(x-bpp)
  4229.       "movl %%eax, %%ecx           \n\t"
  4230.       // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  4231.       "addl _patemp, %%eax         \n\t" // pcv = pav + pbv
  4232.       // pc = abs(pcv)
  4233.       "testl $0x80000000, %%eax    \n\t"
  4234.       "jz paeth_pca2               \n\t"
  4235.       "negl %%eax                  \n\t" // reverse sign of neg values
  4236.  
  4237.    "paeth_pca2:                    \n\t"
  4238.       "movl %%eax, _pctemp         \n\t" // save pc for later use
  4239.       // pb = abs(pbv)
  4240.       "testl $0x80000000, %%ecx    \n\t"
  4241.       "jz paeth_pba2               \n\t"
  4242.       "negl %%ecx                  \n\t" // reverse sign of neg values
  4243.  
  4244.    "paeth_pba2:                    \n\t"
  4245.       "movl %%ecx, _pbtemp         \n\t" // save pb for later use
  4246.       // pa = abs(pav)
  4247.       "movl _patemp, %%eax         \n\t"
  4248.       "testl $0x80000000, %%eax    \n\t"
  4249.       "jz paeth_paa2               \n\t"
  4250.       "negl %%eax                  \n\t" // reverse sign of neg values
  4251.  
  4252.    "paeth_paa2:                    \n\t"
  4253.       "movl %%eax, _patemp         \n\t" // save pa for later use
  4254.       // test if pa <= pb
  4255.       "cmpl %%ecx, %%eax           \n\t"
  4256.       "jna paeth_abb2              \n\t"
  4257.       // pa > pb; now test if pb <= pc
  4258.       "cmpl _pctemp, %%ecx         \n\t"
  4259.       "jna paeth_bbc2              \n\t"
  4260.       // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
  4261.       "movb (%%esi,%%edx,), %%cl   \n\t" // load Prior(x-bpp) into cl
  4262.       "jmp paeth_paeth2            \n\t"
  4263.  
  4264.    "paeth_bbc2:                    \n\t"
  4265.       // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
  4266.       "movb (%%esi,%%ebx,), %%cl   \n\t" // load Prior(x) into cl
  4267.       "jmp paeth_paeth2            \n\t"
  4268.  
  4269.    "paeth_abb2:                    \n\t"
  4270.       // pa <= pb; now test if pa <= pc
  4271.       "cmpl _pctemp, %%eax         \n\t"
  4272.       "jna paeth_abc2              \n\t"
  4273.       // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
  4274.       "movb (%%esi,%%edx,), %%cl   \n\t" // load Prior(x-bpp) into cl
  4275.       "jmp paeth_paeth2            \n\t"
  4276.  
  4277.    "paeth_abc2:                    \n\t"
  4278.       // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
  4279.       "movb (%%edi,%%edx,), %%cl   \n\t" // load Raw(x-bpp) into cl
  4280.  
  4281.    "paeth_paeth2:                  \n\t"
  4282.       "incl %%ebx                  \n\t"
  4283.       "incl %%edx                  \n\t"
  4284.       // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
  4285.       "addb %%cl, -1(%%edi,%%ebx,) \n\t"
  4286.       "cmpl _FullLength, %%ebx     \n\t"
  4287.       "jb paeth_lp2                \n\t"
  4288.  
  4289.    "paeth_end:                     \n\t"
  4290.       "EMMS                        \n\t" // end MMX; prep for poss. FP instrs.
  4291. #ifdef __PIC__
  4292.       "popl %%ebx                  \n\t" // restore index to Global Offset Table
  4293. #endif
  4294.  
  4295.       : "=c" (dummy_value_c),            // output regs (dummy)
  4296.         "=S" (dummy_value_S),
  4297.         "=D" (dummy_value_D)
  4298.  
  4299.       : "0" (bpp),       // ecx          // input regs
  4300.         "1" (prev_row),  // esi
  4301.         "2" (row)        // edi
  4302.  
  4303.       : "%eax", "%edx"                   // clobber list (no input regs!)
  4304. #ifndef __PIC__
  4305.       , "%ebx"
  4306. #endif
  4307.    );
  4308.  
  4309. } /* end png_read_filter_row_mmx_paeth() */
  4310.  
  4311.  
  4312.  
  4313.  
  4314. //===========================================================================//
  4315. //                                                                           //
  4316. //           P N G _ R E A D _ F I L T E R _ R O W _ M M X _ S U B           //
  4317. //                                                                           //
  4318. //===========================================================================//
  4319.  
  4320. // Optimized code for PNG Sub filter decoder
  4321.  
  4322. static void /* PRIVATE */
  4323. png_read_filter_row_mmx_sub(png_row_infop row_info, png_bytep row)
  4324. {
  4325.    int bpp;
  4326.    int dummy_value_a;
  4327.    int dummy_value_D;
  4328.  
  4329.    bpp = (row_info->pixel_depth + 7) >> 3;   // calc number of bytes per pixel
  4330.    _FullLength = row_info->rowbytes - bpp;   // number of bytes to filter
  4331.  
  4332.    __asm__ __volatile__ (
  4333. //pre "movl row, %%edi             \n\t"
  4334.       "movl %%edi, %%esi           \n\t" // lp = row
  4335. //pre "movl bpp, %%eax             \n\t"
  4336.       "addl %%eax, %%edi           \n\t" // rp = row + bpp
  4337. //irr "xorl %%eax, %%eax           \n\t"
  4338.       // get # of bytes to alignment
  4339.       "movl %%edi, _dif            \n\t" // take start of row
  4340.       "addl $0xf, _dif             \n\t" // add 7 + 8 to incr past
  4341.                                          //  alignment boundary
  4342.       "xorl %%ecx, %%ecx           \n\t"
  4343.       "andl $0xfffffff8, _dif      \n\t" // mask to alignment boundary
  4344.       "subl %%edi, _dif            \n\t" // subtract from start ==> value
  4345.       "jz sub_go                   \n\t" //  ecx at alignment
  4346.  
  4347.    "sub_lp1:                       \n\t" // fix alignment
  4348.       "movb (%%esi,%%ecx,), %%al   \n\t"
  4349.       "addb %%al, (%%edi,%%ecx,)   \n\t"
  4350.       "incl %%ecx                  \n\t"
  4351.       "cmpl _dif, %%ecx            \n\t"
  4352.       "jb sub_lp1                  \n\t"
  4353.  
  4354.    "sub_go:                        \n\t"
  4355.       "movl _FullLength, %%eax     \n\t"
  4356.       "movl %%eax, %%edx           \n\t"
  4357.       "subl %%ecx, %%edx           \n\t" // subtract alignment fix
  4358.       "andl $0x00000007, %%edx     \n\t" // calc bytes over mult of 8
  4359.       "subl %%edx, %%eax           \n\t" // drop over bytes from length
  4360.       "movl %%eax, _MMXLength      \n\t"
  4361.  
  4362.       : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  4363.         "=D" (dummy_value_D)    // 1
  4364.  
  4365.       : "0" (bpp),              // eax    // input regs
  4366.         "1" (row)               // edi
  4367.  
  4368.       : "%ebx", "%ecx", "%edx"            // clobber list
  4369.       , "%esi"
  4370.  
  4371. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  4372.       , "%mm0", "%mm1", "%mm2", "%mm3"
  4373.       , "%mm4", "%mm5", "%mm6", "%mm7"
  4374. #endif
  4375.    );
  4376.  
  4377.    // now do the math for the rest of the row
  4378.    switch (bpp)
  4379.    {
  4380.       case 3:
  4381.       {
  4382.          _ActiveMask.use  = 0x0000ffffff000000LL;
  4383.          _ShiftBpp.use = 24;       // == 3 * 8
  4384.          _ShiftRem.use  = 40;      // == 64 - 24
  4385.  
  4386.          __asm__ __volatile__ (
  4387. // preload  "movl row, %%edi              \n\t"
  4388.             "movq _ActiveMask, %%mm7       \n\t" // load _ActiveMask for 2nd
  4389.                                                 //  active byte group
  4390.             "movl %%edi, %%esi            \n\t" // lp = row
  4391. // preload  "movl bpp, %%eax              \n\t"
  4392.             "addl %%eax, %%edi            \n\t" // rp = row + bpp
  4393.             "movq %%mm7, %%mm6            \n\t"
  4394.             "movl _dif, %%edx             \n\t"
  4395.             "psllq _ShiftBpp, %%mm6       \n\t" // move mask in mm6 to cover
  4396.                                                 //  3rd active byte group
  4397.             // prime the pump:  load the first Raw(x-bpp) data set
  4398.             "movq -8(%%edi,%%edx,), %%mm1 \n\t"
  4399.  
  4400.          "sub_3lp:                        \n\t" // shift data for adding first
  4401.             "psrlq _ShiftRem, %%mm1       \n\t" //  bpp bytes (no need for mask;
  4402.                                                 //  shift clears inactive bytes)
  4403.             // add 1st active group
  4404.             "movq (%%edi,%%edx,), %%mm0   \n\t"
  4405.             "paddb %%mm1, %%mm0           \n\t"
  4406.  
  4407.             // add 2nd active group
  4408.             "movq %%mm0, %%mm1            \n\t" // mov updated Raws to mm1
  4409.             "psllq _ShiftBpp, %%mm1       \n\t" // shift data to pos. correctly
  4410.             "pand %%mm7, %%mm1            \n\t" // mask to use 2nd active group
  4411.             "paddb %%mm1, %%mm0           \n\t"
  4412.  
  4413.             // add 3rd active group
  4414.             "movq %%mm0, %%mm1            \n\t" // mov updated Raws to mm1
  4415.             "psllq _ShiftBpp, %%mm1       \n\t" // shift data to pos. correctly
  4416.             "pand %%mm6, %%mm1            \n\t" // mask to use 3rd active group
  4417.             "addl $8, %%edx               \n\t"
  4418.             "paddb %%mm1, %%mm0           \n\t"
  4419.  
  4420.             "cmpl _MMXLength, %%edx       \n\t"
  4421.             "movq %%mm0, -8(%%edi,%%edx,) \n\t" // write updated Raws to array
  4422.             "movq %%mm0, %%mm1            \n\t" // prep 1st add at top of loop
  4423.             "jb sub_3lp                   \n\t"
  4424.  
  4425.             : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  4426.               "=D" (dummy_value_D)    // 1
  4427.  
  4428.             : "0" (bpp),              // eax    // input regs
  4429.               "1" (row)               // edi
  4430.  
  4431.             : "%edx", "%esi"                    // clobber list
  4432. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  4433.             , "%mm0", "%mm1", "%mm6", "%mm7"
  4434. #endif
  4435.          );
  4436.       }
  4437.       break;
  4438.  
  4439.       case 1:
  4440.       {
  4441.          __asm__ __volatile__ (
  4442.             "movl _dif, %%edx            \n\t"
  4443. // preload  "movl row, %%edi             \n\t"
  4444.             "cmpl _FullLength, %%edx     \n\t"
  4445.             "jnb sub_1end                \n\t"
  4446.             "movl %%edi, %%esi           \n\t" // lp = row
  4447.             "xorl %%eax, %%eax           \n\t"
  4448. // preload  "movl bpp, %%eax             \n\t"
  4449.             "addl %%eax, %%edi           \n\t" // rp = row + bpp
  4450.  
  4451.          "sub_1lp:                       \n\t"
  4452.             "movb (%%esi,%%edx,), %%al   \n\t"
  4453.             "addb %%al, (%%edi,%%edx,)   \n\t"
  4454.             "incl %%edx                  \n\t"
  4455.             "cmpl _FullLength, %%edx     \n\t"
  4456.             "jb sub_1lp                  \n\t"
  4457.  
  4458.          "sub_1end:                      \n\t"
  4459.  
  4460.             : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  4461.               "=D" (dummy_value_D)    // 1
  4462.  
  4463.             : "0" (bpp),              // eax    // input regs
  4464.               "1" (row)               // edi
  4465.  
  4466.             : "%edx", "%esi"                    // clobber list
  4467.          );
  4468.       }
  4469.       return;
  4470.  
  4471.       case 6:
  4472.       case 4:
  4473.       //case 7:   // GRR BOGUS
  4474.       //case 5:   // GRR BOGUS
  4475.       {
  4476.          _ShiftBpp.use = bpp << 3;
  4477.          _ShiftRem.use = 64 - _ShiftBpp.use;
  4478.  
  4479.          __asm__ __volatile__ (
  4480. // preload  "movl row, %%edi              \n\t"
  4481.             "movl _dif, %%edx             \n\t"
  4482.             "movl %%edi, %%esi            \n\t" // lp = row
  4483. // preload  "movl bpp, %%eax              \n\t"
  4484.             "addl %%eax, %%edi            \n\t" // rp = row + bpp
  4485.  
  4486.             // prime the pump:  load the first Raw(x-bpp) data set
  4487.             "movq -8(%%edi,%%edx,), %%mm1 \n\t"
  4488.  
  4489.          "sub_4lp:                        \n\t" // shift data for adding first
  4490.             "psrlq _ShiftRem, %%mm1       \n\t" //  bpp bytes (no need for mask;
  4491.                                                 //  shift clears inactive bytes)
  4492.             "movq (%%edi,%%edx,), %%mm0   \n\t"
  4493.             "paddb %%mm1, %%mm0           \n\t"
  4494.  
  4495.             // add 2nd active group
  4496.             "movq %%mm0, %%mm1            \n\t" // mov updated Raws to mm1
  4497.             "psllq _ShiftBpp, %%mm1       \n\t" // shift data to pos. correctly
  4498.             "addl $8, %%edx               \n\t"
  4499.             "paddb %%mm1, %%mm0           \n\t"
  4500.  
  4501.             "cmpl _MMXLength, %%edx       \n\t"
  4502.             "movq %%mm0, -8(%%edi,%%edx,) \n\t"
  4503.             "movq %%mm0, %%mm1            \n\t" // prep 1st add at top of loop
  4504.             "jb sub_4lp                   \n\t"
  4505.  
  4506.             : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  4507.               "=D" (dummy_value_D)    // 1
  4508.  
  4509.             : "0" (bpp),              // eax    // input regs
  4510.               "1" (row)               // edi
  4511.  
  4512.             : "%edx", "%esi"                    // clobber list
  4513. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  4514.             , "%mm0", "%mm1"
  4515. #endif
  4516.          );
  4517.       }
  4518.       break;
  4519.  
  4520.       case 2:
  4521.       {
  4522.          _ActiveMask.use = 0x00000000ffff0000LL;
  4523.          _ShiftBpp.use = 16;       // == 2 * 8
  4524.          _ShiftRem.use = 48;       // == 64 - 16
  4525.  
  4526.          __asm__ __volatile__ (
  4527.             "movq _ActiveMask, %%mm7      \n\t" // load _ActiveMask for 2nd
  4528.                                                 //  active byte group
  4529.             "movl _dif, %%edx             \n\t"
  4530.             "movq %%mm7, %%mm6            \n\t"
  4531. // preload  "movl row, %%edi              \n\t"
  4532.             "psllq _ShiftBpp, %%mm6       \n\t" // move mask in mm6 to cover
  4533.                                                 //  3rd active byte group
  4534.             "movl %%edi, %%esi            \n\t" // lp = row
  4535.             "movq %%mm6, %%mm5            \n\t"
  4536. // preload  "movl bpp, %%eax              \n\t"
  4537.             "addl %%eax, %%edi            \n\t" // rp = row + bpp
  4538.             "psllq _ShiftBpp, %%mm5       \n\t" // move mask in mm5 to cover
  4539.                                                 //  4th active byte group
  4540.             // prime the pump:  load the first Raw(x-bpp) data set
  4541.             "movq -8(%%edi,%%edx,), %%mm1 \n\t"
  4542.  
  4543.          "sub_2lp:                        \n\t" // shift data for adding first
  4544.             "psrlq _ShiftRem, %%mm1       \n\t" //  bpp bytes (no need for mask;
  4545.                                                 //  shift clears inactive bytes)
  4546.             // add 1st active group
  4547.             "movq (%%edi,%%edx,), %%mm0   \n\t"
  4548.             "paddb %%mm1, %%mm0           \n\t"
  4549.  
  4550.             // add 2nd active group
  4551.             "movq %%mm0, %%mm1            \n\t" // mov updated Raws to mm1
  4552.             "psllq _ShiftBpp, %%mm1       \n\t" // shift data to pos. correctly
  4553.             "pand %%mm7, %%mm1            \n\t" // mask to use 2nd active group
  4554.             "paddb %%mm1, %%mm0           \n\t"
  4555.  
  4556.             // add 3rd active group
  4557.             "movq %%mm0, %%mm1            \n\t" // mov updated Raws to mm1
  4558.             "psllq _ShiftBpp, %%mm1       \n\t" // shift data to pos. correctly
  4559.             "pand %%mm6, %%mm1            \n\t" // mask to use 3rd active group
  4560.             "paddb %%mm1, %%mm0           \n\t"
  4561.  
  4562.             // add 4th active group
  4563.             "movq %%mm0, %%mm1            \n\t" // mov updated Raws to mm1
  4564.             "psllq _ShiftBpp, %%mm1       \n\t" // shift data to pos. correctly
  4565.             "pand %%mm5, %%mm1            \n\t" // mask to use 4th active group
  4566.             "addl $8, %%edx               \n\t"
  4567.             "paddb %%mm1, %%mm0           \n\t"
  4568.             "cmpl _MMXLength, %%edx       \n\t"
  4569.             "movq %%mm0, -8(%%edi,%%edx,) \n\t" // write updated Raws to array
  4570.             "movq %%mm0, %%mm1            \n\t" // prep 1st add at top of loop
  4571.             "jb sub_2lp                   \n\t"
  4572.  
  4573.             : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  4574.               "=D" (dummy_value_D)    // 1
  4575.  
  4576.             : "0" (bpp),              // eax    // input regs
  4577.               "1" (row)               // edi
  4578.  
  4579.             : "%edx", "%esi"                    // clobber list
  4580. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  4581.             , "%mm0", "%mm1", "%mm5", "%mm6", "%mm7"
  4582. #endif
  4583.          );
  4584.       }
  4585.       break;
  4586.  
  4587.       case 8:
  4588.       {
  4589.          __asm__ __volatile__ (
  4590. // preload  "movl row, %%edi              \n\t"
  4591.             "movl _dif, %%edx             \n\t"
  4592.             "movl %%edi, %%esi            \n\t" // lp = row
  4593. // preload  "movl bpp, %%eax              \n\t"
  4594.             "addl %%eax, %%edi            \n\t" // rp = row + bpp
  4595.             "movl _MMXLength, %%ecx       \n\t"
  4596.  
  4597.             // prime the pump:  load the first Raw(x-bpp) data set
  4598.             "movq -8(%%edi,%%edx,), %%mm7 \n\t"
  4599.             "andl $0x0000003f, %%ecx      \n\t" // calc bytes over mult of 64
  4600.  
  4601.          "sub_8lp:                        \n\t"
  4602.             "movq (%%edi,%%edx,), %%mm0   \n\t" // load Sub(x) for 1st 8 bytes
  4603.             "paddb %%mm7, %%mm0           \n\t"
  4604.             "movq 8(%%edi,%%edx,), %%mm1  \n\t" // load Sub(x) for 2nd 8 bytes
  4605.             "movq %%mm0, (%%edi,%%edx,)   \n\t" // write Raw(x) for 1st 8 bytes
  4606.  
  4607.             // Now mm0 will be used as Raw(x-bpp) for the 2nd group of 8 bytes.
  4608.             // This will be repeated for each group of 8 bytes with the 8th
  4609.             // group being used as the Raw(x-bpp) for the 1st group of the
  4610.             // next loop.
  4611.  
  4612.             "paddb %%mm0, %%mm1           \n\t"
  4613.             "movq 16(%%edi,%%edx,), %%mm2 \n\t" // load Sub(x) for 3rd 8 bytes
  4614.             "movq %%mm1, 8(%%edi,%%edx,)  \n\t" // write Raw(x) for 2nd 8 bytes
  4615.             "paddb %%mm1, %%mm2           \n\t"
  4616.             "movq 24(%%edi,%%edx,), %%mm3 \n\t" // load Sub(x) for 4th 8 bytes
  4617.             "movq %%mm2, 16(%%edi,%%edx,) \n\t" // write Raw(x) for 3rd 8 bytes
  4618.             "paddb %%mm2, %%mm3           \n\t"
  4619.             "movq 32(%%edi,%%edx,), %%mm4 \n\t" // load Sub(x) for 5th 8 bytes
  4620.             "movq %%mm3, 24(%%edi,%%edx,) \n\t" // write Raw(x) for 4th 8 bytes
  4621.             "paddb %%mm3, %%mm4           \n\t"
  4622.             "movq 40(%%edi,%%edx,), %%mm5 \n\t" // load Sub(x) for 6th 8 bytes
  4623.             "movq %%mm4, 32(%%edi,%%edx,) \n\t" // write Raw(x) for 5th 8 bytes
  4624.             "paddb %%mm4, %%mm5           \n\t"
  4625.             "movq 48(%%edi,%%edx,), %%mm6 \n\t" // load Sub(x) for 7th 8 bytes
  4626.             "movq %%mm5, 40(%%edi,%%edx,) \n\t" // write Raw(x) for 6th 8 bytes
  4627.             "paddb %%mm5, %%mm6           \n\t"
  4628.             "movq 56(%%edi,%%edx,), %%mm7 \n\t" // load Sub(x) for 8th 8 bytes
  4629.             "movq %%mm6, 48(%%edi,%%edx,) \n\t" // write Raw(x) for 7th 8 bytes
  4630.             "addl $64, %%edx              \n\t"
  4631.             "paddb %%mm6, %%mm7           \n\t"
  4632.             "cmpl %%ecx, %%edx            \n\t"
  4633.             "movq %%mm7, -8(%%edi,%%edx,) \n\t" // write Raw(x) for 8th 8 bytes
  4634.             "jb sub_8lp                   \n\t"
  4635.  
  4636.             "cmpl _MMXLength, %%edx       \n\t"
  4637.             "jnb sub_8lt8                 \n\t"
  4638.  
  4639.          "sub_8lpA:                       \n\t"
  4640.             "movq (%%edi,%%edx,), %%mm0   \n\t"
  4641.             "addl $8, %%edx               \n\t"
  4642.             "paddb %%mm7, %%mm0           \n\t"
  4643.             "cmpl _MMXLength, %%edx       \n\t"
  4644.             "movq %%mm0, -8(%%edi,%%edx,) \n\t" // -8 to offset early addl edx
  4645.             "movq %%mm0, %%mm7            \n\t" // move calculated Raw(x) data
  4646.                                                 //  to mm1 to be new Raw(x-bpp)
  4647.                                                 //  for next loop
  4648.             "jb sub_8lpA                  \n\t"
  4649.  
  4650.          "sub_8lt8:                       \n\t"
  4651.  
  4652.             : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  4653.               "=D" (dummy_value_D)    // 1
  4654.  
  4655.             : "0" (bpp),              // eax    // input regs
  4656.               "1" (row)               // edi
  4657.  
  4658.             : "%ecx", "%edx", "%esi"            // clobber list
  4659. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  4660.             , "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7"
  4661. #endif
  4662.          );
  4663.       }
  4664.       break;
  4665.  
  4666.       default:                // bpp greater than 8 bytes    GRR BOGUS
  4667.       {
  4668.          __asm__ __volatile__ (
  4669.             "movl _dif, %%edx             \n\t"
  4670. // preload  "movl row, %%edi              \n\t"
  4671.             "movl %%edi, %%esi            \n\t" // lp = row
  4672. // preload  "movl bpp, %%eax              \n\t"
  4673.             "addl %%eax, %%edi            \n\t" // rp = row + bpp
  4674.  
  4675.          "sub_Alp:                        \n\t"
  4676.             "movq (%%edi,%%edx,), %%mm0   \n\t"
  4677.             "movq (%%esi,%%edx,), %%mm1   \n\t"
  4678.             "addl $8, %%edx               \n\t"
  4679.             "paddb %%mm1, %%mm0           \n\t"
  4680.             "cmpl _MMXLength, %%edx       \n\t"
  4681.             "movq %%mm0, -8(%%edi,%%edx,) \n\t" // mov does not affect flags;
  4682.                                                 //  -8 to offset addl edx
  4683.             "jb sub_Alp                   \n\t"
  4684.  
  4685.             : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  4686.               "=D" (dummy_value_D)    // 1
  4687.  
  4688.             : "0" (bpp),              // eax    // input regs
  4689.               "1" (row)               // edi
  4690.  
  4691.             : "%edx", "%esi"                    // clobber list
  4692. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  4693.             , "%mm0", "%mm1"
  4694. #endif
  4695.          );
  4696.       }
  4697.       break;
  4698.  
  4699.    } // end switch (bpp)
  4700.  
  4701.    __asm__ __volatile__ (
  4702.       "movl _MMXLength, %%edx       \n\t"
  4703. //pre "movl row, %%edi              \n\t"
  4704.       "cmpl _FullLength, %%edx      \n\t"
  4705.       "jnb sub_end                  \n\t"
  4706.  
  4707.       "movl %%edi, %%esi            \n\t" // lp = row
  4708. //pre "movl bpp, %%eax              \n\t"
  4709.       "addl %%eax, %%edi            \n\t" // rp = row + bpp
  4710.       "xorl %%eax, %%eax            \n\t"
  4711.  
  4712.    "sub_lp2:                        \n\t"
  4713.       "movb (%%esi,%%edx,), %%al    \n\t"
  4714.       "addb %%al, (%%edi,%%edx,)    \n\t"
  4715.       "incl %%edx                   \n\t"
  4716.       "cmpl _FullLength, %%edx      \n\t"
  4717.       "jb sub_lp2                   \n\t"
  4718.  
  4719.    "sub_end:                        \n\t"
  4720.       "EMMS                         \n\t" // end MMX instructions
  4721.  
  4722.       : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  4723.         "=D" (dummy_value_D)    // 1
  4724.  
  4725.       : "0" (bpp),              // eax    // input regs
  4726.         "1" (row)               // edi
  4727.  
  4728.       : "%edx", "%esi"                    // clobber list
  4729.    );
  4730.  
  4731. } // end of png_read_filter_row_mmx_sub()
  4732.  
  4733.  
  4734.  
  4735.  
  4736. //===========================================================================//
  4737. //                                                                           //
  4738. //            P N G _ R E A D _ F I L T E R _ R O W _ M M X _ U P            //
  4739. //                                                                           //
  4740. //===========================================================================//
  4741.  
  4742. // Optimized code for PNG Up filter decoder
  4743.  
  4744. static void /* PRIVATE */
  4745. png_read_filter_row_mmx_up(png_row_infop row_info, png_bytep row,
  4746.                            png_bytep prev_row)
  4747. {
  4748.    png_uint_32 len;
  4749.    int dummy_value_d;   // fix 'forbidden register 3 (dx) was spilled' error
  4750.    int dummy_value_S;
  4751.    int dummy_value_D;
  4752.  
  4753.    len = row_info->rowbytes;              // number of bytes to filter
  4754.  
  4755.    __asm__ __volatile__ (
  4756. //pre "movl row, %%edi              \n\t"
  4757.       // get # of bytes to alignment
  4758.       "movl %%edi, %%ecx            \n\t"
  4759.       "xorl %%ebx, %%ebx            \n\t"
  4760.       "addl $0x7, %%ecx             \n\t"
  4761.       "xorl %%eax, %%eax            \n\t"
  4762.       "andl $0xfffffff8, %%ecx      \n\t"
  4763. //pre "movl prev_row, %%esi         \n\t"
  4764.       "subl %%edi, %%ecx            \n\t"
  4765.       "jz up_go                     \n\t"
  4766.  
  4767.    "up_lp1:                         \n\t" // fix alignment
  4768.       "movb (%%edi,%%ebx,), %%al    \n\t"
  4769.       "addb (%%esi,%%ebx,), %%al    \n\t"
  4770.       "incl %%ebx                   \n\t"
  4771.       "cmpl %%ecx, %%ebx            \n\t"
  4772.       "movb %%al, -1(%%edi,%%ebx,)  \n\t" // mov does not affect flags; -1 to
  4773.       "jb up_lp1                    \n\t" //  offset incl ebx
  4774.  
  4775.    "up_go:                          \n\t"
  4776. //pre "movl len, %%edx              \n\t"
  4777.       "movl %%edx, %%ecx            \n\t"
  4778.       "subl %%ebx, %%edx            \n\t" // subtract alignment fix
  4779.       "andl $0x0000003f, %%edx      \n\t" // calc bytes over mult of 64
  4780.       "subl %%edx, %%ecx            \n\t" // drop over bytes from length
  4781.  
  4782.       // unrolled loop - use all MMX registers and interleave to reduce
  4783.       // number of branch instructions (loops) and reduce partial stalls
  4784.    "up_loop:                        \n\t"
  4785.       "movq (%%esi,%%ebx,), %%mm1   \n\t"
  4786.       "movq (%%edi,%%ebx,), %%mm0   \n\t"
  4787.       "movq 8(%%esi,%%ebx,), %%mm3  \n\t"
  4788.       "paddb %%mm1, %%mm0           \n\t"
  4789.       "movq 8(%%edi,%%ebx,), %%mm2  \n\t"
  4790.       "movq %%mm0, (%%edi,%%ebx,)   \n\t"
  4791.       "paddb %%mm3, %%mm2           \n\t"
  4792.       "movq 16(%%esi,%%ebx,), %%mm5 \n\t"
  4793.       "movq %%mm2, 8(%%edi,%%ebx,)  \n\t"
  4794.       "movq 16(%%edi,%%ebx,), %%mm4 \n\t"
  4795.       "movq 24(%%esi,%%ebx,), %%mm7 \n\t"
  4796.       "paddb %%mm5, %%mm4           \n\t"
  4797.       "movq 24(%%edi,%%ebx,), %%mm6 \n\t"
  4798.       "movq %%mm4, 16(%%edi,%%ebx,) \n\t"
  4799.       "paddb %%mm7, %%mm6           \n\t"
  4800.       "movq 32(%%esi,%%ebx,), %%mm1 \n\t"
  4801.       "movq %%mm6, 24(%%edi,%%ebx,) \n\t"
  4802.       "movq 32(%%edi,%%ebx,), %%mm0 \n\t"
  4803.       "movq 40(%%esi,%%ebx,), %%mm3 \n\t"
  4804.       "paddb %%mm1, %%mm0           \n\t"
  4805.       "movq 40(%%edi,%%ebx,), %%mm2 \n\t"
  4806.       "movq %%mm0, 32(%%edi,%%ebx,) \n\t"
  4807.       "paddb %%mm3, %%mm2           \n\t"
  4808.       "movq 48(%%esi,%%ebx,), %%mm5 \n\t"
  4809.       "movq %%mm2, 40(%%edi,%%ebx,) \n\t"
  4810.       "movq 48(%%edi,%%ebx,), %%mm4 \n\t"
  4811.       "movq 56(%%esi,%%ebx,), %%mm7 \n\t"
  4812.       "paddb %%mm5, %%mm4           \n\t"
  4813.       "movq 56(%%edi,%%ebx,), %%mm6 \n\t"
  4814.       "movq %%mm4, 48(%%edi,%%ebx,) \n\t"
  4815.       "addl $64, %%ebx              \n\t"
  4816.       "paddb %%mm7, %%mm6           \n\t"
  4817.       "cmpl %%ecx, %%ebx            \n\t"
  4818.       "movq %%mm6, -8(%%edi,%%ebx,) \n\t" // (+56)movq does not affect flags;
  4819.       "jb up_loop                   \n\t" //  -8 to offset addl ebx
  4820.  
  4821.       "cmpl $0, %%edx               \n\t" // test for bytes over mult of 64
  4822.       "jz up_end                    \n\t"
  4823.  
  4824.       "cmpl $8, %%edx               \n\t" // test for less than 8 bytes
  4825.       "jb up_lt8                    \n\t" //  [added by lcreeve@netins.net]
  4826.  
  4827.       "addl %%edx, %%ecx            \n\t"
  4828.       "andl $0x00000007, %%edx      \n\t" // calc bytes over mult of 8
  4829.       "subl %%edx, %%ecx            \n\t" // drop over bytes from length
  4830.       "jz up_lt8                    \n\t"
  4831.  
  4832.    "up_lpA:                         \n\t" // use MMX regs to update 8 bytes sim.
  4833.       "movq (%%esi,%%ebx,), %%mm1   \n\t"
  4834.       "movq (%%edi,%%ebx,), %%mm0   \n\t"
  4835.       "addl $8, %%ebx               \n\t"
  4836.       "paddb %%mm1, %%mm0           \n\t"
  4837.       "cmpl %%ecx, %%ebx            \n\t"
  4838.       "movq %%mm0, -8(%%edi,%%ebx,) \n\t" // movq does not affect flags; -8 to
  4839.       "jb up_lpA                    \n\t" //  offset add ebx
  4840.       "cmpl $0, %%edx               \n\t" // test for bytes over mult of 8
  4841.       "jz up_end                    \n\t"
  4842.  
  4843.    "up_lt8:                         \n\t"
  4844.       "xorl %%eax, %%eax            \n\t"
  4845.       "addl %%edx, %%ecx            \n\t" // move over byte count into counter
  4846.  
  4847.    "up_lp2:                         \n\t" // use x86 regs for remaining bytes
  4848.       "movb (%%edi,%%ebx,), %%al    \n\t"
  4849.       "addb (%%esi,%%ebx,), %%al    \n\t"
  4850.       "incl %%ebx                   \n\t"
  4851.       "cmpl %%ecx, %%ebx            \n\t"
  4852.       "movb %%al, -1(%%edi,%%ebx,)  \n\t" // mov does not affect flags; -1 to
  4853.       "jb up_lp2                    \n\t" //  offset inc ebx
  4854.  
  4855.    "up_end:                         \n\t"
  4856.       "EMMS                         \n\t" // conversion of filtered row complete
  4857.  
  4858.       : "=d" (dummy_value_d),   // 0      // output regs (dummy)
  4859.         "=S" (dummy_value_S),   // 1
  4860.         "=D" (dummy_value_D)    // 2
  4861.  
  4862.       : "0" (len),              // edx    // input regs
  4863.         "1" (prev_row),         // esi
  4864.         "2" (row)               // edi
  4865.  
  4866.       : "%eax", "%ebx", "%ecx"            // clobber list (no input regs!)
  4867.  
  4868. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  4869.       , "%mm0", "%mm1", "%mm2", "%mm3"
  4870.       , "%mm4", "%mm5", "%mm6", "%mm7"
  4871. #endif
  4872.    );
  4873.  
  4874. } // end of png_read_filter_row_mmx_up()
  4875.  
  4876. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  4877.  
  4878.  
  4879.  
  4880.  
  4881. /*===========================================================================*/
  4882. /*                                                                           */
  4883. /*                   P N G _ R E A D _ F I L T E R _ R O W                   */
  4884. /*                                                                           */
  4885. /*===========================================================================*/
  4886.  
  4887. #if defined(PNG_HAVE_ASSEMBLER_READ_FILTER_ROW)
  4888.  
  4889. /* Optimized png_read_filter_row routines */
  4890.  
  4891. void /* PRIVATE */
  4892. png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep
  4893.    row, png_bytep prev_row, int filter)
  4894. {
  4895. #ifdef PNG_DEBUG
  4896.    char filnm[10];
  4897. #endif
  4898.  
  4899. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
  4900. /* GRR:  these are superseded by png_ptr->asm_flags: */
  4901. #define UseMMX_sub    1   // GRR:  converted 20000730
  4902. #define UseMMX_up     1   // GRR:  converted 20000729
  4903. #define UseMMX_avg    1   // GRR:  converted 20000828 (+ 16-bit bugfix 20000916)
  4904. #define UseMMX_paeth  1   // GRR:  converted 20000828
  4905.  
  4906.    if (_mmx_supported == 2) {
  4907.        png_mmx_support();
  4908.    }
  4909. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  4910.  
  4911. #ifdef PNG_DEBUG
  4912.    png_debug(1, "in png_read_filter_row (pnggccrd.c)\n");
  4913.    switch (filter)
  4914.    {
  4915.       case 0: sprintf(filnm, "none");
  4916.          break;
  4917.       case 1: sprintf(filnm, "sub-%s", "MMX");
  4918.          break;
  4919.       case 2: sprintf(filnm, "up-%s", "MMX");
  4920.          break;
  4921.       case 3: sprintf(filnm, "avg-%s", "MMX");
  4922.          break;
  4923.       case 4: sprintf(filnm, "Paeth-%s", "MMX");
  4924.          break;
  4925.       default: sprintf(filnm, "unknw");
  4926.          break;
  4927.    }
  4928.    png_debug2(0, "row_number=%5ld, %5s, ", png_ptr->row_number, filnm);
  4929.    png_debug1(0, "row=0x%08lx, ", (unsigned long)row);
  4930.    png_debug2(0, "pixdepth=%2d, bytes=%d, ", (int)row_info->pixel_depth,
  4931.       (int)((row_info->pixel_depth + 7) >> 3));
  4932.    png_debug1(0,"rowbytes=%8ld\n", row_info->rowbytes);
  4933. #endif /* PNG_DEBUG */
  4934.  
  4935.    switch (filter)
  4936.    {
  4937.       case PNG_FILTER_VALUE_NONE:
  4938.          break;
  4939.  
  4940.       case PNG_FILTER_VALUE_SUB:
  4941. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
  4942.          if ( _mmx_supported &&
  4943.              (row_info->pixel_depth >= PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT) &&
  4944.              (row_info->rowbytes >= PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT))
  4945.          {
  4946.             png_read_filter_row_mmx_sub(row_info, row);
  4947.          }
  4948.          else
  4949. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  4950.          {
  4951.             png_uint_32 i;
  4952.             png_uint_32 istop = row_info->rowbytes;
  4953.             png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
  4954.             png_bytep rp = row + bpp;
  4955.             png_bytep lp = row;
  4956.  
  4957.             for (i = bpp; i < istop; i++)
  4958.             {
  4959.                *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
  4960.                rp++;
  4961.             }
  4962.          }  /* end !UseMMX_sub */
  4963.          break;
  4964.  
  4965.       case PNG_FILTER_VALUE_UP:
  4966. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
  4967.          if ( _mmx_supported &&
  4968.              (row_info->pixel_depth >= PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT) &&
  4969.              (row_info->rowbytes >= PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT))
  4970.          {
  4971.             png_read_filter_row_mmx_up(row_info, row, prev_row);
  4972.          }
  4973.           else
  4974. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  4975.          {
  4976.             png_uint_32 i;
  4977.             png_uint_32 istop = row_info->rowbytes;
  4978.             png_bytep rp = row;
  4979.             png_bytep pp = prev_row;
  4980.  
  4981.             for (i = 0; i < istop; ++i)
  4982.             {
  4983.                *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
  4984.                rp++;
  4985.             }
  4986.          }  /* end !UseMMX_up */
  4987.          break;
  4988.  
  4989.       case PNG_FILTER_VALUE_AVG:
  4990. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
  4991.          if ( _mmx_supported &&
  4992.              (row_info->pixel_depth >= PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT) &&
  4993.              (row_info->rowbytes >= PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT))
  4994.          {
  4995.             png_read_filter_row_mmx_avg(row_info, row, prev_row);
  4996.          }
  4997.          else
  4998. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  4999.          {
  5000.             png_uint_32 i;
  5001.             png_bytep rp = row;
  5002.             png_bytep pp = prev_row;
  5003.             png_bytep lp = row;
  5004.             png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
  5005.             png_uint_32 istop = row_info->rowbytes - bpp;
  5006.  
  5007.             for (i = 0; i < bpp; i++)
  5008.             {
  5009.                *rp = (png_byte)(((int)(*rp) +
  5010.                   ((int)(*pp++) >> 1)) & 0xff);
  5011.                rp++;
  5012.             }
  5013.  
  5014.             for (i = 0; i < istop; i++)
  5015.             {
  5016.                *rp = (png_byte)(((int)(*rp) +
  5017.                   ((int)(*pp++ + *lp++) >> 1)) & 0xff);
  5018.                rp++;
  5019.             }
  5020.          }  /* end !UseMMX_avg */
  5021.          break;
  5022.  
  5023.       case PNG_FILTER_VALUE_PAETH:
  5024. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
  5025.          if ( _mmx_supported &&
  5026.              (row_info->pixel_depth >= PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT) &&
  5027.              (row_info->rowbytes >= PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT))
  5028.          {
  5029.             png_read_filter_row_mmx_paeth(row_info, row, prev_row);
  5030.          }
  5031.          else
  5032. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  5033.          {
  5034.             png_uint_32 i;
  5035.             png_bytep rp = row;
  5036.             png_bytep pp = prev_row;
  5037.             png_bytep lp = row;
  5038.             png_bytep cp = prev_row;
  5039.             png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
  5040.             png_uint_32 istop = row_info->rowbytes - bpp;
  5041.  
  5042.             for (i = 0; i < bpp; i++)
  5043.             {
  5044.                *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
  5045.                rp++;
  5046.             }
  5047.  
  5048.             for (i = 0; i < istop; i++)   /* use leftover rp,pp */
  5049.             {
  5050.                int a, b, c, pa, pb, pc, p;
  5051.  
  5052.                a = *lp++;
  5053.                b = *pp++;
  5054.                c = *cp++;
  5055.  
  5056.                p = b - c;
  5057.                pc = a - c;
  5058.  
  5059. #ifdef PNG_USE_ABS
  5060.                pa = abs(p);
  5061.                pb = abs(pc);
  5062.                pc = abs(p + pc);
  5063. #else
  5064.                pa = p < 0 ? -p : p;
  5065.                pb = pc < 0 ? -pc : pc;
  5066.                pc = (p + pc) < 0 ? -(p + pc) : p + pc;
  5067. #endif
  5068.  
  5069.                /*
  5070.                   if (pa <= pb && pa <= pc)
  5071.                      p = a;
  5072.                   else if (pb <= pc)
  5073.                      p = b;
  5074.                   else
  5075.                      p = c;
  5076.                 */
  5077.  
  5078.                p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
  5079.  
  5080.                *rp = (png_byte)(((int)(*rp) + p) & 0xff);
  5081.                rp++;
  5082.             }
  5083.          }  /* end !UseMMX_paeth */
  5084.          break;
  5085.  
  5086.       default:
  5087.          png_warning(png_ptr, "Ignoring bad row-filter type");
  5088.          *row=0;
  5089.          break;
  5090.    }
  5091. }
  5092.  
  5093. #endif /* PNG_HAVE_ASSEMBLER_READ_FILTER_ROW */
  5094.  
  5095.  
  5096. /*===========================================================================*/
  5097. /*                                                                           */
  5098. /*                      P N G _ M M X _ S U P P O R T                        */
  5099. /*                                                                           */
  5100. /*===========================================================================*/
  5101.  
  5102. /* GRR NOTES:  (1) the following code assumes 386 or better (pushfl/popfl)
  5103.  *             (2) all instructions compile with gcc 2.7.2.3 and later
  5104.  *             (3) the function is moved down here to prevent gcc from
  5105.  *                  inlining it in multiple places and then barfing be-
  5106.  *                  cause the ".NOT_SUPPORTED" label is multiply defined
  5107.  *             [is there a way to signal that a *single* function should
  5108.  *              not be inlined?  is there a way to modify the label for
  5109.  *              each inlined instance, e.g., by appending _1, _2, etc.?
  5110.  *              maybe if don't use leading "." in label name? (nope...sigh)]
  5111.  */
  5112.  
  5113. int PNGAPI
  5114. png_mmx_support(void)
  5115. {
  5116. #if defined(PNG_MMX_CODE_SUPPORTED)
  5117.     __asm__ __volatile__ (
  5118.         "pushl %%ebx          \n\t"  // ebx gets clobbered by CPUID instruction
  5119.         "pushl %%ecx          \n\t"  // so does ecx...
  5120.         "pushl %%edx          \n\t"  // ...and edx (but ecx & edx safe on Linux)
  5121. //      ".byte  0x66          \n\t"  // convert 16-bit pushf to 32-bit pushfd
  5122. //      "pushf                \n\t"  // 16-bit pushf
  5123.         "pushfl               \n\t"  // save Eflag to stack
  5124.         "popl %%eax           \n\t"  // get Eflag from stack into eax
  5125.         "movl %%eax, %%ecx    \n\t"  // make another copy of Eflag in ecx
  5126.         "xorl $0x200000, %%eax \n\t" // toggle ID bit in Eflag (i.e., bit 21)
  5127.         "pushl %%eax          \n\t"  // save modified Eflag back to stack
  5128. //      ".byte  0x66          \n\t"  // convert 16-bit popf to 32-bit popfd
  5129. //      "popf                 \n\t"  // 16-bit popf
  5130.         "popfl                \n\t"  // restore modified value to Eflag reg
  5131.         "pushfl               \n\t"  // save Eflag to stack
  5132.         "popl %%eax           \n\t"  // get Eflag from stack
  5133.         "xorl %%ecx, %%eax    \n\t"  // compare new Eflag with original Eflag
  5134.         "jz .NOT_SUPPORTED    \n\t"  // if same, CPUID instr. is not supported
  5135.  
  5136.         "xorl %%eax, %%eax    \n\t"  // set eax to zero
  5137. //      ".byte  0x0f, 0xa2    \n\t"  // CPUID instruction (two-byte opcode)
  5138.         "cpuid                \n\t"  // get the CPU identification info
  5139.         "cmpl $1, %%eax       \n\t"  // make sure eax return non-zero value
  5140.         "jl .NOT_SUPPORTED    \n\t"  // if eax is zero, MMX is not supported
  5141.  
  5142.         "xorl %%eax, %%eax    \n\t"  // set eax to zero and...
  5143.         "incl %%eax           \n\t"  // ...increment eax to 1.  This pair is
  5144.                                      // faster than the instruction "mov eax, 1"
  5145.         "cpuid                \n\t"  // get the CPU identification info again
  5146.         "andl $0x800000, %%edx \n\t" // mask out all bits but MMX bit (23)
  5147.         "cmpl $0, %%edx       \n\t"  // 0 = MMX not supported
  5148.         "jz .NOT_SUPPORTED    \n\t"  // non-zero = yes, MMX IS supported
  5149.  
  5150.         "movl $1, %%eax       \n\t"  // set return value to 1
  5151.         "jmp  .RETURN         \n\t"  // DONE:  have MMX support
  5152.  
  5153.     ".NOT_SUPPORTED:          \n\t"  // target label for jump instructions
  5154.         "movl $0, %%eax       \n\t"  // set return value to 0
  5155.     ".RETURN:          \n\t"  // target label for jump instructions
  5156.         "movl %%eax, _mmx_supported \n\t" // save in global static variable, too
  5157.         "popl %%edx           \n\t"  // restore edx
  5158.         "popl %%ecx           \n\t"  // restore ecx
  5159.         "popl %%ebx           \n\t"  // restore ebx
  5160.  
  5161. //      "ret                  \n\t"  // DONE:  no MMX support
  5162.                                      // (fall through to standard C "ret")
  5163.  
  5164.         :                            // output list (none)
  5165.  
  5166.         :                            // any variables used on input (none)
  5167.  
  5168.         : "%eax"                     // clobber list
  5169. //      , "%ebx", "%ecx", "%edx"     // GRR:  we handle these manually
  5170. //      , "memory"   // if write to a variable gcc thought was in a reg
  5171. //      , "cc"       // "condition codes" (flag bits)
  5172.     );
  5173. #else     
  5174.     _mmx_supported = 0;
  5175. #endif /* PNG_MMX_CODE_SUPPORTED */
  5176.  
  5177.     return _mmx_supported;
  5178. }
  5179.  
  5180. #endif /* PNG_USE_PNGGCCRD */
  5181.