This patch adds support for the compare bytes instruction, which has
been available in the rs6000 architecture since Power6.  Thank you to
Segher Boessenkool for feedback on the original submission of this
patch.  The following refinements have been incorporated:

1. Changed the implementation and documentation to present a single
overloaded function that handles either 32-bit or 64-bit arguments.

2. Corrected the spelling of compare in the comment describing the
RS6000_BTM_CMPB macro.  In response to reviewer question of whether
this line is too long: it is not.  It only appears that way due to
alignment of tabs in the diff output.

The patch has been bootstrapped and tested on powerpc64le-unknown-linux
and powerpc-unknown-linux (big-endian, with both -m32 and -m64 target
options) with no regressions.

Is this ok for the trunk?

gcc/testsuite/ChangeLog:

2017-05-08  Kelvin Nilsen  <kel...@gcc.gnu.org>

        * gcc.target/powerpc/cmpb-1.c: New test.
        * gcc.target/powerpc/cmpb-2.c: New test.
        * gcc.target/powerpc/cmpb-3.c: New test.
        * gcc.target/powerpc/cmpb32-1.c: New test.
        * gcc.target/powerpc/cmpb32-2.c: New test.

gcc/ChangeLog:

2017-05-08  Kelvin Nilsen  <kel...@gcc.gnu.org>

        * config/rs6000/rs6000-c.c (altivec_overloaded_builtins): Add
        array entries to represent two legal parameterizations of the
        overloaded __builtin_cmpb function, as represented by the
        P6_OV_BUILTIN_CMPB constant.
        (altivec_resolve_overloaded_builtin): Add special case handling
        for the __builtin_cmpb function, as represented by the
        P6_OV_BUILTIN_CMPB constant.
        * config/rs6000/rs6000-builtin.def (BU_P6_2): New macro.
        (BU_P6_64BIT_2): New macro.
        (BU_P6_OVERLOAD_2): New macro
        (CMPB_32): Add 32-bit compare-bytes support for 32-bit only targets.
        (CMPB): Add 64-bit compare-bytes support for 32-bit and 64-bit targets.
        (CMPB): Add overload support to represent both 32-bit and 64-bit
        compare-bytes function.
        * config/rs6000/rs6000.c (rs6000_builtin_mask_calculate): Add
        support for TARGET_CMPB.
        * config/rs6000/rs6000.h: Add support for RS6000_BTM_CMPB.
        * doc/extend.texi (PowerPC AltiVec Built-in Functions): Add
        documentation of the __builtin_cmpb overloaded built-in function.

Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c  (revision 247069)
+++ gcc/config/rs6000/rs6000.c  (working copy)
@@ -3788,6 +3788,7 @@ HOST_WIDE_INT
 rs6000_builtin_mask_calculate (void)
 {
   return (((TARGET_ALTIVEC)                ? RS6000_BTM_ALTIVEC   : 0)
+         | ((TARGET_CMPB)                  ? RS6000_BTM_CMPB      : 0)
          | ((TARGET_VSX)                   ? RS6000_BTM_VSX       : 0)
          | ((TARGET_SPE)                   ? RS6000_BTM_SPE       : 0)
          | ((TARGET_PAIRED_FLOAT)          ? RS6000_BTM_PAIRED    : 0)
Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h  (revision 247069)
+++ gcc/config/rs6000/rs6000.h  (working copy)
@@ -2717,6 +2717,7 @@ extern int frame_pointer_needed;
    aren't in target_flags.  */
 #define RS6000_BTM_ALWAYS      0               /* Always enabled.  */
 #define RS6000_BTM_ALTIVEC     MASK_ALTIVEC    /* VMX/altivec vectors.  */
+#define RS6000_BTM_CMPB                MASK_CMPB       /* ISA 2.05: compare 
bytes.  */
 #define RS6000_BTM_VSX         MASK_VSX        /* VSX (vector/scalar).  */
 #define RS6000_BTM_P8_VECTOR   MASK_P8_VECTOR  /* ISA 2.07 vector.  */
 #define RS6000_BTM_P9_VECTOR   MASK_P9_VECTOR  /* ISA 3.0 vector.  */
Index: gcc/config/rs6000/rs6000-c.c
===================================================================
--- gcc/config/rs6000/rs6000-c.c        (revision 247069)
+++ gcc/config/rs6000/rs6000-c.c        (working copy)
@@ -5348,6 +5348,11 @@ const struct altivec_builtin_types altivec_overloa
     RS6000_BTI_unsigned_V1TI, RS6000_BTI_unsigned_V1TI,
     RS6000_BTI_unsigned_V1TI, 0 },
 
+  { P6_OV_BUILTIN_CMPB, P6_BUILTIN_CMPB_32,
+    RS6000_BTI_UINTSI, RS6000_BTI_UINTSI, RS6000_BTI_UINTSI, 0 },
+  { P6_OV_BUILTIN_CMPB, P6_BUILTIN_CMPB,
+    RS6000_BTI_UINTDI, RS6000_BTI_UINTDI, RS6000_BTI_UINTDI, 0 },
+
   { P8V_BUILTIN_VEC_VUPKHSW, P8V_BUILTIN_VUPKHSW,
     RS6000_BTI_V2DI, RS6000_BTI_V4SI, 0, 0 },
   { P8V_BUILTIN_VEC_VUPKHSW, P8V_BUILTIN_VUPKHSW,
@@ -6409,25 +6414,76 @@ altivec_resolve_overloaded_builtin (location_t loc
     for (desc = altivec_overloaded_builtins;
         desc->code && desc->code != fcode; desc++)
       continue;
-    
-    /* For arguments after the last, we have RS6000_BTI_NOT_OPAQUE in
-       the opX fields.  */
-    for (; desc->code == fcode; desc++)
+
+    /* Need to special case __builtin_cmp because the overloaded forms
+       of this function take (unsigned int, unsigned int) or (unsigned
+       long long int, unsigned long long int).  Since C conventions
+       allow the respective argument types to be implicitly coerced into
+       each other, the default handling does not provide adequate
+       discrimination between the desired forms of the function.  */
+    if (fcode == P6_OV_BUILTIN_CMPB)
       {
-       if ((desc->op1 == RS6000_BTI_NOT_OPAQUE
-            || rs6000_builtin_type_compatible (types[0], desc->op1))
-           && (desc->op2 == RS6000_BTI_NOT_OPAQUE
-               || rs6000_builtin_type_compatible (types[1], desc->op2))
-           && (desc->op3 == RS6000_BTI_NOT_OPAQUE
-               || rs6000_builtin_type_compatible (types[2], desc->op3)))
+       int overloaded_code;
+       int arg1_mode = TYPE_MODE (types[0]);
+       int arg2_mode = TYPE_MODE (types[1]);
+
+       if (nargs != 2)
          {
-           if (rs6000_builtin_decls[desc->overloaded_code] != NULL_TREE)
-             return altivec_build_resolved_builtin (args, n, desc);
-           else
-             unsupported_builtin = true;
+           error ("__builtin_cmpb only accepts 2 arguments");
+           return error_mark_node;
          }
+
+      /* If any supplied arguments are wider than 32 bits, resolve to
+        64-bit variant of built-in function.  */
+      if ((arg1_mode == TImode) || (arg1_mode == DImode) ||
+         (arg2_mode == TImode) || (arg2_mode == DImode))
+       {
+         /* Assure all argument and result types are compatible with
+            the built-in function represented by P6_BUILTIN_CMPB.  */
+         overloaded_code = P6_BUILTIN_CMPB;
+       }
+      else
+       {
+         /* Assure all argument and result types are compatible with
+            the built-in function represented by P6_BUILTIN_CMPB_32.  */
+         overloaded_code = P6_BUILTIN_CMPB_32;
+       }
+
+      while (desc->code && desc->code == fcode &&
+            desc->overloaded_code != overloaded_code)
+       desc++;
+
+      if (desc->code && (desc->code == fcode)
+         && rs6000_builtin_type_compatible (types[0], desc->op1)
+         && rs6000_builtin_type_compatible (types[1], desc->op2))
+       {
+         if (rs6000_builtin_decls[desc->overloaded_code] != NULL_TREE)
+           return altivec_build_resolved_builtin (args, n, desc);
+         else
+           unsupported_builtin = true;
+       }
       }
-    
+    else
+      {
+       /* For arguments after the last, we have RS6000_BTI_NOT_OPAQUE in
+          the opX fields.  */
+       for (; desc->code == fcode; desc++)
+         {
+           if ((desc->op1 == RS6000_BTI_NOT_OPAQUE
+                || rs6000_builtin_type_compatible (types[0], desc->op1))
+               && (desc->op2 == RS6000_BTI_NOT_OPAQUE
+                   || rs6000_builtin_type_compatible (types[1], desc->op2))
+               && (desc->op3 == RS6000_BTI_NOT_OPAQUE
+                   || rs6000_builtin_type_compatible (types[2], desc->op3)))
+             {
+               if (rs6000_builtin_decls[desc->overloaded_code] != NULL_TREE)
+                 return altivec_build_resolved_builtin (args, n, desc);
+               else
+                 unsupported_builtin = true;
+             }
+         }
+      }
+
     if (unsupported_builtin)
       {
        const char *name = rs6000_overloaded_builtin_name (fcode);
Index: gcc/config/rs6000/rs6000-builtin.def
===================================================================
--- gcc/config/rs6000/rs6000-builtin.def        (revision 247069)
+++ gcc/config/rs6000/rs6000-builtin.def        (working copy)
@@ -339,6 +339,34 @@
                     | RS6000_BTC_SPECIAL),                             \
                    CODE_FOR_nothing)                   /* ICODE */
 
+/* ISA 2.05 (power6) convenience macros. */
+/* For functions that depend on the CMPB instruction */
+#define BU_P6_2(ENUM, NAME, ATTR, ICODE)                               \
+  RS6000_BUILTIN_2 (P6_BUILTIN_ ## ENUM,               /* ENUM */      \
+                   "__builtin_p6_" NAME,               /* NAME */      \
+                   RS6000_BTM_CMPB,                    /* MASK */      \
+                   (RS6000_BTC_ ## ATTR                /* ATTR */      \
+                    | RS6000_BTC_BINARY),                              \
+                   CODE_FOR_ ## ICODE)                 /* ICODE */
+
+/* For functions that depend on 64-BIT support and on the CMPB instruction */
+#define BU_P6_64BIT_2(ENUM, NAME, ATTR, ICODE)                 \
+  RS6000_BUILTIN_2 (P6_BUILTIN_ ## ENUM,               /* ENUM */      \
+                   "__builtin_p6_" NAME,               /* NAME */      \
+                   RS6000_BTM_CMPB                                     \
+                     | RS6000_BTM_64BIT,               /* MASK */      \
+                   (RS6000_BTC_ ## ATTR                /* ATTR */      \
+                    | RS6000_BTC_BINARY),                              \
+                   CODE_FOR_ ## ICODE)                 /* ICODE */
+
+#define BU_P6_OVERLOAD_2(ENUM, NAME)                                   \
+  RS6000_BUILTIN_2 (P6_OV_BUILTIN_ ## ENUM,            /* ENUM */      \
+                   "__builtin_" NAME,                  /* NAME */      \
+                   RS6000_BTM_CMPB,                    /* MASK */      \
+                   (RS6000_BTC_OVERLOADED              /* ATTR */      \
+                    | RS6000_BTC_BINARY),                              \
+                   CODE_FOR_nothing)                   /* ICODE */
+
 /* ISA 2.07 (power8) vector convenience macros.  */
 /* For the instructions that are encoded as altivec instructions use
    __builtin_altivec_ as the builtin name.  */
@@ -1778,6 +1806,10 @@ BU_VSX_OVERLOAD_X (ST,        "st")
 BU_VSX_OVERLOAD_X (XL,      "xl")
 BU_VSX_OVERLOAD_X (XST,             "xst")
 
+/* 2 argument CMPB instructions added in ISA 2.05. */
+BU_P6_2 (CMPB_32,        "cmpb_32",    CONST,  cmpbsi3)
+BU_P6_64BIT_2 (CMPB,     "cmpb",       CONST,  cmpbdi3)
+
 /* 1 argument VSX instructions added in ISA 2.07.  */
 BU_P8V_VSX_1 (XSCVSPDPN,      "xscvspdpn",     CONST,  vsx_xscvspdpn)
 BU_P8V_VSX_1 (XSCVDPSPN,      "xscvdpspn",     CONST,  vsx_xscvdpspn)
@@ -1864,6 +1896,9 @@ BU_P8V_AV_P (VCMPEQUD_P,  "vcmpequd_p",   CONST,  vect
 BU_P8V_AV_P (VCMPGTSD_P,       "vcmpgtsd_p",   CONST,  vector_gt_v2di_p)
 BU_P8V_AV_P (VCMPGTUD_P,       "vcmpgtud_p",   CONST,  vector_gtu_v2di_p)
 
+/* ISA 2.05 overloaded 2 argument functions.  */
+BU_P6_OVERLOAD_2 (CMPB, "cmpb")
+
 /* ISA 2.07 vector overloaded 1 argument functions.  */
 BU_P8V_OVERLOAD_1 (VUPKHSW,    "vupkhsw")
 BU_P8V_OVERLOAD_1 (VUPKLSW,    "vupklsw")
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi (revision 247069)
+++ gcc/doc/extend.texi (working copy)
@@ -15107,6 +15107,24 @@ Similar to @code{__builtin_nans}, except the retur
 @end table
 
 The following built-in functions are available for the PowerPC family
+of processors, starting with ISA 2.05 or later (@option{-mcpu=power6}
+or @option{-mcmpb}):
+@smallexample
+unsigned long long __builtin_cmpb (unsigned long long int, unsigned long long 
int);
+unsigned int __builtin_cmpb (unsigned int, unsigned int);
+@end smallexample
+
+The @code{__builtin_cmpb} function
+performs a byte-wise compare on the contents of its two arguments,
+returning the result of the byte-wise comparison as the returned
+value.  For each byte comparison, the corresponding byte of the return
+value holds 0xff if the input bytes are equal and 0 if the input bytes
+are not equal.  If either of the arguments to this built-in function
+is wider than 32 bits, the function call expands into the form that
+expects @code{unsigned long long int} arguments
+which is only available on 64-bit targets.
+
+The following built-in functions are available for the PowerPC family
 of processors, starting with ISA 2.06 or later (@option{-mcpu=power7}
 or @option{-mpopcntd}):
 @smallexample
Index: gcc/testsuite/gcc.target/powerpc/cmpb-1.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/cmpb-1.c   (revision 0)
+++ gcc/testsuite/gcc.target/powerpc/cmpb-1.c   (revision 247560)
@@ -0,0 +1,31 @@
+/* { dg-do run { target { powerpc*-*-* } } } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { 
"-mcpu=power6" } } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-require-effective-target dfp_hw } */
+/* { dg-options "-mcpu=power6" } */
+
+void abort ();
+
+unsigned long long int
+do_compare (unsigned long long int a, unsigned long long int b)
+{
+  return __builtin_cmpb (a, b);
+}
+
+void
+expect (unsigned long long int pattern, unsigned long long int value)
+{
+  if (pattern != value)
+    abort ();
+}
+
+int
+main (int argc, char *argv[])
+{
+  expect (0xff00000000000000LL,
+         do_compare (0x0123456789abcdefLL, 0x0100000000000000LL));
+  expect (0x00ffffffffffffff,
+         do_compare (0x0123456789abcdefLL, 0x0023456789abcdefLL));
+  expect (0x00000000000000ff,
+         do_compare (0x00000000000000efLL, 0x0123456789abcdefLL));
+}
Index: gcc/testsuite/gcc.target/powerpc/cmpb-2.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/cmpb-2.c   (revision 0)
+++ gcc/testsuite/gcc.target/powerpc/cmpb-2.c   (revision 247560)
@@ -0,0 +1,31 @@
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { 
"-mcpu=power5" } } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-require-effective-target powerpc_popcntb_ok } */
+/* { dg-options "-mcpu=power5" } */
+
+void abort ();
+
+unsigned long long int
+do_compare (unsigned long long int a, unsigned long long int b)
+{
+  return __builtin_cmpb (a, b);        /* { dg-warning "implicit declaration 
of function '__builtin_cmpb'" } */
+}
+
+void
+expect (unsigned long long int pattern, unsigned long long int value)
+{
+  if (pattern != value)
+    abort ();
+}
+
+int
+main (int argc, char *argv[])
+{
+  expect (0xff00000000000000LL,
+         do_compare (0x0123456789abcdefLL, 0x0100000000000000LL));
+  expect (0x00ffffffffffffff,
+         do_compare (0x0123456789abcdefLL, 0x0023456789abcdefLL));
+  expect (0x00000000000000ff,
+         do_compare (0x00000000000000efLL, 0x0123456789abcdefLL));
+}
Index: gcc/testsuite/gcc.target/powerpc/cmpb-3.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/cmpb-3.c   (revision 0)
+++ gcc/testsuite/gcc.target/powerpc/cmpb-3.c   (revision 247649)
@@ -0,0 +1,30 @@
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { 
"-mcpu=power6" } } */
+/* { dg-require-effective-target ilp32 } */
+/* { dg-require-effective-target powerpc_popcntb_ok } */
+/* { dg-options "-mcpu=power6" } */
+
+void abort ();
+
+long long int
+do_compare (long long int a, long long int b)
+{
+  return __builtin_cmpb (a, b);        /* { dg-error "Builtin function 
__builtin_cmpb not supported in this compiler configuration" } */
+}
+
+void expect (long long int pattern, long long int value)
+{
+  if (pattern != value)
+    abort ();
+}
+
+int
+main (int argc, char *argv[])
+{
+  expect (0xff00000000000000LL,
+         do_compare (0x0123456789abcdefLL, 0x0100000000000000LL));
+  expect (0x00ffffffffffffff,
+         do_compare (0x0123456789abcdefLL, 0x0023456789abcdefLL));
+  expect (0x00000000000000ff,
+         do_compare (0x00000000000000efLL, 0x0123456789abcdefLL));
+}
Index: gcc/testsuite/gcc.target/powerpc/cmpb32-1.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/cmpb32-1.c (revision 0)
+++ gcc/testsuite/gcc.target/powerpc/cmpb32-1.c (revision 247560)
@@ -0,0 +1,27 @@
+/* { dg-do run { target { powerpc*-*-* } } } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { 
"-mcpu=power6" } } */
+/* { dg-require-effective-target dfp_hw } */
+/* { dg-options "-mcpu=power6" } */
+
+void abort ();
+
+unsigned int
+do_compare (unsigned int a, unsigned int b)
+{
+  return __builtin_cmpb (a, b);
+}
+
+void
+expect (unsigned int pattern, unsigned int value)
+{
+  if (pattern != value)
+    abort ();
+}
+
+int
+main (int argc, char *argv[])
+{
+  expect (0xff000000, do_compare (0x12345678, 0x12000000));
+  expect (0x00ffffff, do_compare (0x12345678, 0x00345678));
+  expect (0x000000ff, do_compare (0x00000078, 0x12345678));
+}
Index: gcc/testsuite/gcc.target/powerpc/cmpb32-2.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/cmpb32-2.c (revision 0)
+++ gcc/testsuite/gcc.target/powerpc/cmpb32-2.c (revision 247560)
@@ -0,0 +1,27 @@
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { 
"-mcpu=power5" } } */
+/* { dg-require-effective-target powerpc_popcntb_ok } */
+/* { dg-options "-mcpu=power5" } */
+
+void abort ();
+
+unsigned int
+do_compare (unsigned int a, unsigned int b)
+{
+  return __builtin_cmpb (a, b);  /* { dg-warning "implicit declaration of 
function '__builtin_cmpb'" } */
+}
+
+void
+expect (unsigned int pattern, unsigned int value)
+{
+  if (pattern != value)
+    abort ();
+}
+
+int
+main (int argc, char *argv[])
+{
+  expect (0xff000000, do_compare (0x12345678, 0x12000000));
+  expect (0x00ffffff, do_compare (0x12345678, 0x00345678));
+  expect (0x000000ff, do_compare (0x00000078, 0x12345678));
+}

Reply via email to