Hi!

As the testcases show, not using build_binary_op resulted in sometimes
non-promoted arguments, and there were issues with division,
where we initially want to use TRUNC_DIV_EXPR, but if the arguments
are floating point, change it into RDIV_EXPR instead.

Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux,
committed to trunk (backports will follow later, but hopefully soon).

2015-02-04  Jakub Jelinek  <ja...@redhat.com>

        PR c/64824
        PR c/64868
gcc/c/
        * c-parser.c (c_parser_omp_atomic): Handle RDIV_EXPR.
gcc/cp/
        * parser.c (cp_parser_omp_atomic): Handle RDIV_EXPR.
gcc/c-family/
        * c-omp.c (c_finish_omp_atomic): Use TRUNC_DIV_EXPR
        instead of RDIV_EXPR.  Use build_binary_op instead of
        build2_loc.
libgomp/
        * testsuite/libgomp.c/pr64824.c: New test.
        * testsuite/libgomp.c/pr64868.c: New test.
        * testsuite/libgomp.c++/pr64824.C: New test.
        * testsuite/libgomp.c++/pr64868.C: New test.

--- gcc/c/c-parser.c.jj 2015-02-03 10:33:55.000000000 +0100
+++ gcc/c/c-parser.c    2015-02-04 17:57:50.318652940 +0100
@@ -12611,6 +12611,7 @@ restart:
            {
            case MULT_EXPR:
            case TRUNC_DIV_EXPR:
+           case RDIV_EXPR:
            case PLUS_EXPR:
            case MINUS_EXPR:
            case LSHIFT_EXPR:
--- gcc/cp/parser.c.jj  2015-01-31 10:07:36.000000000 +0100
+++ gcc/cp/parser.c     2015-02-04 18:11:38.761575168 +0100
@@ -29835,6 +29835,7 @@ restart:
                {
                case MULT_EXPR:
                case TRUNC_DIV_EXPR:
+               case RDIV_EXPR:
                case PLUS_EXPR:
                case MINUS_EXPR:
                case LSHIFT_EXPR:
--- gcc/c-family/c-omp.c.jj     2015-01-15 23:39:03.000000000 +0100
+++ gcc/c-family/c-omp.c        2015-02-04 19:08:55.498673461 +0100
@@ -206,6 +206,9 @@ c_finish_omp_atomic (location_t loc, enu
       return error_mark_node;
     }
 
+  if (opcode == RDIV_EXPR)
+    opcode = TRUNC_DIV_EXPR;
+
   /* ??? Validate that rhs does not overlap lhs.  */
 
   /* Take and save the address of the lhs.  From then on we'll reference it
@@ -240,7 +243,7 @@ c_finish_omp_atomic (location_t loc, enu
      to do this, and then take it apart again.  */
   if (swapped)
     {
-      rhs = build2_loc (loc, opcode, TREE_TYPE (lhs), rhs, lhs);
+      rhs = build_binary_op (loc, opcode, rhs, lhs, 1);
       opcode = NOP_EXPR;
     }
   bool save = in_late_binary_op;
--- libgomp/testsuite/libgomp.c/pr64824.c.jj    2015-02-04 20:18:57.061199758 
+0100
+++ libgomp/testsuite/libgomp.c/pr64824.c       2015-02-04 20:18:26.509710353 
+0100
@@ -0,0 +1,16 @@
+/* PR c/64824 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fopenmp" } */
+
+int
+main ()
+{
+  long long a;
+  long long b = 1LL;
+  int c = 3;
+#pragma omp atomic capture
+  a = b = c << b;
+  if (b != 6LL || a != 6LL)
+    __builtin_abort ();
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/pr64868.c.jj    2015-02-04 19:46:39.570674828 
+0100
+++ libgomp/testsuite/libgomp.c/pr64868.c       2015-02-04 19:46:19.000000000 
+0100
@@ -0,0 +1,87 @@
+/* PR c/64868 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fopenmp" } */
+
+float f = 2.0f;
+double d = 4.0;
+long double ld = 8.0L;
+
+void
+foo ()
+{
+#pragma omp atomic
+  f = 1.0f / f;
+#pragma omp atomic
+  f = 1 / f;
+#pragma omp atomic
+  f = f / 2.0f;
+#pragma omp atomic
+  f = f / 2;
+#pragma omp atomic
+  f /= 2.0f;
+#pragma omp atomic
+  f /= 2;
+#pragma omp atomic
+  d = 1.0 / d;
+#pragma omp atomic
+  d = 1 / d;
+#pragma omp atomic
+  d = d / 2.0;
+#pragma omp atomic
+  d = d / 2;
+#pragma omp atomic
+  d /= 2.0;
+#pragma omp atomic
+  d /= 2;
+#pragma omp atomic
+  ld = 1.0L / ld;
+#pragma omp atomic
+  ld = 1 / ld;
+#pragma omp atomic
+  ld = ld / 2.0L;
+#pragma omp atomic
+  ld = ld / 2;
+#pragma omp atomic
+  ld /= 2.0L;
+#pragma omp atomic
+  ld /= 2;
+  if (f != 0.125f || d != 0.25 || ld != 0.5L)
+    __builtin_abort ();
+}
+
+#ifdef __cplusplus
+template <typename T, int N1, int N2>
+void
+bar ()
+{
+  T v = ::d;
+#pragma omp atomic
+  v *= 16;
+#pragma omp atomic
+  v = 1.0 / v;
+#pragma omp atomic
+  v = N1 / v;
+#pragma omp atomic
+  v = v / 2.0;
+#pragma omp atomic
+  v = v / N2;
+#pragma omp atomic
+  v /= 2.0;
+#pragma omp atomic
+  v /= N2;
+  if (v != 0.25)
+    __builtin_abort ();
+}
+#endif
+
+int
+main ()
+{
+  foo ();
+#ifdef __cplusplus
+  bar<float, 1, 2> ();
+  bar<double, 1, 2> ();
+  bar<long double, 1, 2> ();
+#endif
+  return 0;
+}
--- libgomp/testsuite/libgomp.c++/pr64824.C.jj  2015-02-04 20:19:23.268761761 
+0100
+++ libgomp/testsuite/libgomp.c++/pr64824.C     2015-02-04 20:19:19.364827006 
+0100
@@ -0,0 +1,5 @@
+// PR c/64824
+// { dg-do run }
+// { dg-options "-O2 -fopenmp" }
+
+#include "../libgomp.c/pr64824.c"
--- libgomp/testsuite/libgomp.c++/pr64868.C.jj  2015-02-04 19:47:23.565935798 
+0100
+++ libgomp/testsuite/libgomp.c++/pr64868.C     2015-02-04 19:47:16.883048057 
+0100
@@ -0,0 +1,5 @@
+// PR c/64868
+// { dg-do run }
+// { dg-options "-O2 -fopenmp" }
+
+#include "../libgomp.c/pr64868.c"

        Jakub

Reply via email to