pnggccrd.c
上传用户:jnfxsk
上传日期:2022-06-16
资源大小:3675k
文件大小:235k
源码类别:

游戏引擎

开发平台:

Visual C++

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