pnggccrd.c
上传用户:looem2003
上传日期:2014-07-20
资源大小:13733k
文件大小:230k
源码类别:

打印编程

开发平台:

Visual C++

  1.                }
  2.                else if (pixel_bytes == 8)
  3.                {
  4.                   for (i = width; i; i--)
  5.                   {
  6.                      png_byte v[8];
  7.                      int j;
  8.                      png_memcpy(v, sptr, 8);
  9.                      for (j = 0; j < png_pass_inc[pass]; j++)
  10.                      {
  11.                         png_memcpy(dp, v, 8);
  12.                         dp -= 8;
  13.                      }
  14.                      sptr -= 8;
  15.                   }
  16.                }
  17.                else     /* GRR:  should never be reached */
  18.                {
  19.                   for (i = width; i; i--)
  20.                   {
  21.                      png_byte v[8];
  22.                      int j;
  23.                      png_memcpy(v, sptr, pixel_bytes);
  24.                      for (j = 0; j < png_pass_inc[pass]; j++)
  25.                      {
  26.                         png_memcpy(dp, v, pixel_bytes);
  27.                         dp -= pixel_bytes;
  28.                      }
  29.                      sptr -= pixel_bytes;
  30.                   }
  31.                }
  32.             } /* end if (MMX not supported) */
  33.             break;
  34.          }
  35.       } /* end switch (row_info->pixel_depth) */
  36.       row_info->width = final_width;
  37.       row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,final_width);
  38.    }
  39. } /* end png_do_read_interlace() */
  40. #endif /* PNG_HAVE_MMX_READ_INTERLACE */
  41. #endif /* PNG_READ_INTERLACING_SUPPORTED */
  42. #if defined(PNG_HAVE_MMX_READ_FILTER_ROW)
  43. #if defined(PNG_MMX_CODE_SUPPORTED)
  44. // These variables are utilized in the functions below.  They are declared
  45. // globally here to ensure alignment on 8-byte boundaries.
  46. union uAll {
  47.    long long use;
  48.    double  align;
  49. } _LBCarryMask = {0x0101010101010101LL},
  50.   _HBClearMask = {0x7f7f7f7f7f7f7f7fLL},
  51.   _ActiveMask, _ActiveMask2, _ActiveMaskEnd, _ShiftBpp, _ShiftRem;
  52. #ifdef PNG_THREAD_UNSAFE_OK
  53. //===========================================================================//
  54. //                                                                           //
  55. //           P N G _ R E A D _ F I L T E R _ R O W _ M M X _ A V G           //
  56. //                                                                           //
  57. //===========================================================================//
  58. // Optimized code for PNG Average filter decoder
  59. static void /* PRIVATE */
  60. png_read_filter_row_mmx_avg(png_row_infop row_info, png_bytep row,
  61.                             png_bytep prev_row)
  62. {
  63.    int bpp;
  64.    int dummy_value_c;   // fix 'forbidden register 2 (cx) was spilled' error
  65.    int dummy_value_S;
  66.    int dummy_value_D;
  67.    bpp = (row_info->pixel_depth + 7) >> 3;  // get # bytes per pixel
  68.    _FullLength  = row_info->rowbytes;       // # of bytes to filter
  69.    __asm__ __volatile__ (
  70.       // initialize address pointers and offset
  71. #ifdef __PIC__
  72.       "pushl %%ebx                 nt" // save index to Global Offset Table
  73. #endif
  74. //pre "movl row, %%edi             nt" // edi:  Avg(x)
  75.       "xorl %%ebx, %%ebx           nt" // ebx:  x
  76.       "movl %%edi, %%edx           nt"
  77. //pre "movl prev_row, %%esi        nt" // esi:  Prior(x)
  78. //pre "subl bpp, %%edx             nt" // (bpp is preloaded into ecx)
  79.       "subl %%ecx, %%edx           nt" // edx:  Raw(x-bpp)
  80.       "xorl %%eax,%%eax            nt"
  81.       // Compute the Raw value for the first bpp bytes
  82.       //    Raw(x) = Avg(x) + (Prior(x)/2)
  83.    "avg_rlp:                       nt"
  84.       "movb (%%esi,%%ebx,),%%al    nt" // load al with Prior(x)
  85.       "incl %%ebx                  nt"
  86.       "shrb %%al                   nt" // divide by 2
  87.       "addb -1(%%edi,%%ebx,),%%al  nt" // add Avg(x); -1 to offset inc ebx
  88. //pre "cmpl bpp, %%ebx             nt" // (bpp is preloaded into ecx)
  89.       "cmpl %%ecx, %%ebx           nt"
  90.       "movb %%al,-1(%%edi,%%ebx,)  nt" // write Raw(x); -1 to offset inc ebx
  91.       "jb avg_rlp                  nt" // mov does not affect flags
  92.       // get # of bytes to alignment
  93.       "movl %%edi, _dif            nt" // take start of row
  94.       "addl %%ebx, _dif            nt" // add bpp
  95.       "addl $0xf, _dif             nt" // add 7+8 to incr past alignment bdry
  96.       "andl $0xfffffff8, _dif      nt" // mask to alignment boundary
  97.       "subl %%edi, _dif            nt" // subtract from start => value ebx at
  98.       "jz avg_go                   nt" //  alignment
  99.       // fix alignment
  100.       // Compute the Raw value for the bytes up to the alignment boundary
  101.       //    Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
  102.       "xorl %%ecx, %%ecx           nt"
  103.    "avg_lp1:                       nt"
  104.       "xorl %%eax, %%eax           nt"
  105.       "movb (%%esi,%%ebx,), %%cl   nt" // load cl with Prior(x)
  106.       "movb (%%edx,%%ebx,), %%al   nt" // load al with Raw(x-bpp)
  107.       "addw %%cx, %%ax             nt"
  108.       "incl %%ebx                  nt"
  109.       "shrw %%ax                   nt" // divide by 2
  110.       "addb -1(%%edi,%%ebx,), %%al nt" // add Avg(x); -1 to offset inc ebx
  111.       "cmpl _dif, %%ebx            nt" // check if at alignment boundary
  112.       "movb %%al, -1(%%edi,%%ebx,) nt" // write Raw(x); -1 to offset inc ebx
  113.       "jb avg_lp1                  nt" // repeat until at alignment boundary
  114.    "avg_go:                        nt"
  115.       "movl _FullLength, %%eax     nt"
  116.       "movl %%eax, %%ecx           nt"
  117.       "subl %%ebx, %%eax           nt" // subtract alignment fix
  118.       "andl $0x00000007, %%eax     nt" // calc bytes over mult of 8
  119.       "subl %%eax, %%ecx           nt" // drop over bytes from original length
  120.       "movl %%ecx, _MMXLength      nt"
  121. #ifdef __PIC__
  122.       "popl %%ebx                  nt" // restore index to Global Offset Table
  123. #endif
  124.       : "=c" (dummy_value_c),            // output regs (dummy)
  125.         "=S" (dummy_value_S),
  126.         "=D" (dummy_value_D)
  127.       : "0" (bpp),       // ecx          // input regs
  128.         "1" (prev_row),  // esi
  129.         "2" (row)        // edi
  130.       : "%eax", "%edx"                   // clobber list
  131. #ifndef __PIC__
  132.       , "%ebx"
  133. #endif
  134.       // GRR: INCLUDE "memory" as clobbered? (_dif, _MMXLength)
  135.       // (seems to work fine without...)
  136.    );
  137.    // now do the math for the rest of the row
  138.    switch (bpp)
  139.    {
  140.       case 3:
  141.       {
  142.          _ActiveMask.use  = 0x0000000000ffffffLL;
  143.          _ShiftBpp.use = 24;    // == 3 * 8
  144.          _ShiftRem.use = 40;    // == 64 - 24
  145.          __asm__ __volatile__ (
  146.             // re-init address pointers and offset
  147.             "movq _ActiveMask, %%mm7      nt"
  148.             "movl _dif, %%ecx             nt" // ecx:  x = offset to
  149.             "movq _LBCarryMask, %%mm5     nt" //  alignment boundary
  150. // preload  "movl row, %%edi              nt" // edi:  Avg(x)
  151.             "movq _HBClearMask, %%mm4     nt"
  152. // preload  "movl prev_row, %%esi         nt" // esi:  Prior(x)
  153.             // prime the pump:  load the first Raw(x-bpp) data set
  154.             "movq -8(%%edi,%%ecx,), %%mm2 nt" // load previous aligned 8 bytes
  155.                                                 // (correct pos. in loop below)
  156.          "avg_3lp:                        nt"
  157.             "movq (%%edi,%%ecx,), %%mm0   nt" // load mm0 with Avg(x)
  158.             "movq %%mm5, %%mm3            nt"
  159.             "psrlq _ShiftRem, %%mm2       nt" // correct position Raw(x-bpp)
  160.                                                 // data
  161.             "movq (%%esi,%%ecx,), %%mm1   nt" // load mm1 with Prior(x)
  162.             "movq %%mm7, %%mm6            nt"
  163.             "pand %%mm1, %%mm3            nt" // get lsb for each prev_row byte
  164.             "psrlq $1, %%mm1              nt" // divide prev_row bytes by 2
  165.             "pand  %%mm4, %%mm1           nt" // clear invalid bit 7 of each
  166.                                                 // byte
  167.             "paddb %%mm1, %%mm0           nt" // add (Prev_row/2) to Avg for
  168.                                                 // each byte
  169.             // add 1st active group (Raw(x-bpp)/2) to average with LBCarry
  170.             "movq %%mm3, %%mm1            nt" // now use mm1 for getting
  171.                                                 // LBCarrys
  172.             "pand %%mm2, %%mm1            nt" // get LBCarrys for each byte
  173.                                                 // where both
  174.                                // lsb's were == 1 (only valid for active group)
  175.             "psrlq $1, %%mm2              nt" // divide raw bytes by 2
  176.             "pand  %%mm4, %%mm2           nt" // clear invalid bit 7 of each
  177.                                                 // byte
  178.             "paddb %%mm1, %%mm2           nt" // add LBCarrys to (Raw(x-bpp)/2)
  179.                                                 // for each byte
  180.             "pand %%mm6, %%mm2            nt" // leave only Active Group 1
  181.                                                 // bytes to add to Avg
  182.             "paddb %%mm2, %%mm0           nt" // add (Raw/2) + LBCarrys to
  183.                                                 // Avg for each Active
  184.                                //  byte
  185.             // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry
  186.             "psllq _ShiftBpp, %%mm6       nt" // shift the mm6 mask to cover
  187.                                                 // bytes 3-5
  188.             "movq %%mm0, %%mm2            nt" // mov updated Raws to mm2
  189.             "psllq _ShiftBpp, %%mm2       nt" // shift data to pos. correctly
  190.             "movq %%mm3, %%mm1            nt" // now use mm1 for getting
  191.                                                 // LBCarrys
  192.             "pand %%mm2, %%mm1            nt" // get LBCarrys for each byte
  193.                                                 // where both
  194.                                // lsb's were == 1 (only valid for active group)
  195.             "psrlq $1, %%mm2              nt" // divide raw bytes by 2
  196.             "pand  %%mm4, %%mm2           nt" // clear invalid bit 7 of each
  197.                                                 // byte
  198.             "paddb %%mm1, %%mm2           nt" // add LBCarrys to (Raw(x-bpp)/2)
  199.                                                 // for each byte
  200.             "pand %%mm6, %%mm2            nt" // leave only Active Group 2
  201.                                                 // bytes to add to Avg
  202.             "paddb %%mm2, %%mm0           nt" // add (Raw/2) + LBCarrys to
  203.                                                 // Avg for each Active
  204.                                //  byte
  205.             // add 3rd active group (Raw(x-bpp)/2) to average with _LBCarry
  206.             "psllq _ShiftBpp, %%mm6       nt" // shift mm6 mask to cover last
  207.                                                 // two
  208.                                  // bytes
  209.             "movq %%mm0, %%mm2            nt" // mov updated Raws to mm2
  210.             "psllq _ShiftBpp, %%mm2       nt" // shift data to pos. correctly
  211.                               // Data only needs to be shifted once here to
  212.                               // get the correct x-bpp offset.
  213.             "movq %%mm3, %%mm1            nt" // now use mm1 for getting
  214.                                                 // LBCarrys
  215.             "pand %%mm2, %%mm1            nt" // get LBCarrys for each byte
  216.                                                 // where both
  217.                               // lsb's were == 1 (only valid for active group)
  218.             "psrlq $1, %%mm2              nt" // divide raw bytes by 2
  219.             "pand  %%mm4, %%mm2           nt" // clear invalid bit 7 of each
  220.                                                 // byte
  221.             "paddb %%mm1, %%mm2           nt" // add LBCarrys to (Raw(x-bpp)/2)
  222.                                                 // for each byte
  223.             "pand %%mm6, %%mm2            nt" // leave only Active Group 2
  224.                                                 // bytes to add to Avg
  225.             "addl $8, %%ecx               nt"
  226.             "paddb %%mm2, %%mm0           nt" // add (Raw/2) + LBCarrys to
  227.                                                 // Avg for each Active
  228.                                                 // byte
  229.             // now ready to write back to memory
  230.             "movq %%mm0, -8(%%edi,%%ecx,) nt"
  231.             // move updated Raw(x) to use as Raw(x-bpp) for next loop
  232.             "cmpl _MMXLength, %%ecx       nt"
  233.             "movq %%mm0, %%mm2            nt" // mov updated Raw(x) to mm2
  234.             "jb avg_3lp                   nt"
  235.             : "=S" (dummy_value_S),             // output regs (dummy)
  236.               "=D" (dummy_value_D)
  237.             : "0" (prev_row),  // esi           // input regs
  238.               "1" (row)        // edi
  239.             : "%ecx"                            // clobber list
  240. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  241.             , "%mm0", "%mm1", "%mm2", "%mm3"
  242.             , "%mm4", "%mm5", "%mm6", "%mm7"
  243. #endif
  244.          );
  245.       }
  246.       break;  // end 3 bpp
  247.       case 6:
  248.       case 4:
  249.       //case 7:   // who wrote this?  PNG doesn't support 5 or 7 bytes/pixel
  250.       //case 5:   // GRR BOGUS
  251.       {
  252.          _ActiveMask.use  = 0xffffffffffffffffLL; // use shift below to clear
  253.                                                   // appropriate inactive bytes
  254.          _ShiftBpp.use = bpp << 3;
  255.          _ShiftRem.use = 64 - _ShiftBpp.use;
  256.          __asm__ __volatile__ (
  257.             "movq _HBClearMask, %%mm4    nt"
  258.             // re-init address pointers and offset
  259.             "movl _dif, %%ecx            nt" // ecx:  x = offset to
  260.                                                // alignment boundary
  261.             // load _ActiveMask and clear all bytes except for 1st active group
  262.             "movq _ActiveMask, %%mm7     nt"
  263. // preload  "movl row, %%edi             nt" // edi:  Avg(x)
  264.             "psrlq _ShiftRem, %%mm7      nt"
  265. // preload  "movl prev_row, %%esi        nt" // esi:  Prior(x)
  266.             "movq %%mm7, %%mm6           nt"
  267.             "movq _LBCarryMask, %%mm5    nt"
  268.             "psllq _ShiftBpp, %%mm6      nt" // create mask for 2nd active
  269.                                                // group
  270.             // prime the pump:  load the first Raw(x-bpp) data set
  271.             "movq -8(%%edi,%%ecx,), %%mm2 nt" // load previous aligned 8 bytes
  272.                                           // (we correct pos. in loop below)
  273.          "avg_4lp:                       nt"
  274.             "movq (%%edi,%%ecx,), %%mm0  nt"
  275.             "psrlq _ShiftRem, %%mm2      nt" // shift data to pos. correctly
  276.             "movq (%%esi,%%ecx,), %%mm1  nt"
  277.             // add (Prev_row/2) to average
  278.             "movq %%mm5, %%mm3           nt"
  279.             "pand %%mm1, %%mm3           nt" // get lsb for each prev_row byte
  280.             "psrlq $1, %%mm1             nt" // divide prev_row bytes by 2
  281.             "pand  %%mm4, %%mm1          nt" // clear invalid bit 7 of each
  282.                                                // byte
  283.             "paddb %%mm1, %%mm0          nt" // add (Prev_row/2) to Avg for
  284.                                                // each byte
  285.             // add 1st active group (Raw(x-bpp)/2) to average with _LBCarry
  286.             "movq %%mm3, %%mm1           nt" // now use mm1 for getting
  287.                                                // LBCarrys
  288.             "pand %%mm2, %%mm1           nt" // get LBCarrys for each byte
  289.                                                // where both
  290.                               // lsb's were == 1 (only valid for active group)
  291.             "psrlq $1, %%mm2             nt" // divide raw bytes by 2
  292.             "pand  %%mm4, %%mm2          nt" // clear invalid bit 7 of each
  293.                                                // byte
  294.             "paddb %%mm1, %%mm2          nt" // add LBCarrys to (Raw(x-bpp)/2)
  295.                                                // for each byte
  296.             "pand %%mm7, %%mm2           nt" // leave only Active Group 1
  297.                                                // bytes to add to Avg
  298.             "paddb %%mm2, %%mm0          nt" // add (Raw/2) + LBCarrys to Avg
  299.                                                // for each Active
  300.                               // byte
  301.             // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry
  302.             "movq %%mm0, %%mm2           nt" // mov updated Raws to mm2
  303.             "psllq _ShiftBpp, %%mm2      nt" // shift data to pos. correctly
  304.             "addl $8, %%ecx              nt"
  305.             "movq %%mm3, %%mm1           nt" // now use mm1 for getting
  306.                                                // LBCarrys
  307.             "pand %%mm2, %%mm1           nt" // get LBCarrys for each byte
  308.                                                // where both
  309.                               // lsb's were == 1 (only valid for active group)
  310.             "psrlq $1, %%mm2             nt" // divide raw bytes by 2
  311.             "pand  %%mm4, %%mm2          nt" // clear invalid bit 7 of each
  312.                                                // byte
  313.             "paddb %%mm1, %%mm2          nt" // add LBCarrys to (Raw(x-bpp)/2)
  314.                                                // for each byte
  315.             "pand %%mm6, %%mm2           nt" // leave only Active Group 2
  316.                                                // bytes to add to Avg
  317.             "paddb %%mm2, %%mm0          nt" // add (Raw/2) + LBCarrys to
  318.                                                // Avg for each Active
  319.                               // byte
  320.             "cmpl _MMXLength, %%ecx      nt"
  321.             // now ready to write back to memory
  322.             "movq %%mm0, -8(%%edi,%%ecx,) nt"
  323.             // prep Raw(x-bpp) for next loop
  324.             "movq %%mm0, %%mm2           nt" // mov updated Raws to mm2
  325.             "jb avg_4lp                  nt"
  326.             : "=S" (dummy_value_S),            // output regs (dummy)
  327.               "=D" (dummy_value_D)
  328.             : "0" (prev_row),  // esi          // input regs
  329.               "1" (row)        // edi
  330.             : "%ecx"                           // clobber list
  331. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  332.             , "%mm0", "%mm1", "%mm2", "%mm3"
  333.             , "%mm4", "%mm5", "%mm6", "%mm7"
  334. #endif
  335.          );
  336.       }
  337.       break;  // end 4,6 bpp
  338.       case 2:
  339.       {
  340.          _ActiveMask.use  = 0x000000000000ffffLL;
  341.          _ShiftBpp.use = 16;   // == 2 * 8
  342.          _ShiftRem.use = 48;   // == 64 - 16
  343.          __asm__ __volatile__ (
  344.             // load _ActiveMask
  345.             "movq _ActiveMask, %%mm7     nt"
  346.             // re-init address pointers and offset
  347.             "movl _dif, %%ecx            nt" // ecx:  x = offset to alignment
  348.                                                // boundary
  349.             "movq _LBCarryMask, %%mm5    nt"
  350. // preload  "movl row, %%edi             nt" // edi:  Avg(x)
  351.             "movq _HBClearMask, %%mm4    nt"
  352. // preload  "movl prev_row, %%esi        nt" // esi:  Prior(x)
  353.             // prime the pump:  load the first Raw(x-bpp) data set
  354.             "movq -8(%%edi,%%ecx,), %%mm2 nt" // load previous aligned 8 bytes
  355.                               // (we correct pos. in loop below)
  356.          "avg_2lp:                       nt"
  357.             "movq (%%edi,%%ecx,), %%mm0  nt"
  358.             "psrlq _ShiftRem, %%mm2      nt" // shift data to pos. correctly
  359.             "movq (%%esi,%%ecx,), %%mm1  nt" //  (GRR BUGFIX:  was psllq)
  360.             // add (Prev_row/2) to average
  361.             "movq %%mm5, %%mm3           nt"
  362.             "pand %%mm1, %%mm3           nt" // get lsb for each prev_row byte
  363.             "psrlq $1, %%mm1             nt" // divide prev_row bytes by 2
  364.             "pand  %%mm4, %%mm1          nt" // clear invalid bit 7 of each
  365.                                                // byte
  366.             "movq %%mm7, %%mm6           nt"
  367.             "paddb %%mm1, %%mm0          nt" // add (Prev_row/2) to Avg for
  368.                                                // each byte
  369.             // add 1st active group (Raw(x-bpp)/2) to average with _LBCarry
  370.             "movq %%mm3, %%mm1           nt" // now use mm1 for getting
  371.                                                // LBCarrys
  372.             "pand %%mm2, %%mm1           nt" // get LBCarrys for each byte
  373.                                                // where both
  374.                                                // lsb's were == 1 (only valid
  375.                                                // for active group)
  376.             "psrlq $1, %%mm2             nt" // divide raw bytes by 2
  377.             "pand  %%mm4, %%mm2          nt" // clear invalid bit 7 of each
  378.                                                // byte
  379.             "paddb %%mm1, %%mm2          nt" // add LBCarrys to (Raw(x-bpp)/2)
  380.                                                // for each byte
  381.             "pand %%mm6, %%mm2           nt" // leave only Active Group 1
  382.                                                // bytes to add to Avg
  383.             "paddb %%mm2, %%mm0          nt" // add (Raw/2) + LBCarrys to Avg
  384.                                                // for each Active byte
  385.             // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry
  386.             "psllq _ShiftBpp, %%mm6      nt" // shift the mm6 mask to cover
  387.                                                // bytes 2 & 3
  388.             "movq %%mm0, %%mm2           nt" // mov updated Raws to mm2
  389.             "psllq _ShiftBpp, %%mm2      nt" // shift data to pos. correctly
  390.             "movq %%mm3, %%mm1           nt" // now use mm1 for getting
  391.                                                // LBCarrys
  392.             "pand %%mm2, %%mm1           nt" // get LBCarrys for each byte
  393.                                                // where both
  394.                                                // lsb's were == 1 (only valid
  395.                                                // for active group)
  396.             "psrlq $1, %%mm2             nt" // divide raw bytes by 2
  397.             "pand  %%mm4, %%mm2          nt" // clear invalid bit 7 of each
  398.                                                // byte
  399.             "paddb %%mm1, %%mm2          nt" // add LBCarrys to (Raw(x-bpp)/2)
  400.                                                // for each byte
  401.             "pand %%mm6, %%mm2           nt" // leave only Active Group 2
  402.                                                // bytes to add to Avg
  403.             "paddb %%mm2, %%mm0          nt" // add (Raw/2) + LBCarrys to
  404.                                                // Avg for each Active byte
  405.             // add 3rd active group (Raw(x-bpp)/2) to average with _LBCarry
  406.             "psllq _ShiftBpp, %%mm6      nt" // shift the mm6 mask to cover
  407.                                                // bytes 4 & 5
  408.             "movq %%mm0, %%mm2           nt" // mov updated Raws to mm2
  409.             "psllq _ShiftBpp, %%mm2      nt" // shift data to pos. correctly
  410.             "movq %%mm3, %%mm1           nt" // now use mm1 for getting
  411.                                                // LBCarrys
  412.             "pand %%mm2, %%mm1           nt" // get LBCarrys for each byte
  413.                                                // where both lsb's were == 1
  414.                                                // (only valid for active group)
  415.             "psrlq $1, %%mm2             nt" // divide raw bytes by 2
  416.             "pand  %%mm4, %%mm2          nt" // clear invalid bit 7 of each
  417.                                                // byte
  418.             "paddb %%mm1, %%mm2          nt" // add LBCarrys to (Raw(x-bpp)/2)
  419.                                                // for each byte
  420.             "pand %%mm6, %%mm2           nt" // leave only Active Group 2
  421.                                                // bytes to add to Avg
  422.             "paddb %%mm2, %%mm0          nt" // add (Raw/2) + LBCarrys to
  423.                                                // Avg for each Active byte
  424.             // add 4th active group (Raw(x-bpp)/2) to average with _LBCarry
  425.             "psllq _ShiftBpp, %%mm6      nt" // shift the mm6 mask to cover
  426.                                                // bytes 6 & 7
  427.             "movq %%mm0, %%mm2           nt" // mov updated Raws to mm2
  428.             "psllq _ShiftBpp, %%mm2      nt" // shift data to pos. correctly
  429.             "addl $8, %%ecx              nt"
  430.             "movq %%mm3, %%mm1           nt" // now use mm1 for getting
  431.                                                // LBCarrys
  432.             "pand %%mm2, %%mm1           nt" // get LBCarrys for each byte
  433.                                                // where both
  434.                                                // lsb's were == 1 (only valid
  435.                                                // for active group)
  436.             "psrlq $1, %%mm2             nt" // divide raw bytes by 2
  437.             "pand  %%mm4, %%mm2          nt" // clear invalid bit 7 of each
  438.                                                // byte
  439.             "paddb %%mm1, %%mm2          nt" // add LBCarrys to (Raw(x-bpp)/2)
  440.                                                // for each byte
  441.             "pand %%mm6, %%mm2           nt" // leave only Active Group 2
  442.                                                // bytes to add to Avg
  443.             "paddb %%mm2, %%mm0          nt" // add (Raw/2) + LBCarrys to
  444.                                                // Avg for each Active byte
  445.             "cmpl _MMXLength, %%ecx      nt"
  446.             // now ready to write back to memory
  447.             "movq %%mm0, -8(%%edi,%%ecx,) nt"
  448.             // prep Raw(x-bpp) for next loop
  449.             "movq %%mm0, %%mm2           nt" // mov updated Raws to mm2
  450.             "jb avg_2lp                  nt"
  451.             : "=S" (dummy_value_S),            // output regs (dummy)
  452.               "=D" (dummy_value_D)
  453.             : "0" (prev_row),  // esi          // input regs
  454.               "1" (row)        // edi
  455.             : "%ecx"                           // clobber list
  456. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  457.             , "%mm0", "%mm1", "%mm2", "%mm3"
  458.             , "%mm4", "%mm5", "%mm6", "%mm7"
  459. #endif
  460.          );
  461.       }
  462.       break;  // end 2 bpp
  463.       case 1:
  464.       {
  465.          __asm__ __volatile__ (
  466.             // re-init address pointers and offset
  467. #ifdef __PIC__
  468.             "pushl %%ebx                 nt" // save Global Offset Table index
  469. #endif
  470.             "movl _dif, %%ebx            nt" // ebx:  x = offset to alignment
  471.                                                // boundary
  472. // preload  "movl row, %%edi             nt" // edi:  Avg(x)
  473.             "cmpl _FullLength, %%ebx     nt" // test if offset at end of array
  474.             "jnb avg_1end                nt"
  475.             // do Paeth decode for remaining bytes
  476. // preload  "movl prev_row, %%esi        nt" // esi:  Prior(x)
  477.             "movl %%edi, %%edx           nt"
  478. // preload  "subl bpp, %%edx             nt" // (bpp is preloaded into ecx)
  479.             "subl %%ecx, %%edx           nt" // edx:  Raw(x-bpp)
  480.             "xorl %%ecx, %%ecx           nt" // zero ecx before using cl & cx
  481.                                                //  in loop below
  482.          "avg_1lp:                       nt"
  483.             // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
  484.             "xorl %%eax, %%eax           nt"
  485.             "movb (%%esi,%%ebx,), %%cl   nt" // load cl with Prior(x)
  486.             "movb (%%edx,%%ebx,), %%al   nt" // load al with Raw(x-bpp)
  487.             "addw %%cx, %%ax             nt"
  488.             "incl %%ebx                  nt"
  489.             "shrw %%ax                   nt" // divide by 2
  490.             "addb -1(%%edi,%%ebx,), %%al nt" // add Avg(x); -1 to offset
  491.                                                // inc ebx
  492.             "cmpl _FullLength, %%ebx     nt" // check if at end of array
  493.             "movb %%al, -1(%%edi,%%ebx,) nt" // write back Raw(x);
  494.                          // mov does not affect flags; -1 to offset inc ebx
  495.             "jb avg_1lp                  nt"
  496.          "avg_1end:                      nt"
  497. #ifdef __PIC__
  498.             "popl %%ebx                  nt" // Global Offset Table index
  499. #endif
  500.             : "=c" (dummy_value_c),            // output regs (dummy)
  501.               "=S" (dummy_value_S),
  502.               "=D" (dummy_value_D)
  503.             : "0" (bpp),       // ecx          // input regs
  504.               "1" (prev_row),  // esi
  505.               "2" (row)        // edi
  506.             : "%eax", "%edx"                   // clobber list
  507. #ifndef __PIC__
  508.             , "%ebx"
  509. #endif
  510.          );
  511.       }
  512.       return;  // end 1 bpp
  513.       case 8:
  514.       {
  515.          __asm__ __volatile__ (
  516.             // re-init address pointers and offset
  517.             "movl _dif, %%ecx            nt" // ecx:  x == offset to alignment
  518.             "movq _LBCarryMask, %%mm5    nt" //            boundary
  519. // preload  "movl row, %%edi             nt" // edi:  Avg(x)
  520.             "movq _HBClearMask, %%mm4    nt"
  521. // preload  "movl prev_row, %%esi        nt" // esi:  Prior(x)
  522.             // prime the pump:  load the first Raw(x-bpp) data set
  523.             "movq -8(%%edi,%%ecx,), %%mm2 nt" // load previous aligned 8 bytes
  524.                                       // (NO NEED to correct pos. in loop below)
  525.          "avg_8lp:                       nt"
  526.             "movq (%%edi,%%ecx,), %%mm0  nt"
  527.             "movq %%mm5, %%mm3           nt"
  528.             "movq (%%esi,%%ecx,), %%mm1  nt"
  529.             "addl $8, %%ecx              nt"
  530.             "pand %%mm1, %%mm3           nt" // get lsb for each prev_row byte
  531.             "psrlq $1, %%mm1             nt" // divide prev_row bytes by 2
  532.             "pand %%mm2, %%mm3           nt" // get LBCarrys for each byte
  533.                                                //  where both lsb's were == 1
  534.             "psrlq $1, %%mm2             nt" // divide raw bytes by 2
  535.             "pand  %%mm4, %%mm1          nt" // clear invalid bit 7, each byte
  536.             "paddb %%mm3, %%mm0          nt" // add LBCarrys to Avg, each byte
  537.             "pand  %%mm4, %%mm2          nt" // clear invalid bit 7, each byte
  538.             "paddb %%mm1, %%mm0          nt" // add (Prev_row/2) to Avg, each
  539.             "paddb %%mm2, %%mm0          nt" // add (Raw/2) to Avg for each
  540.             "cmpl _MMXLength, %%ecx      nt"
  541.             "movq %%mm0, -8(%%edi,%%ecx,) nt"
  542.             "movq %%mm0, %%mm2           nt" // reuse as Raw(x-bpp)
  543.             "jb avg_8lp                  nt"
  544.             : "=S" (dummy_value_S),            // output regs (dummy)
  545.               "=D" (dummy_value_D)
  546.             : "0" (prev_row),  // esi          // input regs
  547.               "1" (row)        // edi
  548.             : "%ecx"                           // clobber list
  549. #if 0  /* %mm0, ..., %mm5 not supported by gcc 2.7.2.3 or egcs 1.1 */
  550.             , "%mm0", "%mm1", "%mm2"
  551.             , "%mm3", "%mm4", "%mm5"
  552. #endif
  553.          );
  554.       }
  555.       break;  // end 8 bpp
  556.       default:                  // bpp greater than 8 (!= 1,2,3,4,[5],6,[7],8)
  557.       {
  558. #ifdef PNG_DEBUG
  559.          // GRR:  PRINT ERROR HERE:  SHOULD NEVER BE REACHED
  560.         png_debug(1,
  561.         "Internal logic error in pnggccrd (png_read_filter_row_mmx_avg())n");
  562. #endif
  563. #if 0
  564.         __asm__ __volatile__ (
  565.             "movq _LBCarryMask, %%mm5    nt"
  566.             // re-init address pointers and offset
  567.             "movl _dif, %%ebx            nt" // ebx:  x = offset to
  568.                                                // alignment boundary
  569.             "movl row, %%edi             nt" // edi:  Avg(x)
  570.             "movq _HBClearMask, %%mm4    nt"
  571.             "movl %%edi, %%edx           nt"
  572.             "movl prev_row, %%esi        nt" // esi:  Prior(x)
  573.             "subl bpp, %%edx             nt" // edx:  Raw(x-bpp)
  574.          "avg_Alp:                       nt"
  575.             "movq (%%edi,%%ebx,), %%mm0  nt"
  576.             "movq %%mm5, %%mm3           nt"
  577.             "movq (%%esi,%%ebx,), %%mm1  nt"
  578.             "pand %%mm1, %%mm3           nt" // get lsb for each prev_row byte
  579.             "movq (%%edx,%%ebx,), %%mm2  nt"
  580.             "psrlq $1, %%mm1             nt" // divide prev_row bytes by 2
  581.             "pand %%mm2, %%mm3           nt" // get LBCarrys for each byte
  582.                                                // where both lsb's were == 1
  583.             "psrlq $1, %%mm2             nt" // divide raw bytes by 2
  584.             "pand  %%mm4, %%mm1          nt" // clear invalid bit 7 of each
  585.                                                // byte
  586.             "paddb %%mm3, %%mm0          nt" // add LBCarrys to Avg for each
  587.                                                // byte
  588.             "pand  %%mm4, %%mm2          nt" // clear invalid bit 7 of each
  589.                                                // byte
  590.             "paddb %%mm1, %%mm0          nt" // add (Prev_row/2) to Avg for
  591.                                                // each byte
  592.             "addl $8, %%ebx              nt"
  593.             "paddb %%mm2, %%mm0          nt" // add (Raw/2) to Avg for each
  594.                                                // byte
  595.             "cmpl _MMXLength, %%ebx      nt"
  596.             "movq %%mm0, -8(%%edi,%%ebx,) nt"
  597.             "jb avg_Alp                  nt"
  598.             : // FIXASM: output regs/vars go here, e.g.:  "=m" (memory_var)
  599.             : // FIXASM: input regs, e.g.:  "c" (count), "S" (src), "D" (dest)
  600.             : "%ebx", "%edx", "%edi", "%esi" // CHECKASM: clobber list
  601.          );
  602. #endif /* 0 - NEVER REACHED */
  603.       }
  604.       break;
  605.    } // end switch (bpp)
  606.    __asm__ __volatile__ (
  607.       // MMX acceleration complete; now do clean-up
  608.       // check if any remaining bytes left to decode
  609. #ifdef __PIC__
  610.       "pushl %%ebx                 nt" // save index to Global Offset Table
  611. #endif
  612.       "movl _MMXLength, %%ebx      nt" // ebx:  x == offset bytes after MMX
  613. //pre "movl row, %%edi             nt" // edi:  Avg(x)
  614.       "cmpl _FullLength, %%ebx     nt" // test if offset at end of array
  615.       "jnb avg_end                 nt"
  616.       // do Avg decode for remaining bytes
  617. //pre "movl prev_row, %%esi        nt" // esi:  Prior(x)
  618.       "movl %%edi, %%edx           nt"
  619. //pre "subl bpp, %%edx             nt" // (bpp is preloaded into ecx)
  620.       "subl %%ecx, %%edx           nt" // edx:  Raw(x-bpp)
  621.       "xorl %%ecx, %%ecx           nt" // zero ecx before using cl & cx below
  622.    "avg_lp2:                       nt"
  623.       // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
  624.       "xorl %%eax, %%eax           nt"
  625.       "movb (%%esi,%%ebx,), %%cl   nt" // load cl with Prior(x)
  626.       "movb (%%edx,%%ebx,), %%al   nt" // load al with Raw(x-bpp)
  627.       "addw %%cx, %%ax             nt"
  628.       "incl %%ebx                  nt"
  629.       "shrw %%ax                   nt" // divide by 2
  630.       "addb -1(%%edi,%%ebx,), %%al nt" // add Avg(x); -1 to offset inc ebx
  631.       "cmpl _FullLength, %%ebx     nt" // check if at end of array
  632.       "movb %%al, -1(%%edi,%%ebx,) nt" // write back Raw(x) [mov does not
  633.       "jb avg_lp2                  nt" //  affect flags; -1 to offset inc ebx]
  634.    "avg_end:                       nt"
  635.       "EMMS                        nt" // end MMX; prep for poss. FP instrs.
  636. #ifdef __PIC__
  637.       "popl %%ebx                  nt" // restore index to Global Offset Table
  638. #endif
  639.       : "=c" (dummy_value_c),            // output regs (dummy)
  640.         "=S" (dummy_value_S),
  641.         "=D" (dummy_value_D)
  642.       : "0" (bpp),       // ecx          // input regs
  643.         "1" (prev_row),  // esi
  644.         "2" (row)        // edi
  645.       : "%eax", "%edx"                   // clobber list
  646. #ifndef __PIC__
  647.       , "%ebx"
  648. #endif
  649.    );
  650. } /* end png_read_filter_row_mmx_avg() */
  651. #endif
  652. #ifdef PNG_THREAD_UNSAFE_OK
  653. //===========================================================================//
  654. //                                                                           //
  655. //         P N G _ R E A D _ F I L T E R _ R O W _ M M X _ P A E T H         //
  656. //                                                                           //
  657. //===========================================================================//
  658. // Optimized code for PNG Paeth filter decoder
  659. static void /* PRIVATE */
  660. png_read_filter_row_mmx_paeth(png_row_infop row_info, png_bytep row,
  661.                               png_bytep prev_row)
  662. {
  663.    int bpp;
  664.    int dummy_value_c;   // fix 'forbidden register 2 (cx) was spilled' error
  665.    int dummy_value_S;
  666.    int dummy_value_D;
  667.    bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel
  668.    _FullLength  = row_info->rowbytes; // # of bytes to filter
  669.    __asm__ __volatile__ (
  670. #ifdef __PIC__
  671.       "pushl %%ebx                 nt" // save index to Global Offset Table
  672. #endif
  673.       "xorl %%ebx, %%ebx           nt" // ebx:  x offset
  674. //pre "movl row, %%edi             nt"
  675.       "xorl %%edx, %%edx           nt" // edx:  x-bpp offset
  676. //pre "movl prev_row, %%esi        nt"
  677.       "xorl %%eax, %%eax           nt"
  678.       // Compute the Raw value for the first bpp bytes
  679.       // Note: the formula works out to be always
  680.       //   Paeth(x) = Raw(x) + Prior(x)      where x < bpp
  681.    "paeth_rlp:                     nt"
  682.       "movb (%%edi,%%ebx,), %%al   nt"
  683.       "addb (%%esi,%%ebx,), %%al   nt"
  684.       "incl %%ebx                  nt"
  685. //pre "cmpl bpp, %%ebx             nt" (bpp is preloaded into ecx)
  686.       "cmpl %%ecx, %%ebx           nt"
  687.       "movb %%al, -1(%%edi,%%ebx,) nt"
  688.       "jb paeth_rlp                nt"
  689.       // get # of bytes to alignment
  690.       "movl %%edi, _dif            nt" // take start of row
  691.       "addl %%ebx, _dif            nt" // add bpp
  692.       "xorl %%ecx, %%ecx           nt"
  693.       "addl $0xf, _dif             nt" // add 7 + 8 to incr past alignment
  694.                                          // boundary
  695.       "andl $0xfffffff8, _dif      nt" // mask to alignment boundary
  696.       "subl %%edi, _dif            nt" // subtract from start ==> value ebx
  697.                                          // at alignment
  698.       "jz paeth_go                 nt"
  699.       // fix alignment
  700.    "paeth_lp1:                     nt"
  701.       "xorl %%eax, %%eax           nt"
  702.       // pav = p - a = (a + b - c) - a = b - c
  703.       "movb (%%esi,%%ebx,), %%al   nt" // load Prior(x) into al
  704.       "movb (%%esi,%%edx,), %%cl   nt" // load Prior(x-bpp) into cl
  705.       "subl %%ecx, %%eax           nt" // subtract Prior(x-bpp)
  706.       "movl %%eax, _patemp         nt" // Save pav for later use
  707.       "xorl %%eax, %%eax           nt"
  708.       // pbv = p - b = (a + b - c) - b = a - c
  709.       "movb (%%edi,%%edx,), %%al   nt" // load Raw(x-bpp) into al
  710.       "subl %%ecx, %%eax           nt" // subtract Prior(x-bpp)
  711.       "movl %%eax, %%ecx           nt"
  712.       // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  713.       "addl _patemp, %%eax         nt" // pcv = pav + pbv
  714.       // pc = abs(pcv)
  715.       "testl $0x80000000, %%eax    nt"
  716.       "jz paeth_pca                nt"
  717.       "negl %%eax                  nt" // reverse sign of neg values
  718.    "paeth_pca:                     nt"
  719.       "movl %%eax, _pctemp         nt" // save pc for later use
  720.       // pb = abs(pbv)
  721.       "testl $0x80000000, %%ecx    nt"
  722.       "jz paeth_pba                nt"
  723.       "negl %%ecx                  nt" // reverse sign of neg values
  724.    "paeth_pba:                     nt"
  725.       "movl %%ecx, _pbtemp         nt" // save pb for later use
  726.       // pa = abs(pav)
  727.       "movl _patemp, %%eax         nt"
  728.       "testl $0x80000000, %%eax    nt"
  729.       "jz paeth_paa                nt"
  730.       "negl %%eax                  nt" // reverse sign of neg values
  731.    "paeth_paa:                     nt"
  732.       "movl %%eax, _patemp         nt" // save pa for later use
  733.       // test if pa <= pb
  734.       "cmpl %%ecx, %%eax           nt"
  735.       "jna paeth_abb               nt"
  736.       // pa > pb; now test if pb <= pc
  737.       "cmpl _pctemp, %%ecx         nt"
  738.       "jna paeth_bbc               nt"
  739.       // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
  740.       "movb (%%esi,%%edx,), %%cl   nt" // load Prior(x-bpp) into cl
  741.       "jmp paeth_paeth             nt"
  742.    "paeth_bbc:                     nt"
  743.       // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
  744.       "movb (%%esi,%%ebx,), %%cl   nt" // load Prior(x) into cl
  745.       "jmp paeth_paeth             nt"
  746.    "paeth_abb:                     nt"
  747.       // pa <= pb; now test if pa <= pc
  748.       "cmpl _pctemp, %%eax         nt"
  749.       "jna paeth_abc               nt"
  750.       // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
  751.       "movb (%%esi,%%edx,), %%cl   nt" // load Prior(x-bpp) into cl
  752.       "jmp paeth_paeth             nt"
  753.    "paeth_abc:                     nt"
  754.       // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
  755.       "movb (%%edi,%%edx,), %%cl   nt" // load Raw(x-bpp) into cl
  756.    "paeth_paeth:                   nt"
  757.       "incl %%ebx                  nt"
  758.       "incl %%edx                  nt"
  759.       // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
  760.       "addb %%cl, -1(%%edi,%%ebx,) nt"
  761.       "cmpl _dif, %%ebx            nt"
  762.       "jb paeth_lp1                nt"
  763.    "paeth_go:                      nt"
  764.       "movl _FullLength, %%ecx     nt"
  765.       "movl %%ecx, %%eax           nt"
  766.       "subl %%ebx, %%eax           nt" // subtract alignment fix
  767.       "andl $0x00000007, %%eax     nt" // calc bytes over mult of 8
  768.       "subl %%eax, %%ecx           nt" // drop over bytes from original length
  769.       "movl %%ecx, _MMXLength      nt"
  770. #ifdef __PIC__
  771.       "popl %%ebx                  nt" // restore index to Global Offset Table
  772. #endif
  773.       : "=c" (dummy_value_c),            // output regs (dummy)
  774.         "=S" (dummy_value_S),
  775.         "=D" (dummy_value_D)
  776.       : "0" (bpp),       // ecx          // input regs
  777.         "1" (prev_row),  // esi
  778.         "2" (row)        // edi
  779.       : "%eax", "%edx"                   // clobber list
  780. #ifndef __PIC__
  781.       , "%ebx"
  782. #endif
  783.    );
  784.    // now do the math for the rest of the row
  785.    switch (bpp)
  786.    {
  787.       case 3:
  788.       {
  789.          _ActiveMask.use = 0x0000000000ffffffLL;
  790.          _ActiveMaskEnd.use = 0xffff000000000000LL;
  791.          _ShiftBpp.use = 24;    // == bpp(3) * 8
  792.          _ShiftRem.use = 40;    // == 64 - 24
  793.          __asm__ __volatile__ (
  794.             "movl _dif, %%ecx            nt"
  795. // preload  "movl row, %%edi             nt"
  796. // preload  "movl prev_row, %%esi        nt"
  797.             "pxor %%mm0, %%mm0           nt"
  798.             // prime the pump:  load the first Raw(x-bpp) data set
  799.             "movq -8(%%edi,%%ecx,), %%mm1 nt"
  800.          "paeth_3lp:                     nt"
  801.             "psrlq _ShiftRem, %%mm1      nt" // shift last 3 bytes to 1st
  802.                                                // 3 bytes
  803.             "movq (%%esi,%%ecx,), %%mm2  nt" // load b=Prior(x)
  804.             "punpcklbw %%mm0, %%mm1      nt" // unpack High bytes of a
  805.             "movq -8(%%esi,%%ecx,), %%mm3 nt" // prep c=Prior(x-bpp) bytes
  806.             "punpcklbw %%mm0, %%mm2      nt" // unpack High bytes of b
  807.             "psrlq _ShiftRem, %%mm3      nt" // shift last 3 bytes to 1st
  808.                                                // 3 bytes
  809.             // pav = p - a = (a + b - c) - a = b - c
  810.             "movq %%mm2, %%mm4           nt"
  811.             "punpcklbw %%mm0, %%mm3      nt" // unpack High bytes of c
  812.             // pbv = p - b = (a + b - c) - b = a - c
  813.             "movq %%mm1, %%mm5           nt"
  814.             "psubw %%mm3, %%mm4          nt"
  815.             "pxor %%mm7, %%mm7           nt"
  816.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  817.             "movq %%mm4, %%mm6           nt"
  818.             "psubw %%mm3, %%mm5          nt"
  819.             // pa = abs(p-a) = abs(pav)
  820.             // pb = abs(p-b) = abs(pbv)
  821.             // pc = abs(p-c) = abs(pcv)
  822.             "pcmpgtw %%mm4, %%mm0        nt" // create mask pav bytes < 0
  823.             "paddw %%mm5, %%mm6          nt"
  824.             "pand %%mm4, %%mm0           nt" // only pav bytes < 0 in mm7
  825.             "pcmpgtw %%mm5, %%mm7        nt" // create mask pbv bytes < 0
  826.             "psubw %%mm0, %%mm4          nt"
  827.             "pand %%mm5, %%mm7           nt" // only pbv bytes < 0 in mm0
  828.             "psubw %%mm0, %%mm4          nt"
  829.             "psubw %%mm7, %%mm5          nt"
  830.             "pxor %%mm0, %%mm0           nt"
  831.             "pcmpgtw %%mm6, %%mm0        nt" // create mask pcv bytes < 0
  832.             "pand %%mm6, %%mm0           nt" // only pav bytes < 0 in mm7
  833.             "psubw %%mm7, %%mm5          nt"
  834.             "psubw %%mm0, %%mm6          nt"
  835.             //  test pa <= pb
  836.             "movq %%mm4, %%mm7           nt"
  837.             "psubw %%mm0, %%mm6          nt"
  838.             "pcmpgtw %%mm5, %%mm7        nt" // pa > pb?
  839.             "movq %%mm7, %%mm0           nt"
  840.             // use mm7 mask to merge pa & pb
  841.             "pand %%mm7, %%mm5           nt"
  842.             // use mm0 mask copy to merge a & b
  843.             "pand %%mm0, %%mm2           nt"
  844.             "pandn %%mm4, %%mm7          nt"
  845.             "pandn %%mm1, %%mm0          nt"
  846.             "paddw %%mm5, %%mm7          nt"
  847.             "paddw %%mm2, %%mm0          nt"
  848.             //  test  ((pa <= pb)? pa:pb) <= pc
  849.             "pcmpgtw %%mm6, %%mm7        nt" // pab > pc?
  850.             "pxor %%mm1, %%mm1           nt"
  851.             "pand %%mm7, %%mm3           nt"
  852.             "pandn %%mm0, %%mm7          nt"
  853.             "paddw %%mm3, %%mm7          nt"
  854.             "pxor %%mm0, %%mm0           nt"
  855.             "packuswb %%mm1, %%mm7       nt"
  856.             "movq (%%esi,%%ecx,), %%mm3  nt" // load c=Prior(x-bpp)
  857.             "pand _ActiveMask, %%mm7     nt"
  858.             "movq %%mm3, %%mm2           nt" // load b=Prior(x) step 1
  859.             "paddb (%%edi,%%ecx,), %%mm7 nt" // add Paeth predictor with Raw(x)
  860.             "punpcklbw %%mm0, %%mm3      nt" // unpack High bytes of c
  861.             "movq %%mm7, (%%edi,%%ecx,)  nt" // write back updated value
  862.             "movq %%mm7, %%mm1           nt" // now mm1 will be used as
  863.                                                // Raw(x-bpp)
  864.             // now do Paeth for 2nd set of bytes (3-5)
  865.             "psrlq _ShiftBpp, %%mm2      nt" // load b=Prior(x) step 2
  866.             "punpcklbw %%mm0, %%mm1      nt" // unpack High bytes of a
  867.             "pxor %%mm7, %%mm7           nt"
  868.             "punpcklbw %%mm0, %%mm2      nt" // unpack High bytes of b
  869.             // pbv = p - b = (a + b - c) - b = a - c
  870.             "movq %%mm1, %%mm5           nt"
  871.             // pav = p - a = (a + b - c) - a = b - c
  872.             "movq %%mm2, %%mm4           nt"
  873.             "psubw %%mm3, %%mm5          nt"
  874.             "psubw %%mm3, %%mm4          nt"
  875.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) =
  876.             //       pav + pbv = pbv + pav
  877.             "movq %%mm5, %%mm6           nt"
  878.             "paddw %%mm4, %%mm6          nt"
  879.             // pa = abs(p-a) = abs(pav)
  880.             // pb = abs(p-b) = abs(pbv)
  881.             // pc = abs(p-c) = abs(pcv)
  882.             "pcmpgtw %%mm5, %%mm0        nt" // create mask pbv bytes < 0
  883.             "pcmpgtw %%mm4, %%mm7        nt" // create mask pav bytes < 0
  884.             "pand %%mm5, %%mm0           nt" // only pbv bytes < 0 in mm0
  885.             "pand %%mm4, %%mm7           nt" // only pav bytes < 0 in mm7
  886.             "psubw %%mm0, %%mm5          nt"
  887.             "psubw %%mm7, %%mm4          nt"
  888.             "psubw %%mm0, %%mm5          nt"
  889.             "psubw %%mm7, %%mm4          nt"
  890.             "pxor %%mm0, %%mm0           nt"
  891.             "pcmpgtw %%mm6, %%mm0        nt" // create mask pcv bytes < 0
  892.             "pand %%mm6, %%mm0           nt" // only pav bytes < 0 in mm7
  893.             "psubw %%mm0, %%mm6          nt"
  894.             //  test pa <= pb
  895.             "movq %%mm4, %%mm7           nt"
  896.             "psubw %%mm0, %%mm6          nt"
  897.             "pcmpgtw %%mm5, %%mm7        nt" // pa > pb?
  898.             "movq %%mm7, %%mm0           nt"
  899.             // use mm7 mask to merge pa & pb
  900.             "pand %%mm7, %%mm5           nt"
  901.             // use mm0 mask copy to merge a & b
  902.             "pand %%mm0, %%mm2           nt"
  903.             "pandn %%mm4, %%mm7          nt"
  904.             "pandn %%mm1, %%mm0          nt"
  905.             "paddw %%mm5, %%mm7          nt"
  906.             "paddw %%mm2, %%mm0          nt"
  907.             //  test  ((pa <= pb)? pa:pb) <= pc
  908.             "pcmpgtw %%mm6, %%mm7        nt" // pab > pc?
  909.             "movq (%%esi,%%ecx,), %%mm2  nt" // load b=Prior(x)
  910.             "pand %%mm7, %%mm3           nt"
  911.             "pandn %%mm0, %%mm7          nt"
  912.             "pxor %%mm1, %%mm1           nt"
  913.             "paddw %%mm3, %%mm7          nt"
  914.             "pxor %%mm0, %%mm0           nt"
  915.             "packuswb %%mm1, %%mm7       nt"
  916.             "movq %%mm2, %%mm3           nt" // load c=Prior(x-bpp) step 1
  917.             "pand _ActiveMask, %%mm7     nt"
  918.             "punpckhbw %%mm0, %%mm2      nt" // unpack High bytes of b
  919.             "psllq _ShiftBpp, %%mm7      nt" // shift bytes to 2nd group of
  920.                                                // 3 bytes
  921.              // pav = p - a = (a + b - c) - a = b - c
  922.             "movq %%mm2, %%mm4           nt"
  923.             "paddb (%%edi,%%ecx,), %%mm7 nt" // add Paeth predictor with Raw(x)
  924.             "psllq _ShiftBpp, %%mm3      nt" // load c=Prior(x-bpp) step 2
  925.             "movq %%mm7, (%%edi,%%ecx,)  nt" // write back updated value
  926.             "movq %%mm7, %%mm1           nt"
  927.             "punpckhbw %%mm0, %%mm3      nt" // unpack High bytes of c
  928.             "psllq _ShiftBpp, %%mm1      nt" // shift bytes
  929.                                     // now mm1 will be used as Raw(x-bpp)
  930.             // now do Paeth for 3rd, and final, set of bytes (6-7)
  931.             "pxor %%mm7, %%mm7           nt"
  932.             "punpckhbw %%mm0, %%mm1      nt" // unpack High bytes of a
  933.             "psubw %%mm3, %%mm4          nt"
  934.             // pbv = p - b = (a + b - c) - b = a - c
  935.             "movq %%mm1, %%mm5           nt"
  936.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  937.             "movq %%mm4, %%mm6           nt"
  938.             "psubw %%mm3, %%mm5          nt"
  939.             "pxor %%mm0, %%mm0           nt"
  940.             "paddw %%mm5, %%mm6          nt"
  941.             // pa = abs(p-a) = abs(pav)
  942.             // pb = abs(p-b) = abs(pbv)
  943.             // pc = abs(p-c) = abs(pcv)
  944.             "pcmpgtw %%mm4, %%mm0        nt" // create mask pav bytes < 0
  945.             "pcmpgtw %%mm5, %%mm7        nt" // create mask pbv bytes < 0
  946.             "pand %%mm4, %%mm0           nt" // only pav bytes < 0 in mm7
  947.             "pand %%mm5, %%mm7           nt" // only pbv bytes < 0 in mm0
  948.             "psubw %%mm0, %%mm4          nt"
  949.             "psubw %%mm7, %%mm5          nt"
  950.             "psubw %%mm0, %%mm4          nt"
  951.             "psubw %%mm7, %%mm5          nt"
  952.             "pxor %%mm0, %%mm0           nt"
  953.             "pcmpgtw %%mm6, %%mm0        nt" // create mask pcv bytes < 0
  954.             "pand %%mm6, %%mm0           nt" // only pav bytes < 0 in mm7
  955.             "psubw %%mm0, %%mm6          nt"
  956.             //  test pa <= pb
  957.             "movq %%mm4, %%mm7           nt"
  958.             "psubw %%mm0, %%mm6          nt"
  959.             "pcmpgtw %%mm5, %%mm7        nt" // pa > pb?
  960.             "movq %%mm7, %%mm0           nt"
  961.             // use mm0 mask copy to merge a & b
  962.             "pand %%mm0, %%mm2           nt"
  963.             // use mm7 mask to merge pa & pb
  964.             "pand %%mm7, %%mm5           nt"
  965.             "pandn %%mm1, %%mm0          nt"
  966.             "pandn %%mm4, %%mm7          nt"
  967.             "paddw %%mm2, %%mm0          nt"
  968.             "paddw %%mm5, %%mm7          nt"
  969.             //  test  ((pa <= pb)? pa:pb) <= pc
  970.             "pcmpgtw %%mm6, %%mm7        nt" // pab > pc?
  971.             "pand %%mm7, %%mm3           nt"
  972.             "pandn %%mm0, %%mm7          nt"
  973.             "paddw %%mm3, %%mm7          nt"
  974.             "pxor %%mm1, %%mm1           nt"
  975.             "packuswb %%mm7, %%mm1       nt"
  976.             // step ecx to next set of 8 bytes and repeat loop til done
  977.             "addl $8, %%ecx              nt"
  978.             "pand _ActiveMaskEnd, %%mm1  nt"
  979.             "paddb -8(%%edi,%%ecx,), %%mm1 nt" // add Paeth predictor with
  980.                                                  // Raw(x)
  981.             "cmpl _MMXLength, %%ecx      nt"
  982.             "pxor %%mm0, %%mm0           nt" // pxor does not affect flags
  983.             "movq %%mm1, -8(%%edi,%%ecx,) nt" // write back updated value
  984.                                  // mm1 will be used as Raw(x-bpp) next loop
  985.                            // mm3 ready to be used as Prior(x-bpp) next loop
  986.             "jb paeth_3lp                nt"
  987.             : "=S" (dummy_value_S),             // output regs (dummy)
  988.               "=D" (dummy_value_D)
  989.             : "0" (prev_row),  // esi           // input regs
  990.               "1" (row)        // edi
  991.             : "%ecx"                            // clobber list
  992. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  993.             , "%mm0", "%mm1", "%mm2", "%mm3"
  994.             , "%mm4", "%mm5", "%mm6", "%mm7"
  995. #endif
  996.          );
  997.       }
  998.       break;  // end 3 bpp
  999.       case 6:
  1000.       //case 7:   // GRR BOGUS
  1001.       //case 5:   // GRR BOGUS
  1002.       {
  1003.          _ActiveMask.use  = 0x00000000ffffffffLL;
  1004.          _ActiveMask2.use = 0xffffffff00000000LL;
  1005.          _ShiftBpp.use = bpp << 3;    // == bpp * 8
  1006.          _ShiftRem.use = 64 - _ShiftBpp.use;
  1007.          __asm__ __volatile__ (
  1008.             "movl _dif, %%ecx            nt"
  1009. // preload  "movl row, %%edi             nt"
  1010. // preload  "movl prev_row, %%esi        nt"
  1011.             // prime the pump:  load the first Raw(x-bpp) data set
  1012.             "movq -8(%%edi,%%ecx,), %%mm1 nt"
  1013.             "pxor %%mm0, %%mm0           nt"
  1014.          "paeth_6lp:                     nt"
  1015.             // must shift to position Raw(x-bpp) data
  1016.             "psrlq _ShiftRem, %%mm1      nt"
  1017.             // do first set of 4 bytes
  1018.             "movq -8(%%esi,%%ecx,), %%mm3 nt" // read c=Prior(x-bpp) bytes
  1019.             "punpcklbw %%mm0, %%mm1      nt" // unpack Low bytes of a
  1020.             "movq (%%esi,%%ecx,), %%mm2  nt" // load b=Prior(x)
  1021.             "punpcklbw %%mm0, %%mm2      nt" // unpack Low bytes of b
  1022.             // must shift to position Prior(x-bpp) data
  1023.             "psrlq _ShiftRem, %%mm3      nt"
  1024.             // pav = p - a = (a + b - c) - a = b - c
  1025.             "movq %%mm2, %%mm4           nt"
  1026.             "punpcklbw %%mm0, %%mm3      nt" // unpack Low bytes of c
  1027.             // pbv = p - b = (a + b - c) - b = a - c
  1028.             "movq %%mm1, %%mm5           nt"
  1029.             "psubw %%mm3, %%mm4          nt"
  1030.             "pxor %%mm7, %%mm7           nt"
  1031.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  1032.             "movq %%mm4, %%mm6           nt"
  1033.             "psubw %%mm3, %%mm5          nt"
  1034.             // pa = abs(p-a) = abs(pav)
  1035.             // pb = abs(p-b) = abs(pbv)
  1036.             // pc = abs(p-c) = abs(pcv)
  1037.             "pcmpgtw %%mm4, %%mm0        nt" // create mask pav bytes < 0
  1038.             "paddw %%mm5, %%mm6          nt"
  1039.             "pand %%mm4, %%mm0           nt" // only pav bytes < 0 in mm7
  1040.             "pcmpgtw %%mm5, %%mm7        nt" // create mask pbv bytes < 0
  1041.             "psubw %%mm0, %%mm4          nt"
  1042.             "pand %%mm5, %%mm7           nt" // only pbv bytes < 0 in mm0
  1043.             "psubw %%mm0, %%mm4          nt"
  1044.             "psubw %%mm7, %%mm5          nt"
  1045.             "pxor %%mm0, %%mm0           nt"
  1046.             "pcmpgtw %%mm6, %%mm0        nt" // create mask pcv bytes < 0
  1047.             "pand %%mm6, %%mm0           nt" // only pav bytes < 0 in mm7
  1048.             "psubw %%mm7, %%mm5          nt"
  1049.             "psubw %%mm0, %%mm6          nt"
  1050.             //  test pa <= pb
  1051.             "movq %%mm4, %%mm7           nt"
  1052.             "psubw %%mm0, %%mm6          nt"
  1053.             "pcmpgtw %%mm5, %%mm7        nt" // pa > pb?
  1054.             "movq %%mm7, %%mm0           nt"
  1055.             // use mm7 mask to merge pa & pb
  1056.             "pand %%mm7, %%mm5           nt"
  1057.             // use mm0 mask copy to merge a & b
  1058.             "pand %%mm0, %%mm2           nt"
  1059.             "pandn %%mm4, %%mm7          nt"
  1060.             "pandn %%mm1, %%mm0          nt"
  1061.             "paddw %%mm5, %%mm7          nt"
  1062.             "paddw %%mm2, %%mm0          nt"
  1063.             //  test  ((pa <= pb)? pa:pb) <= pc
  1064.             "pcmpgtw %%mm6, %%mm7        nt" // pab > pc?
  1065.             "pxor %%mm1, %%mm1           nt"
  1066.             "pand %%mm7, %%mm3           nt"
  1067.             "pandn %%mm0, %%mm7          nt"
  1068.             "paddw %%mm3, %%mm7          nt"
  1069.             "pxor %%mm0, %%mm0           nt"
  1070.             "packuswb %%mm1, %%mm7       nt"
  1071.             "movq -8(%%esi,%%ecx,), %%mm3 nt" // load c=Prior(x-bpp)
  1072.             "pand _ActiveMask, %%mm7     nt"
  1073.             "psrlq _ShiftRem, %%mm3      nt"
  1074.             "movq (%%esi,%%ecx,), %%mm2  nt" // load b=Prior(x) step 1
  1075.             "paddb (%%edi,%%ecx,), %%mm7 nt" // add Paeth predictor and Raw(x)
  1076.             "movq %%mm2, %%mm6           nt"
  1077.             "movq %%mm7, (%%edi,%%ecx,)  nt" // write back updated value
  1078.             "movq -8(%%edi,%%ecx,), %%mm1 nt"
  1079.             "psllq _ShiftBpp, %%mm6      nt"
  1080.             "movq %%mm7, %%mm5           nt"
  1081.             "psrlq _ShiftRem, %%mm1      nt"
  1082.             "por %%mm6, %%mm3            nt"
  1083.             "psllq _ShiftBpp, %%mm5      nt"
  1084.             "punpckhbw %%mm0, %%mm3      nt" // unpack High bytes of c
  1085.             "por %%mm5, %%mm1            nt"
  1086.             // do second set of 4 bytes
  1087.             "punpckhbw %%mm0, %%mm2      nt" // unpack High bytes of b
  1088.             "punpckhbw %%mm0, %%mm1      nt" // unpack High bytes of a
  1089.             // pav = p - a = (a + b - c) - a = b - c
  1090.             "movq %%mm2, %%mm4           nt"
  1091.             // pbv = p - b = (a + b - c) - b = a - c
  1092.             "movq %%mm1, %%mm5           nt"
  1093.             "psubw %%mm3, %%mm4          nt"
  1094.             "pxor %%mm7, %%mm7           nt"
  1095.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  1096.             "movq %%mm4, %%mm6           nt"
  1097.             "psubw %%mm3, %%mm5          nt"
  1098.             // pa = abs(p-a) = abs(pav)
  1099.             // pb = abs(p-b) = abs(pbv)
  1100.             // pc = abs(p-c) = abs(pcv)
  1101.             "pcmpgtw %%mm4, %%mm0        nt" // create mask pav bytes < 0
  1102.             "paddw %%mm5, %%mm6          nt"
  1103.             "pand %%mm4, %%mm0           nt" // only pav bytes < 0 in mm7
  1104.             "pcmpgtw %%mm5, %%mm7        nt" // create mask pbv bytes < 0
  1105.             "psubw %%mm0, %%mm4          nt"
  1106.             "pand %%mm5, %%mm7           nt" // only pbv bytes < 0 in mm0
  1107.             "psubw %%mm0, %%mm4          nt"
  1108.             "psubw %%mm7, %%mm5          nt"
  1109.             "pxor %%mm0, %%mm0           nt"
  1110.             "pcmpgtw %%mm6, %%mm0        nt" // create mask pcv bytes < 0
  1111.             "pand %%mm6, %%mm0           nt" // only pav bytes < 0 in mm7
  1112.             "psubw %%mm7, %%mm5          nt"
  1113.             "psubw %%mm0, %%mm6          nt"
  1114.             //  test pa <= pb
  1115.             "movq %%mm4, %%mm7           nt"
  1116.             "psubw %%mm0, %%mm6          nt"
  1117.             "pcmpgtw %%mm5, %%mm7        nt" // pa > pb?
  1118.             "movq %%mm7, %%mm0           nt"
  1119.             // use mm7 mask to merge pa & pb
  1120.             "pand %%mm7, %%mm5           nt"
  1121.             // use mm0 mask copy to merge a & b
  1122.             "pand %%mm0, %%mm2           nt"
  1123.             "pandn %%mm4, %%mm7          nt"
  1124.             "pandn %%mm1, %%mm0          nt"
  1125.             "paddw %%mm5, %%mm7          nt"
  1126.             "paddw %%mm2, %%mm0          nt"
  1127.             //  test  ((pa <= pb)? pa:pb) <= pc
  1128.             "pcmpgtw %%mm6, %%mm7        nt" // pab > pc?
  1129.             "pxor %%mm1, %%mm1           nt"
  1130.             "pand %%mm7, %%mm3           nt"
  1131.             "pandn %%mm0, %%mm7          nt"
  1132.             "pxor %%mm1, %%mm1           nt"
  1133.             "paddw %%mm3, %%mm7          nt"
  1134.             "pxor %%mm0, %%mm0           nt"
  1135.             // step ecx to next set of 8 bytes and repeat loop til done
  1136.             "addl $8, %%ecx              nt"
  1137.             "packuswb %%mm7, %%mm1       nt"
  1138.             "paddb -8(%%edi,%%ecx,), %%mm1 nt" // add Paeth predictor with Raw(x)
  1139.             "cmpl _MMXLength, %%ecx      nt"
  1140.             "movq %%mm1, -8(%%edi,%%ecx,) nt" // write back updated value
  1141.                                 // mm1 will be used as Raw(x-bpp) next loop
  1142.             "jb paeth_6lp                nt"
  1143.             : "=S" (dummy_value_S),             // output regs (dummy)
  1144.               "=D" (dummy_value_D)
  1145.             : "0" (prev_row),  // esi           // input regs
  1146.               "1" (row)        // edi
  1147.             : "%ecx"                            // clobber list
  1148. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  1149.             , "%mm0", "%mm1", "%mm2", "%mm3"
  1150.             , "%mm4", "%mm5", "%mm6", "%mm7"
  1151. #endif
  1152.          );
  1153.       }
  1154.       break;  // end 6 bpp
  1155.       case 4:
  1156.       {
  1157.          _ActiveMask.use  = 0x00000000ffffffffLL;
  1158.          __asm__ __volatile__ (
  1159.             "movl _dif, %%ecx            nt"
  1160. // preload  "movl row, %%edi             nt"
  1161. // preload  "movl prev_row, %%esi        nt"
  1162.             "pxor %%mm0, %%mm0           nt"
  1163.             // prime the pump:  load the first Raw(x-bpp) data set
  1164.             "movq -8(%%edi,%%ecx,), %%mm1 nt" // only time should need to read
  1165.                                      //  a=Raw(x-bpp) bytes
  1166.          "paeth_4lp:                     nt"
  1167.             // do first set of 4 bytes
  1168.             "movq -8(%%esi,%%ecx,), %%mm3 nt" // read c=Prior(x-bpp) bytes
  1169.             "punpckhbw %%mm0, %%mm1      nt" // unpack Low bytes of a
  1170.             "movq (%%esi,%%ecx,), %%mm2  nt" // load b=Prior(x)
  1171.             "punpcklbw %%mm0, %%mm2      nt" // unpack High bytes of b
  1172.             // pav = p - a = (a + b - c) - a = b - c
  1173.             "movq %%mm2, %%mm4           nt"
  1174.             "punpckhbw %%mm0, %%mm3      nt" // unpack High bytes of c
  1175.             // pbv = p - b = (a + b - c) - b = a - c
  1176.             "movq %%mm1, %%mm5           nt"
  1177.             "psubw %%mm3, %%mm4          nt"
  1178.             "pxor %%mm7, %%mm7           nt"
  1179.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  1180.             "movq %%mm4, %%mm6           nt"
  1181.             "psubw %%mm3, %%mm5          nt"
  1182.             // pa = abs(p-a) = abs(pav)
  1183.             // pb = abs(p-b) = abs(pbv)
  1184.             // pc = abs(p-c) = abs(pcv)
  1185.             "pcmpgtw %%mm4, %%mm0        nt" // create mask pav bytes < 0
  1186.             "paddw %%mm5, %%mm6          nt"
  1187.             "pand %%mm4, %%mm0           nt" // only pav bytes < 0 in mm7
  1188.             "pcmpgtw %%mm5, %%mm7        nt" // create mask pbv bytes < 0
  1189.             "psubw %%mm0, %%mm4          nt"
  1190.             "pand %%mm5, %%mm7           nt" // only pbv bytes < 0 in mm0
  1191.             "psubw %%mm0, %%mm4          nt"
  1192.             "psubw %%mm7, %%mm5          nt"
  1193.             "pxor %%mm0, %%mm0           nt"
  1194.             "pcmpgtw %%mm6, %%mm0        nt" // create mask pcv bytes < 0
  1195.             "pand %%mm6, %%mm0           nt" // only pav bytes < 0 in mm7
  1196.             "psubw %%mm7, %%mm5          nt"
  1197.             "psubw %%mm0, %%mm6          nt"
  1198.             //  test pa <= pb
  1199.             "movq %%mm4, %%mm7           nt"
  1200.             "psubw %%mm0, %%mm6          nt"
  1201.             "pcmpgtw %%mm5, %%mm7        nt" // pa > pb?
  1202.             "movq %%mm7, %%mm0           nt"
  1203.             // use mm7 mask to merge pa & pb
  1204.             "pand %%mm7, %%mm5           nt"
  1205.             // use mm0 mask copy to merge a & b
  1206.             "pand %%mm0, %%mm2           nt"
  1207.             "pandn %%mm4, %%mm7          nt"
  1208.             "pandn %%mm1, %%mm0          nt"
  1209.             "paddw %%mm5, %%mm7          nt"
  1210.             "paddw %%mm2, %%mm0          nt"
  1211.             //  test  ((pa <= pb)? pa:pb) <= pc
  1212.             "pcmpgtw %%mm6, %%mm7        nt" // pab > pc?
  1213.             "pxor %%mm1, %%mm1           nt"
  1214.             "pand %%mm7, %%mm3           nt"
  1215.             "pandn %%mm0, %%mm7          nt"
  1216.             "paddw %%mm3, %%mm7          nt"
  1217.             "pxor %%mm0, %%mm0           nt"
  1218.             "packuswb %%mm1, %%mm7       nt"
  1219.             "movq (%%esi,%%ecx,), %%mm3  nt" // load c=Prior(x-bpp)
  1220.             "pand _ActiveMask, %%mm7     nt"
  1221.             "movq %%mm3, %%mm2           nt" // load b=Prior(x) step 1
  1222.             "paddb (%%edi,%%ecx,), %%mm7 nt" // add Paeth predictor with Raw(x)
  1223.             "punpcklbw %%mm0, %%mm3      nt" // unpack High bytes of c
  1224.             "movq %%mm7, (%%edi,%%ecx,)  nt" // write back updated value
  1225.             "movq %%mm7, %%mm1           nt" // now mm1 will be used as Raw(x-bpp)
  1226.             // do second set of 4 bytes
  1227.             "punpckhbw %%mm0, %%mm2      nt" // unpack Low bytes of b
  1228.             "punpcklbw %%mm0, %%mm1      nt" // unpack Low bytes of a
  1229.             // pav = p - a = (a + b - c) - a = b - c
  1230.             "movq %%mm2, %%mm4           nt"
  1231.             // pbv = p - b = (a + b - c) - b = a - c
  1232.             "movq %%mm1, %%mm5           nt"
  1233.             "psubw %%mm3, %%mm4          nt"
  1234.             "pxor %%mm7, %%mm7           nt"
  1235.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  1236.             "movq %%mm4, %%mm6           nt"
  1237.             "psubw %%mm3, %%mm5          nt"
  1238.             // pa = abs(p-a) = abs(pav)
  1239.             // pb = abs(p-b) = abs(pbv)
  1240.             // pc = abs(p-c) = abs(pcv)
  1241.             "pcmpgtw %%mm4, %%mm0        nt" // create mask pav bytes < 0
  1242.             "paddw %%mm5, %%mm6          nt"
  1243.             "pand %%mm4, %%mm0           nt" // only pav bytes < 0 in mm7
  1244.             "pcmpgtw %%mm5, %%mm7        nt" // create mask pbv bytes < 0
  1245.             "psubw %%mm0, %%mm4          nt"
  1246.             "pand %%mm5, %%mm7           nt" // only pbv bytes < 0 in mm0
  1247.             "psubw %%mm0, %%mm4          nt"
  1248.             "psubw %%mm7, %%mm5          nt"
  1249.             "pxor %%mm0, %%mm0           nt"
  1250.             "pcmpgtw %%mm6, %%mm0        nt" // create mask pcv bytes < 0
  1251.             "pand %%mm6, %%mm0           nt" // only pav bytes < 0 in mm7
  1252.             "psubw %%mm7, %%mm5          nt"
  1253.             "psubw %%mm0, %%mm6          nt"
  1254.             //  test pa <= pb
  1255.             "movq %%mm4, %%mm7           nt"
  1256.             "psubw %%mm0, %%mm6          nt"
  1257.             "pcmpgtw %%mm5, %%mm7        nt" // pa > pb?
  1258.             "movq %%mm7, %%mm0           nt"
  1259.             // use mm7 mask to merge pa & pb
  1260.             "pand %%mm7, %%mm5           nt"
  1261.             // use mm0 mask copy to merge a & b
  1262.             "pand %%mm0, %%mm2           nt"
  1263.             "pandn %%mm4, %%mm7          nt"
  1264.             "pandn %%mm1, %%mm0          nt"
  1265.             "paddw %%mm5, %%mm7          nt"
  1266.             "paddw %%mm2, %%mm0          nt"
  1267.             //  test  ((pa <= pb)? pa:pb) <= pc
  1268.             "pcmpgtw %%mm6, %%mm7        nt" // pab > pc?
  1269.             "pxor %%mm1, %%mm1           nt"
  1270.             "pand %%mm7, %%mm3           nt"
  1271.             "pandn %%mm0, %%mm7          nt"
  1272.             "pxor %%mm1, %%mm1           nt"
  1273.             "paddw %%mm3, %%mm7          nt"
  1274.             "pxor %%mm0, %%mm0           nt"
  1275.             // step ecx to next set of 8 bytes and repeat loop til done
  1276.             "addl $8, %%ecx              nt"
  1277.             "packuswb %%mm7, %%mm1       nt"
  1278.             "paddb -8(%%edi,%%ecx,), %%mm1 nt" // add predictor with Raw(x)
  1279.             "cmpl _MMXLength, %%ecx      nt"
  1280.             "movq %%mm1, -8(%%edi,%%ecx,) nt" // write back updated value
  1281.                                 // mm1 will be used as Raw(x-bpp) next loop
  1282.             "jb paeth_4lp                nt"
  1283.             : "=S" (dummy_value_S),             // output regs (dummy)
  1284.               "=D" (dummy_value_D)
  1285.             : "0" (prev_row),  // esi           // input regs
  1286.               "1" (row)        // edi
  1287.             : "%ecx"                            // clobber list
  1288. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  1289.             , "%mm0", "%mm1", "%mm2", "%mm3"
  1290.             , "%mm4", "%mm5", "%mm6", "%mm7"
  1291. #endif
  1292.          );
  1293.       }
  1294.       break;  // end 4 bpp
  1295.       case 8:                          // bpp == 8
  1296.       {
  1297.          _ActiveMask.use  = 0x00000000ffffffffLL;
  1298.          __asm__ __volatile__ (
  1299.             "movl _dif, %%ecx            nt"
  1300. // preload  "movl row, %%edi             nt"
  1301. // preload  "movl prev_row, %%esi        nt"
  1302.             "pxor %%mm0, %%mm0           nt"
  1303.             // prime the pump:  load the first Raw(x-bpp) data set
  1304.             "movq -8(%%edi,%%ecx,), %%mm1 nt" // only time should need to read
  1305.                                        //  a=Raw(x-bpp) bytes
  1306.          "paeth_8lp:                     nt"
  1307.             // do first set of 4 bytes
  1308.             "movq -8(%%esi,%%ecx,), %%mm3 nt" // read c=Prior(x-bpp) bytes
  1309.             "punpcklbw %%mm0, %%mm1      nt" // unpack Low bytes of a
  1310.             "movq (%%esi,%%ecx,), %%mm2  nt" // load b=Prior(x)
  1311.             "punpcklbw %%mm0, %%mm2      nt" // unpack Low bytes of b
  1312.             // pav = p - a = (a + b - c) - a = b - c
  1313.             "movq %%mm2, %%mm4           nt"
  1314.             "punpcklbw %%mm0, %%mm3      nt" // unpack Low bytes of c
  1315.             // pbv = p - b = (a + b - c) - b = a - c
  1316.             "movq %%mm1, %%mm5           nt"
  1317.             "psubw %%mm3, %%mm4          nt"
  1318.             "pxor %%mm7, %%mm7           nt"
  1319.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  1320.             "movq %%mm4, %%mm6           nt"
  1321.             "psubw %%mm3, %%mm5          nt"
  1322.             // pa = abs(p-a) = abs(pav)
  1323.             // pb = abs(p-b) = abs(pbv)
  1324.             // pc = abs(p-c) = abs(pcv)
  1325.             "pcmpgtw %%mm4, %%mm0        nt" // create mask pav bytes < 0
  1326.             "paddw %%mm5, %%mm6          nt"
  1327.             "pand %%mm4, %%mm0           nt" // only pav bytes < 0 in mm7
  1328.             "pcmpgtw %%mm5, %%mm7        nt" // create mask pbv bytes < 0
  1329.             "psubw %%mm0, %%mm4          nt"
  1330.             "pand %%mm5, %%mm7           nt" // only pbv bytes < 0 in mm0
  1331.             "psubw %%mm0, %%mm4          nt"
  1332.             "psubw %%mm7, %%mm5          nt"
  1333.             "pxor %%mm0, %%mm0           nt"
  1334.             "pcmpgtw %%mm6, %%mm0        nt" // create mask pcv bytes < 0
  1335.             "pand %%mm6, %%mm0           nt" // only pav bytes < 0 in mm7
  1336.             "psubw %%mm7, %%mm5          nt"
  1337.             "psubw %%mm0, %%mm6          nt"
  1338.             //  test pa <= pb
  1339.             "movq %%mm4, %%mm7           nt"
  1340.             "psubw %%mm0, %%mm6          nt"
  1341.             "pcmpgtw %%mm5, %%mm7        nt" // pa > pb?
  1342.             "movq %%mm7, %%mm0           nt"
  1343.             // use mm7 mask to merge pa & pb
  1344.             "pand %%mm7, %%mm5           nt"
  1345.             // use mm0 mask copy to merge a & b
  1346.             "pand %%mm0, %%mm2           nt"
  1347.             "pandn %%mm4, %%mm7          nt"
  1348.             "pandn %%mm1, %%mm0          nt"
  1349.             "paddw %%mm5, %%mm7          nt"
  1350.             "paddw %%mm2, %%mm0          nt"
  1351.             //  test  ((pa <= pb)? pa:pb) <= pc
  1352.             "pcmpgtw %%mm6, %%mm7        nt" // pab > pc?
  1353.             "pxor %%mm1, %%mm1           nt"
  1354.             "pand %%mm7, %%mm3           nt"
  1355.             "pandn %%mm0, %%mm7          nt"
  1356.             "paddw %%mm3, %%mm7          nt"
  1357.             "pxor %%mm0, %%mm0           nt"
  1358.             "packuswb %%mm1, %%mm7       nt"
  1359.             "movq -8(%%esi,%%ecx,), %%mm3 nt" // read c=Prior(x-bpp) bytes
  1360.             "pand _ActiveMask, %%mm7     nt"
  1361.             "movq (%%esi,%%ecx,), %%mm2  nt" // load b=Prior(x)
  1362.             "paddb (%%edi,%%ecx,), %%mm7 nt" // add Paeth predictor with Raw(x)
  1363.             "punpckhbw %%mm0, %%mm3      nt" // unpack High bytes of c
  1364.             "movq %%mm7, (%%edi,%%ecx,)  nt" // write back updated value
  1365.             "movq -8(%%edi,%%ecx,), %%mm1 nt" // read a=Raw(x-bpp) bytes
  1366.             // do second set of 4 bytes
  1367.             "punpckhbw %%mm0, %%mm2      nt" // unpack High bytes of b
  1368.             "punpckhbw %%mm0, %%mm1      nt" // unpack High bytes of a
  1369.             // pav = p - a = (a + b - c) - a = b - c
  1370.             "movq %%mm2, %%mm4           nt"
  1371.             // pbv = p - b = (a + b - c) - b = a - c
  1372.             "movq %%mm1, %%mm5           nt"
  1373.             "psubw %%mm3, %%mm4          nt"
  1374.             "pxor %%mm7, %%mm7           nt"
  1375.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  1376.             "movq %%mm4, %%mm6           nt"
  1377.             "psubw %%mm3, %%mm5          nt"
  1378.             // pa = abs(p-a) = abs(pav)
  1379.             // pb = abs(p-b) = abs(pbv)
  1380.             // pc = abs(p-c) = abs(pcv)
  1381.             "pcmpgtw %%mm4, %%mm0        nt" // create mask pav bytes < 0
  1382.             "paddw %%mm5, %%mm6          nt"
  1383.             "pand %%mm4, %%mm0           nt" // only pav bytes < 0 in mm7
  1384.             "pcmpgtw %%mm5, %%mm7        nt" // create mask pbv bytes < 0
  1385.             "psubw %%mm0, %%mm4          nt"
  1386.             "pand %%mm5, %%mm7           nt" // only pbv bytes < 0 in mm0
  1387.             "psubw %%mm0, %%mm4          nt"
  1388.             "psubw %%mm7, %%mm5          nt"
  1389.             "pxor %%mm0, %%mm0           nt"
  1390.             "pcmpgtw %%mm6, %%mm0        nt" // create mask pcv bytes < 0
  1391.             "pand %%mm6, %%mm0           nt" // only pav bytes < 0 in mm7
  1392.             "psubw %%mm7, %%mm5          nt"
  1393.             "psubw %%mm0, %%mm6          nt"
  1394.             //  test pa <= pb
  1395.             "movq %%mm4, %%mm7           nt"
  1396.             "psubw %%mm0, %%mm6          nt"
  1397.             "pcmpgtw %%mm5, %%mm7        nt" // pa > pb?
  1398.             "movq %%mm7, %%mm0           nt"
  1399.             // use mm7 mask to merge pa & pb
  1400.             "pand %%mm7, %%mm5           nt"
  1401.             // use mm0 mask copy to merge a & b
  1402.             "pand %%mm0, %%mm2           nt"
  1403.             "pandn %%mm4, %%mm7          nt"
  1404.             "pandn %%mm1, %%mm0          nt"
  1405.             "paddw %%mm5, %%mm7          nt"
  1406.             "paddw %%mm2, %%mm0          nt"
  1407.             //  test  ((pa <= pb)? pa:pb) <= pc
  1408.             "pcmpgtw %%mm6, %%mm7        nt" // pab > pc?
  1409.             "pxor %%mm1, %%mm1           nt"
  1410.             "pand %%mm7, %%mm3           nt"
  1411.             "pandn %%mm0, %%mm7          nt"
  1412.             "pxor %%mm1, %%mm1           nt"
  1413.             "paddw %%mm3, %%mm7          nt"
  1414.             "pxor %%mm0, %%mm0           nt"
  1415.             // step ecx to next set of 8 bytes and repeat loop til done
  1416.             "addl $8, %%ecx              nt"
  1417.             "packuswb %%mm7, %%mm1       nt"
  1418.             "paddb -8(%%edi,%%ecx,), %%mm1 nt" // add Paeth predictor with Raw(x)
  1419.             "cmpl _MMXLength, %%ecx      nt"
  1420.             "movq %%mm1, -8(%%edi,%%ecx,) nt" // write back updated value
  1421.                             // mm1 will be used as Raw(x-bpp) next loop
  1422.             "jb paeth_8lp                nt"
  1423.             : "=S" (dummy_value_S),             // output regs (dummy)
  1424.               "=D" (dummy_value_D)
  1425.             : "0" (prev_row),  // esi           // input regs
  1426.               "1" (row)        // edi
  1427.             : "%ecx"                            // clobber list
  1428. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  1429.             , "%mm0", "%mm1", "%mm2", "%mm3"
  1430.             , "%mm4", "%mm5", "%mm6", "%mm7"
  1431. #endif
  1432.          );
  1433.       }
  1434.       break;  // end 8 bpp
  1435.       case 1:                // bpp = 1
  1436.       case 2:                // bpp = 2
  1437.       default:               // bpp > 8
  1438.       {
  1439.          __asm__ __volatile__ (
  1440. #ifdef __PIC__
  1441.             "pushl %%ebx                 nt" // save Global Offset Table index
  1442. #endif
  1443.             "movl _dif, %%ebx            nt"
  1444.             "cmpl _FullLength, %%ebx     nt"
  1445.             "jnb paeth_dend              nt"
  1446. // preload  "movl row, %%edi             nt"
  1447. // preload  "movl prev_row, %%esi        nt"
  1448.             // do Paeth decode for remaining bytes
  1449.             "movl %%ebx, %%edx           nt"
  1450. // preload  "subl bpp, %%edx             nt" // (bpp is preloaded into ecx)
  1451.             "subl %%ecx, %%edx           nt" // edx = ebx - bpp
  1452.             "xorl %%ecx, %%ecx           nt" // zero ecx before using cl & cx
  1453.          "paeth_dlp:                     nt"
  1454.             "xorl %%eax, %%eax           nt"
  1455.             // pav = p - a = (a + b - c) - a = b - c
  1456.             "movb (%%esi,%%ebx,), %%al   nt" // load Prior(x) into al
  1457.             "movb (%%esi,%%edx,), %%cl   nt" // load Prior(x-bpp) into cl
  1458.             "subl %%ecx, %%eax           nt" // subtract Prior(x-bpp)
  1459.             "movl %%eax, _patemp         nt" // Save pav for later use
  1460.             "xorl %%eax, %%eax           nt"
  1461.             // pbv = p - b = (a + b - c) - b = a - c
  1462.             "movb (%%edi,%%edx,), %%al   nt" // load Raw(x-bpp) into al
  1463.             "subl %%ecx, %%eax           nt" // subtract Prior(x-bpp)
  1464.             "movl %%eax, %%ecx           nt"
  1465.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  1466.             "addl _patemp, %%eax         nt" // pcv = pav + pbv
  1467.             // pc = abs(pcv)
  1468.             "testl $0x80000000, %%eax    nt"
  1469.             "jz paeth_dpca               nt"
  1470.             "negl %%eax                  nt" // reverse sign of neg values
  1471.          "paeth_dpca:                    nt"
  1472.             "movl %%eax, _pctemp         nt" // save pc for later use
  1473.             // pb = abs(pbv)
  1474.             "testl $0x80000000, %%ecx    nt"
  1475.             "jz paeth_dpba               nt"
  1476.             "negl %%ecx                  nt" // reverse sign of neg values
  1477.          "paeth_dpba:                    nt"
  1478.             "movl %%ecx, _pbtemp         nt" // save pb for later use
  1479.             // pa = abs(pav)
  1480.             "movl _patemp, %%eax         nt"
  1481.             "testl $0x80000000, %%eax    nt"
  1482.             "jz paeth_dpaa               nt"
  1483.             "negl %%eax                  nt" // reverse sign of neg values
  1484.          "paeth_dpaa:                    nt"
  1485.             "movl %%eax, _patemp         nt" // save pa for later use
  1486.             // test if pa <= pb
  1487.             "cmpl %%ecx, %%eax           nt"
  1488.             "jna paeth_dabb              nt"
  1489.             // pa > pb; now test if pb <= pc
  1490.             "cmpl _pctemp, %%ecx         nt"
  1491.             "jna paeth_dbbc              nt"
  1492.             // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
  1493.             "movb (%%esi,%%edx,), %%cl   nt" // load Prior(x-bpp) into cl
  1494.             "jmp paeth_dpaeth            nt"
  1495.          "paeth_dbbc:                    nt"
  1496.             // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
  1497.             "movb (%%esi,%%ebx,), %%cl   nt" // load Prior(x) into cl
  1498.             "jmp paeth_dpaeth            nt"
  1499.          "paeth_dabb:                    nt"
  1500.             // pa <= pb; now test if pa <= pc
  1501.             "cmpl _pctemp, %%eax         nt"
  1502.             "jna paeth_dabc              nt"
  1503.             // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
  1504.             "movb (%%esi,%%edx,), %%cl   nt" // load Prior(x-bpp) into cl
  1505.             "jmp paeth_dpaeth            nt"
  1506.          "paeth_dabc:                    nt"
  1507.             // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
  1508.             "movb (%%edi,%%edx,), %%cl   nt" // load Raw(x-bpp) into cl
  1509.          "paeth_dpaeth:                  nt"
  1510.             "incl %%ebx                  nt"
  1511.             "incl %%edx                  nt"
  1512.             // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
  1513.             "addb %%cl, -1(%%edi,%%ebx,) nt"
  1514.             "cmpl _FullLength, %%ebx     nt"
  1515.             "jb paeth_dlp                nt"
  1516.          "paeth_dend:                    nt"
  1517. #ifdef __PIC__
  1518.             "popl %%ebx                  nt" // index to Global Offset Table
  1519. #endif
  1520.             : "=c" (dummy_value_c),            // output regs (dummy)
  1521.               "=S" (dummy_value_S),
  1522.               "=D" (dummy_value_D)
  1523.             : "0" (bpp),       // ecx          // input regs
  1524.               "1" (prev_row),  // esi
  1525.               "2" (row)        // edi
  1526.             : "%eax", "%edx"                   // clobber list
  1527. #ifndef __PIC__
  1528.             , "%ebx"
  1529. #endif
  1530.          );
  1531.       }
  1532.       return;                   // No need to go further with this one
  1533.    } // end switch (bpp)
  1534.    __asm__ __volatile__ (
  1535.       // MMX acceleration complete; now do clean-up
  1536.       // check if any remaining bytes left to decode
  1537. #ifdef __PIC__
  1538.       "pushl %%ebx                 nt" // save index to Global Offset Table
  1539. #endif
  1540.       "movl _MMXLength, %%ebx      nt"
  1541.       "cmpl _FullLength, %%ebx     nt"
  1542.       "jnb paeth_end               nt"
  1543. //pre "movl row, %%edi             nt"
  1544. //pre "movl prev_row, %%esi        nt"
  1545.       // do Paeth decode for remaining bytes
  1546.       "movl %%ebx, %%edx           nt"
  1547. //pre "subl bpp, %%edx             nt" // (bpp is preloaded into ecx)
  1548.       "subl %%ecx, %%edx           nt" // edx = ebx - bpp
  1549.       "xorl %%ecx, %%ecx           nt" // zero ecx before using cl & cx below
  1550.    "paeth_lp2:                     nt"
  1551.       "xorl %%eax, %%eax           nt"
  1552.       // pav = p - a = (a + b - c) - a = b - c
  1553.       "movb (%%esi,%%ebx,), %%al   nt" // load Prior(x) into al
  1554.       "movb (%%esi,%%edx,), %%cl   nt" // load Prior(x-bpp) into cl
  1555.       "subl %%ecx, %%eax           nt" // subtract Prior(x-bpp)
  1556.       "movl %%eax, _patemp         nt" // Save pav for later use
  1557.       "xorl %%eax, %%eax           nt"
  1558.       // pbv = p - b = (a + b - c) - b = a - c
  1559.       "movb (%%edi,%%edx,), %%al   nt" // load Raw(x-bpp) into al
  1560.       "subl %%ecx, %%eax           nt" // subtract Prior(x-bpp)
  1561.       "movl %%eax, %%ecx           nt"
  1562.       // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  1563.       "addl _patemp, %%eax         nt" // pcv = pav + pbv
  1564.       // pc = abs(pcv)
  1565.       "testl $0x80000000, %%eax    nt"
  1566.       "jz paeth_pca2               nt"
  1567.       "negl %%eax                  nt" // reverse sign of neg values
  1568.    "paeth_pca2:                    nt"
  1569.       "movl %%eax, _pctemp         nt" // save pc for later use
  1570.       // pb = abs(pbv)
  1571.       "testl $0x80000000, %%ecx    nt"
  1572.       "jz paeth_pba2               nt"
  1573.       "negl %%ecx                  nt" // reverse sign of neg values
  1574.    "paeth_pba2:                    nt"
  1575.       "movl %%ecx, _pbtemp         nt" // save pb for later use
  1576.       // pa = abs(pav)
  1577.       "movl _patemp, %%eax         nt"
  1578.       "testl $0x80000000, %%eax    nt"
  1579.       "jz paeth_paa2               nt"
  1580.       "negl %%eax                  nt" // reverse sign of neg values
  1581.    "paeth_paa2:                    nt"
  1582.       "movl %%eax, _patemp         nt" // save pa for later use
  1583.       // test if pa <= pb
  1584.       "cmpl %%ecx, %%eax           nt"
  1585.       "jna paeth_abb2              nt"
  1586.       // pa > pb; now test if pb <= pc
  1587.       "cmpl _pctemp, %%ecx         nt"
  1588.       "jna paeth_bbc2              nt"
  1589.       // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
  1590.       "movb (%%esi,%%edx,), %%cl   nt" // load Prior(x-bpp) into cl
  1591.       "jmp paeth_paeth2            nt"
  1592.    "paeth_bbc2:                    nt"
  1593.       // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
  1594.       "movb (%%esi,%%ebx,), %%cl   nt" // load Prior(x) into cl
  1595.       "jmp paeth_paeth2            nt"
  1596.    "paeth_abb2:                    nt"
  1597.       // pa <= pb; now test if pa <= pc
  1598.       "cmpl _pctemp, %%eax         nt"
  1599.       "jna paeth_abc2              nt"
  1600.       // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
  1601.       "movb (%%esi,%%edx,), %%cl   nt" // load Prior(x-bpp) into cl
  1602.       "jmp paeth_paeth2            nt"
  1603.    "paeth_abc2:                    nt"
  1604.       // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
  1605.       "movb (%%edi,%%edx,), %%cl   nt" // load Raw(x-bpp) into cl
  1606.    "paeth_paeth2:                  nt"
  1607.       "incl %%ebx                  nt"
  1608.       "incl %%edx                  nt"
  1609.       // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
  1610.       "addb %%cl, -1(%%edi,%%ebx,) nt"
  1611.       "cmpl _FullLength, %%ebx     nt"
  1612.       "jb paeth_lp2                nt"
  1613.    "paeth_end:                     nt"
  1614.       "EMMS                        nt" // end MMX; prep for poss. FP instrs.
  1615. #ifdef __PIC__
  1616.       "popl %%ebx                  nt" // restore index to Global Offset Table
  1617. #endif
  1618.       : "=c" (dummy_value_c),            // output regs (dummy)
  1619.         "=S" (dummy_value_S),
  1620.         "=D" (dummy_value_D)
  1621.       : "0" (bpp),       // ecx          // input regs
  1622.         "1" (prev_row),  // esi
  1623.         "2" (row)        // edi
  1624.       : "%eax", "%edx"                   // clobber list (no input regs!)
  1625. #ifndef __PIC__
  1626.       , "%ebx"
  1627. #endif
  1628.    );
  1629. } /* end png_read_filter_row_mmx_paeth() */
  1630. #endif
  1631. #ifdef PNG_THREAD_UNSAFE_OK
  1632. //===========================================================================//
  1633. //                                                                           //
  1634. //           P N G _ R E A D _ F I L T E R _ R O W _ M M X _ S U B           //
  1635. //                                                                           //
  1636. //===========================================================================//
  1637. // Optimized code for PNG Sub filter decoder
  1638. static void /* PRIVATE */
  1639. png_read_filter_row_mmx_sub(png_row_infop row_info, png_bytep row)
  1640. {
  1641.    int bpp;
  1642.    int dummy_value_a;
  1643.    int dummy_value_D;
  1644.    bpp = (row_info->pixel_depth + 7) >> 3;   // calc number of bytes per pixel
  1645.    _FullLength = row_info->rowbytes - bpp;   // number of bytes to filter
  1646.    __asm__ __volatile__ (
  1647. //pre "movl row, %%edi             nt"
  1648.       "movl %%edi, %%esi           nt" // lp = row
  1649. //pre "movl bpp, %%eax             nt"
  1650.       "addl %%eax, %%edi           nt" // rp = row + bpp
  1651. //irr "xorl %%eax, %%eax           nt"
  1652.       // get # of bytes to alignment
  1653.       "movl %%edi, _dif            nt" // take start of row
  1654.       "addl $0xf, _dif             nt" // add 7 + 8 to incr past
  1655.                                          //  alignment boundary
  1656.       "xorl %%ecx, %%ecx           nt"
  1657.       "andl $0xfffffff8, _dif      nt" // mask to alignment boundary
  1658.       "subl %%edi, _dif            nt" // subtract from start ==> value
  1659.       "jz sub_go                   nt" //  ecx at alignment
  1660.    "sub_lp1:                       nt" // fix alignment
  1661.       "movb (%%esi,%%ecx,), %%al   nt"
  1662.       "addb %%al, (%%edi,%%ecx,)   nt"
  1663.       "incl %%ecx                  nt"
  1664.       "cmpl _dif, %%ecx            nt"
  1665.       "jb sub_lp1                  nt"
  1666.    "sub_go:                        nt"
  1667.       "movl _FullLength, %%eax     nt"
  1668.       "movl %%eax, %%edx           nt"
  1669.       "subl %%ecx, %%edx           nt" // subtract alignment fix
  1670.       "andl $0x00000007, %%edx     nt" // calc bytes over mult of 8
  1671.       "subl %%edx, %%eax           nt" // drop over bytes from length
  1672.       "movl %%eax, _MMXLength      nt"
  1673.       : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  1674.         "=D" (dummy_value_D)    // 1
  1675.       : "0" (bpp),              // eax    // input regs
  1676.         "1" (row)               // edi
  1677.       : "%esi", "%ecx", "%edx"            // clobber list
  1678. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  1679.       , "%mm0", "%mm1", "%mm2", "%mm3"
  1680.       , "%mm4", "%mm5", "%mm6", "%mm7"
  1681. #endif
  1682.    );
  1683.    // now do the math for the rest of the row
  1684.    switch (bpp)
  1685.    {
  1686.       case 3:
  1687.       {
  1688.          _ActiveMask.use  = 0x0000ffffff000000LL;
  1689.          _ShiftBpp.use = 24;       // == 3 * 8
  1690.          _ShiftRem.use  = 40;      // == 64 - 24
  1691.          __asm__ __volatile__ (
  1692. // preload  "movl row, %%edi              nt"
  1693.             "movq _ActiveMask, %%mm7       nt" // load _ActiveMask for 2nd
  1694.                                                 //  active byte group
  1695.             "movl %%edi, %%esi            nt" // lp = row
  1696. // preload  "movl bpp, %%eax              nt"
  1697.             "addl %%eax, %%edi            nt" // rp = row + bpp
  1698.             "movq %%mm7, %%mm6            nt"
  1699.             "movl _dif, %%edx             nt"
  1700.             "psllq _ShiftBpp, %%mm6       nt" // move mask in mm6 to cover
  1701.                                                 //  3rd active byte group
  1702.             // prime the pump:  load the first Raw(x-bpp) data set
  1703.             "movq -8(%%edi,%%edx,), %%mm1 nt"
  1704.          "sub_3lp:                        nt" // shift data for adding first
  1705.             "psrlq _ShiftRem, %%mm1       nt" //  bpp bytes (no need for mask;
  1706.                                                 //  shift clears inactive bytes)
  1707.             // add 1st active group
  1708.             "movq (%%edi,%%edx,), %%mm0   nt"
  1709.             "paddb %%mm1, %%mm0           nt"
  1710.             // add 2nd active group
  1711.             "movq %%mm0, %%mm1            nt" // mov updated Raws to mm1
  1712.             "psllq _ShiftBpp, %%mm1       nt" // shift data to pos. correctly
  1713.             "pand %%mm7, %%mm1            nt" // mask to use 2nd active group
  1714.             "paddb %%mm1, %%mm0           nt"
  1715.             // add 3rd active group
  1716.             "movq %%mm0, %%mm1            nt" // mov updated Raws to mm1
  1717.             "psllq _ShiftBpp, %%mm1       nt" // shift data to pos. correctly
  1718.             "pand %%mm6, %%mm1            nt" // mask to use 3rd active group
  1719.             "addl $8, %%edx               nt"
  1720.             "paddb %%mm1, %%mm0           nt"
  1721.             "cmpl _MMXLength, %%edx       nt"
  1722.             "movq %%mm0, -8(%%edi,%%edx,) nt" // write updated Raws to array
  1723.             "movq %%mm0, %%mm1            nt" // prep 1st add at top of loop
  1724.             "jb sub_3lp                   nt"
  1725.             : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  1726.               "=D" (dummy_value_D)    // 1
  1727.             : "0" (bpp),              // eax    // input regs
  1728.               "1" (row)               // edi
  1729.             : "%edx", "%esi"                    // clobber list
  1730. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  1731.             , "%mm0", "%mm1", "%mm6", "%mm7"
  1732. #endif
  1733.          );
  1734.       }
  1735.       break;
  1736.       case 1:
  1737.       {
  1738.          __asm__ __volatile__ (
  1739.             "movl _dif, %%edx            nt"
  1740. // preload  "movl row, %%edi             nt"
  1741.             "cmpl _FullLength, %%edx     nt"
  1742.             "jnb sub_1end                nt"
  1743.             "movl %%edi, %%esi           nt" // lp = row
  1744.             "xorl %%eax, %%eax           nt"
  1745. // preload  "movl bpp, %%eax             nt"
  1746.             "addl %%eax, %%edi           nt" // rp = row + bpp
  1747.          "sub_1lp:                       nt"
  1748.             "movb (%%esi,%%edx,), %%al   nt"
  1749.             "addb %%al, (%%edi,%%edx,)   nt"
  1750.             "incl %%edx                  nt"
  1751.             "cmpl _FullLength, %%edx     nt"
  1752.             "jb sub_1lp                  nt"
  1753.          "sub_1end:                      nt"
  1754.             : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  1755.               "=D" (dummy_value_D)    // 1
  1756.             : "0" (bpp),              // eax    // input regs
  1757.               "1" (row)               // edi
  1758.             : "%edx", "%esi"                    // clobber list
  1759.          );
  1760.       }
  1761.       return;
  1762.       case 6:
  1763.       case 4:
  1764.       //case 7:   // GRR BOGUS
  1765.       //case 5:   // GRR BOGUS
  1766.       {
  1767.          _ShiftBpp.use = bpp << 3;
  1768.          _ShiftRem.use = 64 - _ShiftBpp.use;
  1769.          __asm__ __volatile__ (
  1770. // preload  "movl row, %%edi              nt"
  1771.             "movl _dif, %%edx             nt"
  1772.             "movl %%edi, %%esi            nt" // lp = row
  1773. // preload  "movl bpp, %%eax              nt"
  1774.             "addl %%eax, %%edi            nt" // rp = row + bpp
  1775.             // prime the pump:  load the first Raw(x-bpp) data set
  1776.             "movq -8(%%edi,%%edx,), %%mm1 nt"
  1777.          "sub_4lp:                        nt" // shift data for adding first
  1778.             "psrlq _ShiftRem, %%mm1       nt" //  bpp bytes (no need for mask;
  1779.                                                 //  shift clears inactive bytes)
  1780.             "movq (%%edi,%%edx,), %%mm0   nt"
  1781.             "paddb %%mm1, %%mm0           nt"
  1782.             // add 2nd active group
  1783.             "movq %%mm0, %%mm1            nt" // mov updated Raws to mm1
  1784.             "psllq _ShiftBpp, %%mm1       nt" // shift data to pos. correctly
  1785.             "addl $8, %%edx               nt"
  1786.             "paddb %%mm1, %%mm0           nt"
  1787.             "cmpl _MMXLength, %%edx       nt"
  1788.             "movq %%mm0, -8(%%edi,%%edx,) nt"
  1789.             "movq %%mm0, %%mm1            nt" // prep 1st add at top of loop
  1790.             "jb sub_4lp                   nt"
  1791.             : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  1792.               "=D" (dummy_value_D)    // 1
  1793.             : "0" (bpp),              // eax    // input regs
  1794.               "1" (row)               // edi
  1795.             : "%edx", "%esi"                    // clobber list
  1796. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  1797.             , "%mm0", "%mm1"
  1798. #endif
  1799.          );
  1800.       }
  1801.       break;
  1802.       case 2:
  1803.       {
  1804.          _ActiveMask.use = 0x00000000ffff0000LL;
  1805.          _ShiftBpp.use = 16;       // == 2 * 8
  1806.          _ShiftRem.use = 48;       // == 64 - 16
  1807.          __asm__ __volatile__ (
  1808.             "movq _ActiveMask, %%mm7      nt" // load _ActiveMask for 2nd
  1809.                                                 //  active byte group
  1810.             "movl _dif, %%edx             nt"
  1811.             "movq %%mm7, %%mm6            nt"
  1812. // preload  "movl row, %%edi              nt"
  1813.             "psllq _ShiftBpp, %%mm6       nt" // move mask in mm6 to cover
  1814.                                                 //  3rd active byte group
  1815.             "movl %%edi, %%esi            nt" // lp = row
  1816.             "movq %%mm6, %%mm5            nt"
  1817. // preload  "movl bpp, %%eax              nt"
  1818.             "addl %%eax, %%edi            nt" // rp = row + bpp
  1819.             "psllq _ShiftBpp, %%mm5       nt" // move mask in mm5 to cover
  1820.                                                 //  4th active byte group
  1821.             // prime the pump:  load the first Raw(x-bpp) data set
  1822.             "movq -8(%%edi,%%edx,), %%mm1 nt"
  1823.          "sub_2lp:                        nt" // shift data for adding first
  1824.             "psrlq _ShiftRem, %%mm1       nt" //  bpp bytes (no need for mask;
  1825.                                                 //  shift clears inactive bytes)
  1826.             // add 1st active group
  1827.             "movq (%%edi,%%edx,), %%mm0   nt"
  1828.             "paddb %%mm1, %%mm0           nt"
  1829.             // add 2nd active group
  1830.             "movq %%mm0, %%mm1            nt" // mov updated Raws to mm1
  1831.             "psllq _ShiftBpp, %%mm1       nt" // shift data to pos. correctly
  1832.             "pand %%mm7, %%mm1            nt" // mask to use 2nd active group
  1833.             "paddb %%mm1, %%mm0           nt"
  1834.             // add 3rd active group
  1835.             "movq %%mm0, %%mm1            nt" // mov updated Raws to mm1
  1836.             "psllq _ShiftBpp, %%mm1       nt" // shift data to pos. correctly
  1837.             "pand %%mm6, %%mm1            nt" // mask to use 3rd active group
  1838.             "paddb %%mm1, %%mm0           nt"
  1839.             // add 4th active group
  1840.             "movq %%mm0, %%mm1            nt" // mov updated Raws to mm1
  1841.             "psllq _ShiftBpp, %%mm1       nt" // shift data to pos. correctly
  1842.             "pand %%mm5, %%mm1            nt" // mask to use 4th active group
  1843.             "addl $8, %%edx               nt"
  1844.             "paddb %%mm1, %%mm0           nt"
  1845.             "cmpl _MMXLength, %%edx       nt"
  1846.             "movq %%mm0, -8(%%edi,%%edx,) nt" // write updated Raws to array
  1847.             "movq %%mm0, %%mm1            nt" // prep 1st add at top of loop
  1848.             "jb sub_2lp                   nt"
  1849.             : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  1850.               "=D" (dummy_value_D)    // 1
  1851.             : "0" (bpp),              // eax    // input regs
  1852.               "1" (row)               // edi
  1853.             : "%edx", "%esi"                    // clobber list
  1854. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  1855.             , "%mm0", "%mm1", "%mm5", "%mm6", "%mm7"
  1856. #endif
  1857.          );
  1858.       }
  1859.       break;
  1860.       case 8:
  1861.       {
  1862.          __asm__ __volatile__ (
  1863. // preload  "movl row, %%edi              nt"
  1864.             "movl _dif, %%edx             nt"
  1865.             "movl %%edi, %%esi            nt" // lp = row
  1866. // preload  "movl bpp, %%eax              nt"
  1867.             "addl %%eax, %%edi            nt" // rp = row + bpp
  1868.             "movl _MMXLength, %%ecx       nt"
  1869.             // prime the pump:  load the first Raw(x-bpp) data set
  1870.             "movq -8(%%edi,%%edx,), %%mm7 nt"
  1871.             "andl $0x0000003f, %%ecx      nt" // calc bytes over mult of 64
  1872.          "sub_8lp:                        nt"
  1873.             "movq (%%edi,%%edx,), %%mm0   nt" // load Sub(x) for 1st 8 bytes
  1874.             "paddb %%mm7, %%mm0           nt"
  1875.             "movq 8(%%edi,%%edx,), %%mm1  nt" // load Sub(x) for 2nd 8 bytes
  1876.             "movq %%mm0, (%%edi,%%edx,)   nt" // write Raw(x) for 1st 8 bytes
  1877.             // Now mm0 will be used as Raw(x-bpp) for the 2nd group of 8 bytes.
  1878.             // This will be repeated for each group of 8 bytes with the 8th
  1879.             // group being used as the Raw(x-bpp) for the 1st group of the
  1880.             // next loop.
  1881.             "paddb %%mm0, %%mm1           nt"
  1882.             "movq 16(%%edi,%%edx,), %%mm2 nt" // load Sub(x) for 3rd 8 bytes
  1883.             "movq %%mm1, 8(%%edi,%%edx,)  nt" // write Raw(x) for 2nd 8 bytes
  1884.             "paddb %%mm1, %%mm2           nt"
  1885.             "movq 24(%%edi,%%edx,), %%mm3 nt" // load Sub(x) for 4th 8 bytes
  1886.             "movq %%mm2, 16(%%edi,%%edx,) nt" // write Raw(x) for 3rd 8 bytes
  1887.             "paddb %%mm2, %%mm3           nt"
  1888.             "movq 32(%%edi,%%edx,), %%mm4 nt" // load Sub(x) for 5th 8 bytes
  1889.             "movq %%mm3, 24(%%edi,%%edx,) nt" // write Raw(x) for 4th 8 bytes
  1890.             "paddb %%mm3, %%mm4           nt"
  1891.             "movq 40(%%edi,%%edx,), %%mm5 nt" // load Sub(x) for 6th 8 bytes
  1892.             "movq %%mm4, 32(%%edi,%%edx,) nt" // write Raw(x) for 5th 8 bytes
  1893.             "paddb %%mm4, %%mm5           nt"
  1894.             "movq 48(%%edi,%%edx,), %%mm6 nt" // load Sub(x) for 7th 8 bytes
  1895.             "movq %%mm5, 40(%%edi,%%edx,) nt" // write Raw(x) for 6th 8 bytes
  1896.             "paddb %%mm5, %%mm6           nt"
  1897.             "movq 56(%%edi,%%edx,), %%mm7 nt" // load Sub(x) for 8th 8 bytes
  1898.             "movq %%mm6, 48(%%edi,%%edx,) nt" // write Raw(x) for 7th 8 bytes
  1899.             "addl $64, %%edx              nt"
  1900.             "paddb %%mm6, %%mm7           nt"
  1901.             "cmpl %%ecx, %%edx            nt"
  1902.             "movq %%mm7, -8(%%edi,%%edx,) nt" // write Raw(x) for 8th 8 bytes
  1903.             "jb sub_8lp                   nt"
  1904.             "cmpl _MMXLength, %%edx       nt"
  1905.             "jnb sub_8lt8                 nt"
  1906.          "sub_8lpA:                       nt"
  1907.             "movq (%%edi,%%edx,), %%mm0   nt"
  1908.             "addl $8, %%edx               nt"
  1909.             "paddb %%mm7, %%mm0           nt"
  1910.             "cmpl _MMXLength, %%edx       nt"
  1911.             "movq %%mm0, -8(%%edi,%%edx,) nt" // -8 to offset early addl edx
  1912.             "movq %%mm0, %%mm7            nt" // move calculated Raw(x) data
  1913.                                                 //  to mm1 to be new Raw(x-bpp)
  1914.                                                 //  for next loop
  1915.             "jb sub_8lpA                  nt"
  1916.          "sub_8lt8:                       nt"
  1917.             : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  1918.               "=D" (dummy_value_D)    // 1
  1919.             : "0" (bpp),              // eax    // input regs
  1920.               "1" (row)               // edi
  1921.             : "%ecx", "%edx", "%esi"            // clobber list
  1922. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  1923.             , "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7"
  1924. #endif
  1925.          );
  1926.       }
  1927.       break;
  1928.       default:                // bpp greater than 8 bytes   GRR BOGUS
  1929.       {
  1930.          __asm__ __volatile__ (
  1931.             "movl _dif, %%edx             nt"
  1932. // preload  "movl row, %%edi              nt"
  1933.             "movl %%edi, %%esi            nt" // lp = row
  1934. // preload  "movl bpp, %%eax              nt"
  1935.             "addl %%eax, %%edi            nt" // rp = row + bpp
  1936.          "sub_Alp:                        nt"
  1937.             "movq (%%edi,%%edx,), %%mm0   nt"
  1938.             "movq (%%esi,%%edx,), %%mm1   nt"
  1939.             "addl $8, %%edx               nt"
  1940.             "paddb %%mm1, %%mm0           nt"
  1941.             "cmpl _MMXLength, %%edx       nt"
  1942.             "movq %%mm0, -8(%%edi,%%edx,) nt" // mov does not affect flags;
  1943.                                                 //  -8 to offset addl edx
  1944.             "jb sub_Alp                   nt"
  1945.             : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  1946.               "=D" (dummy_value_D)    // 1
  1947.             : "0" (bpp),              // eax    // input regs
  1948.               "1" (row)               // edi
  1949.             : "%edx", "%esi"                    // clobber list
  1950. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  1951.             , "%mm0", "%mm1"
  1952. #endif
  1953.          );
  1954.       }
  1955.       break;
  1956.    } // end switch (bpp)
  1957.    __asm__ __volatile__ (
  1958.       "movl _MMXLength, %%edx       nt"
  1959. //pre "movl row, %%edi              nt"
  1960.       "cmpl _FullLength, %%edx      nt"
  1961.       "jnb sub_end                  nt"
  1962.       "movl %%edi, %%esi            nt" // lp = row
  1963. //pre "movl bpp, %%eax              nt"
  1964.       "addl %%eax, %%edi            nt" // rp = row + bpp
  1965.       "xorl %%eax, %%eax            nt"
  1966.    "sub_lp2:                        nt"
  1967.       "movb (%%esi,%%edx,), %%al    nt"
  1968.       "addb %%al, (%%edi,%%edx,)    nt"
  1969.       "incl %%edx                   nt"
  1970.       "cmpl _FullLength, %%edx      nt"
  1971.       "jb sub_lp2                   nt"
  1972.    "sub_end:                        nt"
  1973.       "EMMS                         nt" // end MMX instructions
  1974.       : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  1975.         "=D" (dummy_value_D)    // 1
  1976.       : "0" (bpp),              // eax    // input regs
  1977.         "1" (row)               // edi
  1978.       : "%edx", "%esi"                    // clobber list
  1979.    );
  1980. } // end of png_read_filter_row_mmx_sub()
  1981. #endif
  1982. //===========================================================================//
  1983. //                                                                           //
  1984. //            P N G _ R E A D _ F I L T E R _ R O W _ M M X _ U P            //
  1985. //                                                                           //
  1986. //===========================================================================//
  1987. // Optimized code for PNG Up filter decoder
  1988. static void /* PRIVATE */
  1989. png_read_filter_row_mmx_up(png_row_infop row_info, png_bytep row,
  1990.                            png_bytep prev_row)
  1991. {
  1992.    png_uint_32 len;
  1993.    int dummy_value_d;   // fix 'forbidden register 3 (dx) was spilled' error
  1994.    int dummy_value_S;
  1995.    int dummy_value_D;
  1996.    len = row_info->rowbytes;              // number of bytes to filter
  1997.    __asm__ __volatile__ (
  1998. //pre "movl row, %%edi              nt"
  1999.       // get # of bytes to alignment
  2000. #ifdef __PIC__
  2001.       "pushl %%ebx                  nt"
  2002. #endif
  2003.       "movl %%edi, %%ecx            nt"
  2004.       "xorl %%ebx, %%ebx            nt"
  2005.       "addl $0x7, %%ecx             nt"
  2006.       "xorl %%eax, %%eax            nt"
  2007.       "andl $0xfffffff8, %%ecx      nt"
  2008. //pre "movl prev_row, %%esi         nt"
  2009.       "subl %%edi, %%ecx            nt"
  2010.       "jz up_go                     nt"
  2011.    "up_lp1:                         nt" // fix alignment
  2012.       "movb (%%edi,%%ebx,), %%al    nt"
  2013.       "addb (%%esi,%%ebx,), %%al    nt"
  2014.       "incl %%ebx                   nt"
  2015.       "cmpl %%ecx, %%ebx            nt"
  2016.       "movb %%al, -1(%%edi,%%ebx,)  nt" // mov does not affect flags; -1 to
  2017.       "jb up_lp1                    nt" //  offset incl ebx
  2018.    "up_go:                          nt"
  2019. //pre "movl len, %%edx              nt"
  2020.       "movl %%edx, %%ecx            nt"
  2021.       "subl %%ebx, %%edx            nt" // subtract alignment fix
  2022.       "andl $0x0000003f, %%edx      nt" // calc bytes over mult of 64
  2023.       "subl %%edx, %%ecx            nt" // drop over bytes from length
  2024.       // unrolled loop - use all MMX registers and interleave to reduce
  2025.       // number of branch instructions (loops) and reduce partial stalls
  2026.    "up_loop:                        nt"
  2027.       "movq (%%esi,%%ebx,), %%mm1   nt"
  2028.       "movq (%%edi,%%ebx,), %%mm0   nt"
  2029.       "movq 8(%%esi,%%ebx,), %%mm3  nt"
  2030.       "paddb %%mm1, %%mm0           nt"
  2031.       "movq 8(%%edi,%%ebx,), %%mm2  nt"
  2032.       "movq %%mm0, (%%edi,%%ebx,)   nt"
  2033.       "paddb %%mm3, %%mm2           nt"
  2034.       "movq 16(%%esi,%%ebx,), %%mm5 nt"
  2035.       "movq %%mm2, 8(%%edi,%%ebx,)  nt"
  2036.       "movq 16(%%edi,%%ebx,), %%mm4 nt"
  2037.       "movq 24(%%esi,%%ebx,), %%mm7 nt"
  2038.       "paddb %%mm5, %%mm4           nt"
  2039.       "movq 24(%%edi,%%ebx,), %%mm6 nt"
  2040.       "movq %%mm4, 16(%%edi,%%ebx,) nt"
  2041.       "paddb %%mm7, %%mm6           nt"
  2042.       "movq 32(%%esi,%%ebx,), %%mm1 nt"
  2043.       "movq %%mm6, 24(%%edi,%%ebx,) nt"
  2044.       "movq 32(%%edi,%%ebx,), %%mm0 nt"
  2045.       "movq 40(%%esi,%%ebx,), %%mm3 nt"
  2046.       "paddb %%mm1, %%mm0           nt"
  2047.       "movq 40(%%edi,%%ebx,), %%mm2 nt"
  2048.       "movq %%mm0, 32(%%edi,%%ebx,) nt"
  2049.       "paddb %%mm3, %%mm2           nt"
  2050.       "movq 48(%%esi,%%ebx,), %%mm5 nt"
  2051.       "movq %%mm2, 40(%%edi,%%ebx,) nt"
  2052.       "movq 48(%%edi,%%ebx,), %%mm4 nt"
  2053.       "movq 56(%%esi,%%ebx,), %%mm7 nt"
  2054.       "paddb %%mm5, %%mm4           nt"
  2055.       "movq 56(%%edi,%%ebx,), %%mm6 nt"
  2056.       "movq %%mm4, 48(%%edi,%%ebx,) nt"
  2057.       "addl $64, %%ebx              nt"
  2058.       "paddb %%mm7, %%mm6           nt"
  2059.       "cmpl %%ecx, %%ebx            nt"
  2060.       "movq %%mm6, -8(%%edi,%%ebx,) nt" // (+56)movq does not affect flags;
  2061.       "jb up_loop                   nt" //  -8 to offset addl ebx
  2062.       "cmpl $0, %%edx               nt" // test for bytes over mult of 64
  2063.       "jz up_end                    nt"
  2064.       "cmpl $8, %%edx               nt" // test for less than 8 bytes
  2065.       "jb up_lt8                    nt" //  [added by lcreeve at netins.net]
  2066.       "addl %%edx, %%ecx            nt"
  2067.       "andl $0x00000007, %%edx      nt" // calc bytes over mult of 8
  2068.       "subl %%edx, %%ecx            nt" // drop over bytes from length
  2069.       "jz up_lt8                    nt"
  2070.    "up_lpA:                         nt" // use MMX regs to update 8 bytes sim.
  2071.       "movq (%%esi,%%ebx,), %%mm1   nt"
  2072.       "movq (%%edi,%%ebx,), %%mm0   nt"
  2073.       "addl $8, %%ebx               nt"
  2074.       "paddb %%mm1, %%mm0           nt"
  2075.       "cmpl %%ecx, %%ebx            nt"
  2076.       "movq %%mm0, -8(%%edi,%%ebx,) nt" // movq does not affect flags; -8 to
  2077.       "jb up_lpA                    nt" //  offset add ebx
  2078.       "cmpl $0, %%edx               nt" // test for bytes over mult of 8
  2079.       "jz up_end                    nt"
  2080.    "up_lt8:                         nt"
  2081.       "xorl %%eax, %%eax            nt"
  2082.       "addl %%edx, %%ecx            nt" // move over byte count into counter
  2083.    "up_lp2:                         nt" // use x86 regs for remaining bytes
  2084.       "movb (%%edi,%%ebx,), %%al    nt"
  2085.       "addb (%%esi,%%ebx,), %%al    nt"
  2086.       "incl %%ebx                   nt"
  2087.       "cmpl %%ecx, %%ebx            nt"
  2088.       "movb %%al, -1(%%edi,%%ebx,)  nt" // mov does not affect flags; -1 to
  2089.       "jb up_lp2                    nt" //  offset inc ebx
  2090.    "up_end:                         nt"
  2091.       "EMMS                         nt" // conversion of filtered row complete
  2092. #ifdef __PIC__
  2093.       "popl %%ebx                   nt"
  2094. #endif
  2095.       : "=d" (dummy_value_d),   // 0      // output regs (dummy)
  2096.         "=S" (dummy_value_S),   // 1
  2097.         "=D" (dummy_value_D)    // 2
  2098.       : "0" (len),              // edx    // input regs
  2099.         "1" (prev_row),         // esi
  2100.         "2" (row)               // edi
  2101.       : "%eax", "%ecx"            // clobber list (no input regs!)
  2102. #ifndef __PIC__
  2103.       , "%ebx"
  2104. #endif
  2105. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  2106.       , "%mm0", "%mm1", "%mm2", "%mm3"
  2107.       , "%mm4", "%mm5", "%mm6", "%mm7"
  2108. #endif
  2109.    );
  2110. } // end of png_read_filter_row_mmx_up()
  2111. #endif /* PNG_MMX_CODE_SUPPORTED */
  2112. /*===========================================================================*/
  2113. /*                                                                           */
  2114. /*                   P N G _ R E A D _ F I L T E R _ R O W                   */
  2115. /*                                                                           */
  2116. /*===========================================================================*/
  2117. /* Optimized png_read_filter_row routines */
  2118. void /* PRIVATE */
  2119. png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep
  2120.    row, png_bytep prev_row, int filter)
  2121. {
  2122. #ifdef PNG_DEBUG
  2123.    char filnm[10];
  2124. #endif
  2125. #if defined(PNG_MMX_CODE_SUPPORTED)
  2126. /* GRR:  these are superseded by png_ptr->asm_flags: */
  2127. #define UseMMX_sub    1   // GRR:  converted 20000730
  2128. #define UseMMX_up     1   // GRR:  converted 20000729
  2129. #define UseMMX_avg    1   // GRR:  converted 20000828 (+ 16-bit bugfix 20000916)
  2130. #define UseMMX_paeth  1   // GRR:  converted 20000828
  2131.    if (_mmx_supported == 2) {
  2132.        /* this should have happened in png_init_mmx_flags() already */
  2133. #if !defined(PNG_1_0_X)
  2134.        png_warning(png_ptr, "asm_flags may not have been initialized");
  2135. #endif
  2136.        png_mmx_support();
  2137.    }
  2138. #endif /* PNG_MMX_CODE_SUPPORTED */
  2139. #ifdef PNG_DEBUG
  2140.    png_debug(1, "in png_read_filter_row (pnggccrd.c)n");
  2141.    switch (filter)
  2142.    {
  2143.       case 0: sprintf(filnm, "none");
  2144.          break;
  2145.       case 1: sprintf(filnm, "sub-%s",
  2146. #if defined(PNG_MMX_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
  2147. #if !defined(PNG_1_0_X)
  2148.         (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB)? "MMX" :
  2149. #endif
  2150. #endif
  2151. "x86");
  2152.          break;
  2153.       case 2: sprintf(filnm, "up-%s",
  2154. #ifdef PNG_MMX_CODE_SUPPORTED
  2155. #if !defined(PNG_1_0_X)
  2156.         (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP)? "MMX" :
  2157. #endif
  2158. #endif
  2159.  "x86");
  2160.          break;
  2161.       case 3: sprintf(filnm, "avg-%s",
  2162. #if defined(PNG_MMX_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
  2163. #if !defined(PNG_1_0_X)
  2164.         (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG)? "MMX" :
  2165. #endif
  2166. #endif
  2167.  "x86");
  2168.          break;
  2169.       case 4: sprintf(filnm, "Paeth-%s",
  2170. #if defined(PNG_MMX_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
  2171. #if !defined(PNG_1_0_X)
  2172.         (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH)? "MMX":
  2173. #endif
  2174. #endif
  2175. "x86");
  2176.          break;
  2177.       default: sprintf(filnm, "unknw");
  2178.          break;
  2179.    }
  2180.    png_debug2(0, "row_number=%5ld, %5s, ", png_ptr->row_number, filnm);
  2181.    png_debug1(0, "row=0x%08lx, ", (unsigned long)row);
  2182.    png_debug2(0, "pixdepth=%2d, bytes=%d, ", (int)row_info->pixel_depth,
  2183.       (int)((row_info->pixel_depth + 7) >> 3));
  2184.    png_debug1(0,"rowbytes=%8ldn", row_info->rowbytes);
  2185. #endif /* PNG_DEBUG */
  2186.    switch (filter)
  2187.    {
  2188.       case PNG_FILTER_VALUE_NONE:
  2189.          break;
  2190.       case PNG_FILTER_VALUE_SUB:
  2191. #if defined(PNG_MMX_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
  2192. #if !defined(PNG_1_0_X)
  2193.          if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB) &&
  2194.              (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
  2195.              (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
  2196. #else
  2197.          if (_mmx_supported)
  2198. #endif
  2199.          {
  2200.             png_read_filter_row_mmx_sub(row_info, row);
  2201.          }
  2202.          else
  2203. #endif /* PNG_MMX_CODE_SUPPORTED */
  2204.          {
  2205.             png_uint_32 i;
  2206.             png_uint_32 istop = row_info->rowbytes;
  2207.             png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
  2208.             png_bytep rp = row + bpp;
  2209.             png_bytep lp = row;
  2210.             for (i = bpp; i < istop; i++)
  2211.             {
  2212.                *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
  2213.                rp++;
  2214.             }
  2215.          }  /* end !UseMMX_sub */
  2216.          break;
  2217.       case PNG_FILTER_VALUE_UP:
  2218. #if defined(PNG_MMX_CODE_SUPPORTED)
  2219. #if !defined(PNG_1_0_X)
  2220.          if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP) &&
  2221.              (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
  2222.              (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
  2223. #else
  2224.          if (_mmx_supported)
  2225. #endif
  2226.          {
  2227.             png_read_filter_row_mmx_up(row_info, row, prev_row);
  2228.          }
  2229.           else
  2230. #endif /* PNG_MMX_CODE_SUPPORTED */
  2231.          {
  2232.             png_uint_32 i;
  2233.             png_uint_32 istop = row_info->rowbytes;
  2234.             png_bytep rp = row;
  2235.             png_bytep pp = prev_row;
  2236.             for (i = 0; i < istop; ++i)
  2237.             {
  2238.                *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
  2239.                rp++;
  2240.             }
  2241.          }  /* end !UseMMX_up */
  2242.          break;
  2243.       case PNG_FILTER_VALUE_AVG:
  2244. #if defined(PNG_MMX_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
  2245. #if !defined(PNG_1_0_X)
  2246.          if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG) &&
  2247.              (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
  2248.              (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
  2249. #else
  2250.          if (_mmx_supported)
  2251. #endif
  2252.          {
  2253.             png_read_filter_row_mmx_avg(row_info, row, prev_row);
  2254.          }
  2255.          else
  2256. #endif /* PNG_MMX_CODE_SUPPORTED */
  2257.          {
  2258.             png_uint_32 i;
  2259.             png_bytep rp = row;
  2260.             png_bytep pp = prev_row;
  2261.             png_bytep lp = row;
  2262.             png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
  2263.             png_uint_32 istop = row_info->rowbytes - bpp;
  2264.             for (i = 0; i < bpp; i++)
  2265.             {
  2266.                *rp = (png_byte)(((int)(*rp) +
  2267.                   ((int)(*pp++) >> 1)) & 0xff);
  2268.                rp++;
  2269.             }
  2270.             for (i = 0; i < istop; i++)
  2271.             {
  2272.                *rp = (png_byte)(((int)(*rp) +
  2273.                   ((int)(*pp++ + *lp++) >> 1)) & 0xff);
  2274.                rp++;
  2275.             }
  2276.          }  /* end !UseMMX_avg */
  2277.          break;
  2278.       case PNG_FILTER_VALUE_PAETH:
  2279. #if defined(PNG_MMX_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
  2280. #if !defined(PNG_1_0_X)
  2281.          if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH) &&
  2282.              (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
  2283.              (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
  2284. #else
  2285.          if (_mmx_supported)
  2286. #endif
  2287.          {
  2288.             png_read_filter_row_mmx_paeth(row_info, row, prev_row);
  2289.          }
  2290.          else
  2291. #endif /* PNG_MMX_CODE_SUPPORTED */
  2292.          {
  2293.             png_uint_32 i;
  2294.             png_bytep rp = row;
  2295.             png_bytep pp = prev_row;
  2296.             png_bytep lp = row;
  2297.             png_bytep cp = prev_row;
  2298.             png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
  2299.             png_uint_32 istop = row_info->rowbytes - bpp;
  2300.             for (i = 0; i < bpp; i++)
  2301.             {
  2302.                *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
  2303.                rp++;
  2304.             }
  2305.             for (i = 0; i < istop; i++)   /* use leftover rp,pp */
  2306.             {
  2307.                int a, b, c, pa, pb, pc, p;
  2308.                a = *lp++;
  2309.                b = *pp++;
  2310.                c = *cp++;
  2311.                p = b - c;
  2312.                pc = a - c;
  2313. #ifdef PNG_USE_ABS
  2314.                pa = abs(p);
  2315.                pb = abs(pc);
  2316.                pc = abs(p + pc);
  2317. #else
  2318.                pa = p < 0 ? -p : p;
  2319.                pb = pc < 0 ? -pc : pc;
  2320.                pc = (p + pc) < 0 ? -(p + pc) : p + pc;
  2321. #endif
  2322.                /*
  2323.                   if (pa <= pb && pa <= pc)
  2324.                      p = a;
  2325.                   else if (pb <= pc)
  2326.                      p = b;
  2327.                   else
  2328.                      p = c;
  2329.                 */
  2330.                p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
  2331.                *rp = (png_byte)(((int)(*rp) + p) & 0xff);
  2332.                rp++;
  2333.             }
  2334.          }  /* end !UseMMX_paeth */
  2335.          break;
  2336.       default:
  2337.          png_warning(png_ptr, "Ignoring bad row-filter type");
  2338.          *row=0;
  2339.          break;
  2340.    }
  2341. }
  2342. #endif /* PNG_HAVE_MMX_READ_FILTER_ROW */
  2343. /*===========================================================================*/
  2344. /*                                                                           */
  2345. /*                      P N G _ M M X _ S U P P O R T                        */
  2346. /*                                                                           */
  2347. /*===========================================================================*/
  2348. /* GRR NOTES:  (1) the following code assumes 386 or better (pushfl/popfl)
  2349.  *             (2) all instructions compile with gcc 2.7.2.3 and later
  2350.  *             (3) the function is moved down here to prevent gcc from
  2351.  *                  inlining it in multiple places and then barfing be-
  2352.  *                  cause the ".NOT_SUPPORTED" label is multiply defined
  2353.  *             [is there a way to signal that a *single* function should
  2354.  *              not be inlined?  is there a way to modify the label for
  2355.  *              each inlined instance, e.g., by appending _1, _2, etc.?
  2356.  *              maybe if don't use leading "." in label name? (nope...sigh)]
  2357.  */
  2358. int PNGAPI
  2359. png_mmx_support(void)
  2360. {
  2361. #if defined(PNG_MMX_CODE_SUPPORTED)
  2362.     int result;
  2363.     __asm__ __volatile__ (
  2364.         "pushl %%ebx          nt"  // ebx gets clobbered by CPUID instruction
  2365.         "pushl %%ecx          nt"  // so does ecx...
  2366.         "pushl %%edx          nt"  // ...and edx (but ecx & edx safe on Linux)
  2367. //      ".byte  0x66          nt"  // convert 16-bit pushf to 32-bit pushfd
  2368. //      "pushf                nt"  // 16-bit pushf
  2369.         "pushfl               nt"  // save Eflag to stack
  2370.         "popl %%eax           nt"  // get Eflag from stack into eax
  2371.         "movl %%eax, %%ecx    nt"  // make another copy of Eflag in ecx
  2372.         "xorl $0x200000, %%eax nt" // toggle ID bit in Eflag (i.e., bit 21)
  2373.         "pushl %%eax          nt"  // save modified Eflag back to stack
  2374. //      ".byte  0x66          nt"  // convert 16-bit popf to 32-bit popfd
  2375. //      "popf                 nt"  // 16-bit popf
  2376.         "popfl                nt"  // restore modified value to Eflag reg
  2377.         "pushfl               nt"  // save Eflag to stack
  2378.         "popl %%eax           nt"  // get Eflag from stack
  2379.         "pushl %%ecx          nt"  // save original Eflag to stack
  2380.         "popfl                nt"  // restore original Eflag
  2381.         "xorl %%ecx, %%eax    nt"  // compare new Eflag with original Eflag
  2382.         "jz 0f                nt"  // if same, CPUID instr. is not supported
  2383.         "xorl %%eax, %%eax    nt"  // set eax to zero
  2384. //      ".byte  0x0f, 0xa2    nt"  // CPUID instruction (two-byte opcode)
  2385.         "cpuid                nt"  // get the CPU identification info
  2386.         "cmpl $1, %%eax       nt"  // make sure eax return non-zero value
  2387.         "jl 0f                nt"  // if eax is zero, MMX is not supported
  2388.         "xorl %%eax, %%eax    nt"  // set eax to zero and...
  2389.         "incl %%eax           nt"  // ...increment eax to 1.  This pair is
  2390.                                      // faster than the instruction "mov eax, 1"
  2391.         "cpuid                nt"  // get the CPU identification info again
  2392.         "andl $0x800000, %%edx nt" // mask out all bits but MMX bit (23)
  2393.         "cmpl $0, %%edx       nt"  // 0 = MMX not supported
  2394.         "jz 0f                nt"  // non-zero = yes, MMX IS supported
  2395.         "movl $1, %%eax       nt"  // set return value to 1
  2396.         "jmp  1f              nt"  // DONE:  have MMX support
  2397.     "0:                       nt"  // .NOT_SUPPORTED: target label for jump instructions
  2398.         "movl $0, %%eax       nt"  // set return value to 0
  2399.     "1:                       nt"  // .RETURN: target label for jump instructions
  2400.         "popl %%edx           nt"  // restore edx
  2401.         "popl %%ecx           nt"  // restore ecx
  2402.         "popl %%ebx           nt"  // restore ebx
  2403. //      "ret                  nt"  // DONE:  no MMX support
  2404.                                      // (fall through to standard C "ret")
  2405.         : "=a" (result)              // output list
  2406.         :                            // any variables used on input (none)
  2407.                                      // no clobber list
  2408. //      , "%ebx", "%ecx", "%edx"     // GRR:  we handle these manually
  2409. //      , "memory"   // if write to a variable gcc thought was in a reg
  2410. //      , "cc"       // "condition codes" (flag bits)
  2411.     );
  2412.     _mmx_supported = result;
  2413. #else
  2414.     _mmx_supported = 0;
  2415. #endif /* PNG_MMX_CODE_SUPPORTED */
  2416.     return _mmx_supported;
  2417. }
  2418. #endif /* PNG_USE_PNGGCCRD */