https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82628

--- Comment #10 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
Testcase for determining the sbbb and adcb behavior for all operands:

int
main (void)
{
  int cf, x, y;
  for (cf = 0; cf < 2; cf++)
    for (x = 0; x <= 255; x++)
      for (y = 0; y <= 255; y++)
        {
          unsigned char cfout, xout;
          asm volatile ("cmpb %2, %3; sbbb %4, %1; setc %0"
                        : "=a" (cfout), "=q" (xout)
                        : "q" ((unsigned char) cf), "q" ((unsigned char) 0),
"q" ((unsigned char) y), "1" ((unsigned char) x));
          if (cfout != ((unsigned char) (y + cf) > (unsigned char) x))
            __builtin_printf ("cf %d x %x y %x cf %d %d\n", cf, x, y, cfout,
((unsigned char) (y + cf) > (unsigned char) x));
          if (cfout != ((y + cf) > (unsigned char) x))
            __builtin_abort ();
        }
  __builtin_printf ("=======\n");
  for (cf = 0; cf < 2; cf++)
    for (x = -128; x <= 127; x++)
      for (y = -128; y <= 127; y++)
        {
          unsigned char ovout, xout;
          asm volatile ("cmpb %2, %3; sbbb %4, %1; seto %0"
                        : "=a" (ovout), "=q" (xout)
                        : "q" ((unsigned char) cf), "q" ((unsigned char) 0),
"q" ((unsigned char) y), "1" ((unsigned char) x));
          if ((ovout != ((signed char) xout < 0)) != ((signed char) (y + cf) >
(signed char) x))
            __builtin_printf ("cf %d x %x y %x ov %d %d %d\n", cf, x, y, ovout,
(ovout != ((signed char) xout < 0)),
                              ((signed char) (y + cf) > (signed char) x));
          if ((ovout != ((signed char) xout < 0)) != ((y + cf) > (signed char)
x))
            __builtin_abort ();
        }
  __builtin_printf ("=======\n");
  for (cf = 0; cf < 2; cf++)
    for (x = 0; x <= 255; x++)
      for (y = 0; y <= 255; y++)
        {
          unsigned char cfout, xout;
          asm volatile ("cmpb %2, %3; adcb %4, %1; setc %0"
                        : "=a" (cfout), "=q" (xout)
                        : "q" ((unsigned char) cf), "q" ((unsigned char) 0),
"q" ((unsigned char) y), "1" ((unsigned char) x));
          if (cfout != ((unsigned char) (x + y + cf) < (unsigned char) x))
            __builtin_printf ("cf %d x %x y %x cf %d %d\n", cf, x, y, cfout,
((unsigned char) (x + y + cf) < (unsigned char) x));
          if (cfout != ((unsigned char) (x + y + cf) < (y + cf)))
            __builtin_abort ();
        }
  return 0;
}

This shows that the current
(define_insn "sub<mode>3_carry_ccgz"
  [(set (reg:CCGZ FLAGS_REG)
        (compare:CCGZ
          (match_operand:DWIH 1 "register_operand" "0")
          (plus:DWIH
            (ltu:DWIH (reg:CC FLAGS_REG) (const_int 0))
            (match_operand:DWIH 2 "x86_64_general_operand" "rme"))))
   (clobber (match_scratch:DWIH 0 "=r"))]
  ""
  "sbb{<imodesuffix>}\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "<MODE>")])
pattern when we want a comparison that checks the CF flag (i.e. GEU, LTU
comparisons) is wrong for the case
when operands[2] is the unsigned integer maximum and CF is set from earlier; so
it should really be something like:
(define_insn "sub<mode>3_carry_ccc"
  [(set (reg:CCC FLAGS_REG)
        (compare:CCC
          (zero_extend:<DWI> (match_operand:DWIH 1 "register_operand" "0"))
          (plus:<DWI>
            (ltu:<DWI> (reg:CC FLAGS_REG) (const_int 0))
            (zero_extend:<DWI> (match_operand:DWIH 2 "x86_64_general_operand"
"rme")))))
   (clobber (match_scratch:DWIH 0 "=r"))]
  ""
  "sbb{<imodesuffix>}\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "<MODE>")])
(see first loop in the testcase above).
For pattern when we want a comparison that checks the SF and OF flags (i.e. GE,
LT comparisons), we probably need a different
mode instead of CCGZmode that says that just SF and OF are valid (or is any
mode we have usable for this), and then do something like:
(define_insn "sub<mode>3_carry_ccx"
  [(set (reg:CCX FLAGS_REG)
        (compare:CCX
          (sign_extend:<DWI> (match_operand:DWIH 1 "register_operand" "0"))
          (plus:<DWI>
            (ltu:<DWI> (reg:CC FLAGS_REG) (const_int 0))
            (sign_extend:<DWI> (match_operand:DWIH 2 "x86_64_general_operand"
"rme")))))
   (clobber (match_scratch:DWIH 0 "=r"))]
  ""
  "sbb{<imodesuffix>}\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "<MODE>")])
as what we have for the signed comparisons using SF cmp OF fails if operands[2]
is signed maximum and CF is set.
Though, not really sure about this, because in the testcase above I'm using SF
bit from the 8-bit result rather than 16-bit/32-bit result.
And subborrow<mode> and addcarry<mode> would need changes too.

Reply via email to