diff mbox

Backports to 4.9

Message ID 20150603213850.GZ10247@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek June 3, 2015, 9:38 p.m. UTC
Hi!

I've bootstrapped/regtested on x86_64-linux and i686-linux
following backports and committed them to 4.9 branch.

	Jakub
2015-06-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2015-02-18  Jakub Jelinek  <jakub@redhat.com>

	PR gcov-profile/64634
	* tree-eh.c (frob_into_branch_around): Fix up typos
	in function comment.
	(lower_catch): Put eh_seq resulting from EH lowering of
	the cleanup sequence after the cleanup rather than before
	it.

	* g++.dg/gcov/gcov-15.C: New test.
2015-06-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2015-03-10  Jakub Jelinek  <jakub@redhat.com>

	PR target/65368
	* config/i386/i386.md (bmi2_bzhi_<mode>3): Removed define_insn,
	new define_expand.
	(*bmi2_bzhi_<mode>3, *bmi2_bzhi_<mode>3_1): New define_insns.

	* gcc.target/i386/bmi2-bzhi-2.c: New test.

--- gcc/config/i386/i386.md	(revision 221334)
+++ gcc/config/i386/i386.md	(revision 221335)
@@ -12678,17 +12678,51 @@ (define_insn "*bmi_blsr_<mode>"
    (set_attr "mode" "<MODE>")])
 
 ;; BMI2 instructions.
-(define_insn "bmi2_bzhi_<mode>3"
+(define_expand "bmi2_bzhi_<mode>3"
+  [(parallel
+    [(set (match_operand:SWI48 0 "register_operand")
+	  (zero_extract:SWI48
+	    (match_operand:SWI48 1 "nonimmediate_operand")
+	    (umin:SWI48
+	      (and:SWI48 (match_operand:SWI48 2 "register_operand")
+			 (const_int 255))
+	      (match_dup 3))
+	    (const_int 0)))
+     (clobber (reg:CC FLAGS_REG))])]
+  "TARGET_BMI2"
+  "operands[3] = GEN_INT (<MODE_SIZE> * BITS_PER_UNIT);")
+
+(define_insn "*bmi2_bzhi_<mode>3"
   [(set (match_operand:SWI48 0 "register_operand" "=r")
-	(and:SWI48 (lshiftrt:SWI48 (const_int -1)
-				   (match_operand:SWI48 2 "register_operand" "r"))
-		   (match_operand:SWI48 1 "nonimmediate_operand" "rm")))
+	(zero_extract:SWI48
+	  (match_operand:SWI48 1 "nonimmediate_operand" "rm")
+	  (umin:SWI48
+	    (and:SWI48 (match_operand:SWI48 2 "register_operand" "r")
+		       (const_int 255))
+	    (match_operand:SWI48 3 "const_int_operand" "n"))
+	  (const_int 0)))
    (clobber (reg:CC FLAGS_REG))]
-  "TARGET_BMI2"
+  "TARGET_BMI2 && INTVAL (operands[3]) == <MODE_SIZE> * BITS_PER_UNIT"
   "bzhi\t{%2, %1, %0|%0, %1, %2}"
   [(set_attr "type" "bitmanip")
    (set_attr "prefix" "vex")
    (set_attr "mode" "<MODE>")])
+
+(define_mode_attr k [(SI "k") (DI "q")])
+(define_insn "*bmi2_bzhi_<mode>3_1"
+  [(set (match_operand:SWI48 0 "register_operand" "=r")
+	(zero_extract:SWI48
+	  (match_operand:SWI48 1 "nonimmediate_operand" "rm")
+	  (umin:SWI48
+	    (zero_extend:SWI48 (match_operand:QI 2 "register_operand" "r"))
+	    (match_operand:SWI48 3 "const_int_operand" "n"))
+	  (const_int 0)))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_BMI2 && INTVAL (operands[3]) == <MODE_SIZE> * BITS_PER_UNIT"
+  "bzhi\t{%<k>2, %1, %0|%0, %1, %<k>2}"
+  [(set_attr "type" "bitmanip")
+   (set_attr "prefix" "vex")
+   (set_attr "mode" "<MODE>")])
 
 (define_insn "bmi2_pdep_<mode>3"
   [(set (match_operand:SWI48 0 "register_operand" "=r")
--- gcc/testsuite/gcc.target/i386/bmi2-bzhi-2.c	(revision 0)
+++ gcc/testsuite/gcc.target/i386/bmi2-bzhi-2.c	(revision 221335)
@@ -0,0 +1,67 @@
+/* PR target/65368 */
+/* { dg-do assemble { target bmi2 } } */
+/* { dg-options "-O2 -mbmi2" } */
+
+#include <x86intrin.h>
+#include "bmi2-check.h"
+
+unsigned int a;
+unsigned long long b;
+
+#define A __attribute__((noinline, noclone))
+
+A unsigned int f1 (void) { return _bzhi_u32 (a, 0); }
+A unsigned int f2 (unsigned int x) { return _bzhi_u32 (x, 0); }
+A unsigned int f3 (void) { return _bzhi_u32 (a, 5); }
+A unsigned int f4 (unsigned int x) { return _bzhi_u32 (x, 5); }
+A unsigned int f5 (void) { return _bzhi_u32 (a, 31); }
+A unsigned int f6 (unsigned int x) { return _bzhi_u32 (x, 31); }
+A unsigned int f7 (void) { return _bzhi_u32 (a, 32); }
+A unsigned int f8 (unsigned int x) { return _bzhi_u32 (x, 32); }
+A unsigned int f9 (void) { return _bzhi_u32 (a, 37); }
+A unsigned int f10 (unsigned int x) { return _bzhi_u32 (x, 37); }
+A unsigned int f11 (void) { return _bzhi_u32 (a, 257); }
+A unsigned int f12 (unsigned int x) { return _bzhi_u32 (x, 257); }
+A unsigned int f13 (void) { return _bzhi_u32 (a, 289); }
+A unsigned int f14 (unsigned int x) { return _bzhi_u32 (x, 289); }
+#ifdef __x86_64__
+A unsigned long long f21 (void) { return _bzhi_u64 (b, 0); }
+A unsigned long long f22 (unsigned long long x) { return _bzhi_u64 (x, 0); }
+A unsigned long long f23 (void) { return _bzhi_u64 (b, 5); }
+A unsigned long long f24 (unsigned long long x) { return _bzhi_u64 (x, 5); }
+A unsigned long long f25 (void) { return _bzhi_u64 (b, 63); }
+A unsigned long long f26 (unsigned long long x) { return _bzhi_u64 (x, 63); }
+A unsigned long long f27 (void) { return _bzhi_u64 (b, 64); }
+A unsigned long long f28 (unsigned long long x) { return _bzhi_u64 (x, 64); }
+A unsigned long long f29 (void) { return _bzhi_u64 (b, 69); }
+A unsigned long long f30 (unsigned long long x) { return _bzhi_u64 (x, 69); }
+A unsigned long long f31 (void) { return _bzhi_u64 (b, 257); }
+A unsigned long long f32 (unsigned long long x) { return _bzhi_u64 (x, 257); }
+A unsigned long long f33 (void) { return _bzhi_u64 (b, 321); }
+A unsigned long long f34 (unsigned long long x) { return _bzhi_u64 (x, 321); }
+#endif
+
+static void
+bmi2_test ()
+{
+  a = -1U;
+  b = -1ULL;
+  if (f1 () != 0 || f2 (-1U) != 0
+      || f3 () != 0x1f || f4 (-1U) != 0x1f
+      || f5 () != 0x7fffffffU || f6 (-1U) != 0x7fffffffU
+      || f7 () != -1U || f8 (-1U) != -1U
+      || f9 () != -1U || f10 (-1U) != -1U
+      || f11 () != 1 || f12 (-1U) != 1
+      || f13 () != -1U || f14 (-1U) != -1U)
+    abort ();
+#ifdef __x86_64__
+  if (f21 () != 0 || f22 (-1ULL) != 0
+      || f23 () != 0x1f || f24 (-1ULL) != 0x1f
+      || f25 () != 0x7fffffffffffffffULL || f26 (-1ULL) != 0x7fffffffffffffffULL
+      || f27 () != -1ULL || f28 (-1ULL) != -1ULL
+      || f29 () != -1ULL || f30 (-1ULL) != -1ULL
+      || f31 () != 1 || f32 (-1ULL) != 1
+      || f33 () != -1ULL || f34 (-1ULL) != -1ULL)
+    abort ();
+#endif
+}
2015-06-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2015-03-16  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/65427
	* tree-vect-generic.c (do_cond, expand_vector_scalar_condition): New
	functions.
	(expand_vector_operations_1): Handle BLKmode vector COND_EXPR.

	* gcc.c-torture/execute/pr65427.c: New test.

--- gcc/tree-vect-generic.c	(revision 221463)
+++ gcc/tree-vect-generic.c	(revision 221464)
@@ -1389,6 +1389,57 @@ count_type_subparts (tree type)
   return VECTOR_TYPE_P (type) ? TYPE_VECTOR_SUBPARTS (type) : 1;
 }
 
+static tree
+do_cond (gimple_stmt_iterator *gsi, tree inner_type, tree a, tree b,
+	 tree bitpos, tree bitsize, enum tree_code code)
+{
+  if (TREE_CODE (TREE_TYPE (a)) == VECTOR_TYPE)
+    a = tree_vec_extract (gsi, inner_type, a, bitsize, bitpos);
+  if (TREE_CODE (TREE_TYPE (b)) == VECTOR_TYPE)
+    b = tree_vec_extract (gsi, inner_type, b, bitsize, bitpos);
+  tree cond = gimple_assign_rhs1 (gsi_stmt (*gsi));
+  return gimplify_build3 (gsi, code, inner_type, cond, a, b);
+}
+
+/* Expand a vector COND_EXPR to scalars, piecewise.  */
+static void
+expand_vector_scalar_condition (gimple_stmt_iterator *gsi)
+{
+  gimple stmt = gsi_stmt (*gsi);
+  tree type = gimple_expr_type (stmt);
+  tree compute_type = get_compute_type (COND_EXPR, mov_optab, type);
+  machine_mode compute_mode = TYPE_MODE (compute_type);
+  gcc_assert (compute_mode != BLKmode);
+  tree lhs = gimple_assign_lhs (stmt);
+  tree rhs2 = gimple_assign_rhs2 (stmt);
+  tree rhs3 = gimple_assign_rhs3 (stmt);
+  tree new_rhs;
+
+  /* If the compute mode is not a vector mode (hence we are not decomposing
+     a BLKmode vector to smaller, hardware-supported vectors), we may want
+     to expand the operations in parallel.  */
+  if (GET_MODE_CLASS (compute_mode) != MODE_VECTOR_INT
+      && GET_MODE_CLASS (compute_mode) != MODE_VECTOR_FLOAT
+      && GET_MODE_CLASS (compute_mode) != MODE_VECTOR_FRACT
+      && GET_MODE_CLASS (compute_mode) != MODE_VECTOR_UFRACT
+      && GET_MODE_CLASS (compute_mode) != MODE_VECTOR_ACCUM
+      && GET_MODE_CLASS (compute_mode) != MODE_VECTOR_UACCUM)
+    new_rhs = expand_vector_parallel (gsi, do_cond, type, rhs2, rhs3,
+				      COND_EXPR);
+  else
+    new_rhs = expand_vector_piecewise (gsi, do_cond, type, compute_type,
+				       rhs2, rhs3, COND_EXPR);
+  if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (new_rhs)))
+    new_rhs = gimplify_build1 (gsi, VIEW_CONVERT_EXPR, TREE_TYPE (lhs),
+			       new_rhs);
+
+  /* NOTE:  We should avoid using gimple_assign_set_rhs_from_tree. One
+     way to do it is change expand_vector_operation and its callees to
+     return a tree_code, RHS1 and RHS2 instead of a tree. */
+  gimple_assign_set_rhs_from_tree (gsi, new_rhs);
+  update_stmt (gsi_stmt (*gsi));
+}
+
 /* Process one statement.  If we identify a vector operation, expand it.  */
 
 static void
@@ -1420,6 +1471,14 @@ expand_vector_operations_1 (gimple_stmt_
       return;
     }
 
+  if (code == COND_EXPR
+      && TREE_CODE (TREE_TYPE (gimple_assign_lhs (stmt))) == VECTOR_TYPE
+      && TYPE_MODE (TREE_TYPE (gimple_assign_lhs (stmt))) == BLKmode)
+    {
+      expand_vector_scalar_condition (gsi);
+      return;
+    }
+
   if (code == CONSTRUCTOR
       && TREE_CODE (lhs) == SSA_NAME
       && VECTOR_MODE_P (TYPE_MODE (TREE_TYPE (lhs)))
--- gcc/testsuite/gcc.c-torture/execute/pr65427.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/pr65427.c	(revision 221464)
@@ -0,0 +1,34 @@
+/* PR tree-optimization/65427 */
+
+typedef int V __attribute__ ((vector_size (8 * sizeof (int))));
+V a, b, c, d, e, f;
+
+__attribute__((noinline, noclone)) void
+foo (int x, int y)
+{
+  do
+    {
+      if (x)
+	d = a ^ c;
+      else
+	d = a ^ b;
+    }
+  while (y);
+}
+
+int
+main ()
+{
+  a = (V) { 1, 2, 3, 4, 5, 6, 7, 8 };
+  b = (V) { 0x40, 0x80, 0x40, 0x80, 0x40, 0x80, 0x40, 0x80 };
+  e = (V) { 0x41, 0x82, 0x43, 0x84, 0x45, 0x86, 0x47, 0x88 };
+  foo (0, 0);
+  if (__builtin_memcmp (&d, &e, sizeof (V)) != 0)
+    __builtin_abort ();
+  c = (V) { 0x80, 0x40, 0x80, 0x40, 0x80, 0x40, 0x80, 0x40 };
+  f = (V) { 0x81, 0x42, 0x83, 0x44, 0x85, 0x46, 0x87, 0x48 };
+  foo (1, 0);
+  if (__builtin_memcmp (&d, &f, sizeof (V)) != 0)
+    __builtin_abort ();
+  return 0;
+}
2015-06-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2015-03-18  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/65450
	* tree-vect-data-refs.c (vect_duplicate_ssa_name_ptr_info): New
	function.
	(vect_create_addr_base_for_vector_ref, vect_create_data_ref_ptr): Use
	it instead of duplicate_ssa_name_ptr_info.

	* gfortran.dg/pr65450.f90: New test.

--- gcc/tree-vect-data-refs.c	(revision 221489)
+++ gcc/tree-vect-data-refs.c	(revision 221490)
@@ -3845,6 +3845,20 @@ vect_get_new_vect_var (tree type, enum v
   return new_vect_var;
 }
 
+/* Duplicate ptr info and set alignment/misaligment on NAME from DR.  */
+
+static void
+vect_duplicate_ssa_name_ptr_info (tree name, data_reference *dr,
+				  stmt_vec_info stmt_info)
+{
+  duplicate_ssa_name_ptr_info (name, DR_PTR_INFO (dr));
+  unsigned int align = TYPE_ALIGN_UNIT (STMT_VINFO_VECTYPE (stmt_info));
+  int misalign = DR_MISALIGNMENT (dr);
+  if (misalign == -1)
+    mark_ptr_info_alignment_unknown (SSA_NAME_PTR_INFO (name));
+  else
+    set_ptr_info_alignment (SSA_NAME_PTR_INFO (name), align, misalign);
+}
 
 /* Function vect_create_addr_base_for_vector_ref.
 
@@ -3964,13 +3978,9 @@ vect_create_addr_base_for_vector_ref (gi
   if (DR_PTR_INFO (dr)
       && TREE_CODE (addr_base) == SSA_NAME)
     {
-      duplicate_ssa_name_ptr_info (addr_base, DR_PTR_INFO (dr));
-      unsigned int align = TYPE_ALIGN_UNIT (STMT_VINFO_VECTYPE (stmt_info));
-      int misalign = DR_MISALIGNMENT (dr);
-      if (offset || byte_offset || (misalign == -1))
+      vect_duplicate_ssa_name_ptr_info (addr_base, dr, stmt_info);
+      if (offset || byte_offset)
 	mark_ptr_info_alignment_unknown (SSA_NAME_PTR_INFO (addr_base));
-      else
-	set_ptr_info_alignment (SSA_NAME_PTR_INFO (addr_base), align, misalign);
     }
 
   if (dump_enabled_p ())
@@ -4210,7 +4220,7 @@ vect_create_data_ref_ptr (gimple stmt, t
       aggr_ptr_init = make_ssa_name (aggr_ptr, vec_stmt);
       /* Copy the points-to information if it exists. */
       if (DR_PTR_INFO (dr))
-	duplicate_ssa_name_ptr_info (aggr_ptr_init, DR_PTR_INFO (dr));
+	vect_duplicate_ssa_name_ptr_info (aggr_ptr_init, dr, stmt_info);
       gimple_assign_set_lhs (vec_stmt, aggr_ptr_init);
       if (pe)
 	{
@@ -4253,8 +4263,8 @@ vect_create_data_ref_ptr (gimple stmt, t
       /* Copy the points-to information if it exists. */
       if (DR_PTR_INFO (dr))
 	{
-	  duplicate_ssa_name_ptr_info (indx_before_incr, DR_PTR_INFO (dr));
-	  duplicate_ssa_name_ptr_info (indx_after_incr, DR_PTR_INFO (dr));
+	  vect_duplicate_ssa_name_ptr_info (indx_before_incr, dr, stmt_info);
+	  vect_duplicate_ssa_name_ptr_info (indx_after_incr, dr, stmt_info);
 	}
       if (ptr_incr)
 	*ptr_incr = incr;
@@ -4283,8 +4293,8 @@ vect_create_data_ref_ptr (gimple stmt, t
       /* Copy the points-to information if it exists. */
       if (DR_PTR_INFO (dr))
 	{
-	  duplicate_ssa_name_ptr_info (indx_before_incr, DR_PTR_INFO (dr));
-	  duplicate_ssa_name_ptr_info (indx_after_incr, DR_PTR_INFO (dr));
+	  vect_duplicate_ssa_name_ptr_info (indx_before_incr, dr, stmt_info);
+	  vect_duplicate_ssa_name_ptr_info (indx_after_incr, dr, stmt_info);
 	}
       if (ptr_incr)
 	*ptr_incr = incr;
--- gcc/testsuite/gfortran.dg/pr65450.f90	(revision 0)
+++ gcc/testsuite/gfortran.dg/pr65450.f90	(revision 221490)
@@ -0,0 +1,35 @@
+! PR tree-optimization/65450
+! { dg-do run }
+! { dg-additional-options "-mtune=amdfam10" { target x86_64-*-* i?86-*-* } }
+
+program pr65450
+  integer :: n, m, o, i, k
+  double precision :: u(500,60,3), h(500,60,3)
+  double precision :: v(500,60)
+  u = 0
+  h = 0
+  o = 1
+  m = 2
+  n = 3
+  do k = 1, 50
+    v = foo (u(:,:,m))
+    u(2:499,1:60,n) = u(2:499,1:60,o)+16.d0
+    h(1:500,2:59,n) = h(1:500,2:59,o)-4.d0*v(1:500,2:59)-32.0d0
+    i = o
+    o = m
+    m = n
+    n = i
+  end do
+  if (abs (v(17, 23) + h(17, 23, 2) + 768.0d0) > 0.5d0) call abort
+contains
+  function foo(a)
+    double precision :: a(:,:)
+    double precision :: foo(size(a,dim=1),size(a,dim=2))
+    integer :: i, j
+    i = size(a,dim=1)
+    j = size(a,dim=2)
+    foo(2:i-1,1:j) = a(3:i,1:j)-a(1:i-2,1:j)
+    foo(1,1:j) = 2*(a(2,1:j)-a(1,1:j))
+    foo(i,1:j) = 2*(a(i,1:j)-a(i-1,1:j))
+  end function foo
+end program pr65450
2015-06-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2015-03-19  Jakub Jelinek  <jakub@redhat.com>

	* c-decl.c (c_decl_attributes): Also add "omp declare target"
	attribute for DECL_EXTERNAL VAR_DECLs.

	* decl2.c (cplus_decl_attributes): Also add "omp declare target"
	attribute for DECL_EXTERNAL VAR_DECLs.

	* testsuite/libgomp.c/target-10.c: New test.
	* testsuite/libgomp.c++/target-4.C: New test.

--- gcc/c/c-decl.c	(revision 221519)
+++ gcc/c/c-decl.c	(revision 221520)
@@ -4407,7 +4407,8 @@ c_decl_attributes (tree *node, tree attr
 {
   /* Add implicit "omp declare target" attribute if requested.  */
   if (current_omp_declare_target_attribute
-      && ((TREE_CODE (*node) == VAR_DECL && TREE_STATIC (*node))
+      && ((TREE_CODE (*node) == VAR_DECL
+	   && (TREE_STATIC (*node) || DECL_EXTERNAL (*node)))
 	  || TREE_CODE (*node) == FUNCTION_DECL))
     {
       if (TREE_CODE (*node) == VAR_DECL
--- gcc/cp/decl2.c	(revision 221519)
+++ gcc/cp/decl2.c	(revision 221520)
@@ -1440,7 +1440,8 @@ cplus_decl_attributes (tree *decl, tree
 
   /* Add implicit "omp declare target" attribute if requested.  */
   if (scope_chain->omp_declare_target_attribute
-      && ((TREE_CODE (*decl) == VAR_DECL && TREE_STATIC (*decl))
+      && ((TREE_CODE (*decl) == VAR_DECL
+	   && (TREE_STATIC (*decl) || DECL_EXTERNAL (*decl)))
 	  || TREE_CODE (*decl) == FUNCTION_DECL))
     {
       if (TREE_CODE (*decl) == VAR_DECL
--- libgomp/testsuite/libgomp.c/target-10.c	(revision 0)
+++ libgomp/testsuite/libgomp.c/target-10.c	(revision 221520)
@@ -0,0 +1,14 @@
+/* { dg-do run } */
+
+#pragma omp declare target
+extern int v;
+#pragma omp end declare target
+
+int v;
+
+int
+main ()
+{
+  #pragma omp target update to(v)
+  return 0;
+}
--- libgomp/testsuite/libgomp.c++/target-4.C	(revision 0)
+++ libgomp/testsuite/libgomp.c++/target-4.C	(revision 221520)
@@ -0,0 +1,3 @@
+// { dg-do run }
+
+#include "../libgomp.c/target-10.c"
2015-06-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2015-03-23  Jakub Jelinek  <jakub@redhat.com>

	PR target/65504
	* config/i386/i386.c (ix86_copy_addr_to_reg): Set REG_POINTER
	on the pseudo.
	(expand_set_or_movmem_prologue_epilogue_by_misaligned_moves): Set
	REG_POINTER on *destptr after adjusting it for prologue size.

	* gfortran.dg/pr65504.f90: New test.

--- gcc/config/i386/i386.c	(revision 221596)
+++ gcc/config/i386/i386.c	(revision 221597)
@@ -23457,12 +23457,19 @@ counter_mode (rtx count_exp)
 static rtx
 ix86_copy_addr_to_reg (rtx addr)
 {
+  rtx reg;
   if (GET_MODE (addr) == Pmode || GET_MODE (addr) == VOIDmode)
-    return copy_addr_to_reg (addr);
+    {
+      reg = copy_addr_to_reg (addr);
+      REG_POINTER (reg) = 1;
+      return reg;
+    }
   else
     {
       gcc_assert (GET_MODE (addr) == DImode && Pmode == SImode);
-      return gen_rtx_SUBREG (SImode, copy_to_mode_reg (DImode, addr), 0);
+      reg = copy_to_mode_reg (DImode, addr);
+      REG_POINTER (reg) = 1;
+      return gen_rtx_SUBREG (SImode, reg, 0);
     }
 }
 
@@ -24354,6 +24361,8 @@ expand_set_or_movmem_prologue_epilogue_b
       *destptr = expand_simple_binop (GET_MODE (*destptr), PLUS, *destptr,
 				      GEN_INT (prolog_size),
 				      NULL_RTX, 1, OPTAB_DIRECT);
+      if (REG_P (*destptr) && REG_P (saveddest) && REG_POINTER (saveddest))
+	REG_POINTER (*destptr) = 1;
       *destptr = expand_simple_binop (GET_MODE (*destptr), AND, *destptr,
 				      GEN_INT (-desired_align),
 				      *destptr, 1, OPTAB_DIRECT);
@@ -24363,8 +24372,8 @@ expand_set_or_movmem_prologue_epilogue_b
 				       saveddest, 1, OPTAB_DIRECT);
       /* Adjust srcptr and count.  */
       if (!issetmem)
-	*srcptr = expand_simple_binop (GET_MODE (*srcptr), MINUS, *srcptr, saveddest,
-					*srcptr, 1, OPTAB_DIRECT);
+	*srcptr = expand_simple_binop (GET_MODE (*srcptr), MINUS, *srcptr,
+				       saveddest, *srcptr, 1, OPTAB_DIRECT);
       *count = expand_simple_binop (GET_MODE (*count), PLUS, *count,
 				    saveddest, *count, 1, OPTAB_DIRECT);
       /* We copied at most size + prolog_size.  */
--- gcc/testsuite/gfortran.dg/pr65504.f90	(revision 0)
+++ gcc/testsuite/gfortran.dg/pr65504.f90	(revision 221597)
@@ -0,0 +1,28 @@
+! PR target/65504
+! { dg-do run }
+
+program pr65504
+  implicit none
+  type :: T
+    character (len=256) :: a
+    character (len=256) :: b
+  end type T
+  type (T) :: c
+  type (T) :: d
+  c = foo ("test")
+  d = foo ("test")
+  if (trim(c%b) .ne. "foo") call abort
+  contains
+  type (T) function foo (x) result (v)
+    character(len=*), intent(in) :: x
+    select case (x)
+    case ("test")
+      v%b = 'foo'
+    case ("bazx")
+      v%b = 'barx'
+    case default
+      print *, "unknown"
+      stop
+    end select
+  end function foo
+end program pr65504
2015-06-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2015-03-30  Jakub Jelinek  <jakub@redhat.com>

	PR fortran/65597
	* trans-openmp.c (gfc_trans_omp_do): For !simple simd with explicit
	linear clause for the iterator set OMP_CLAUSE_LINEAR_NO_COPYIN.
	For implcitly added !simple OMP_CLAUSE_LINEAR set it too.  Use step 1
	instead of the original step on the new iterator - count.

	* testsuite/libgomp.fortran/pr65597.f90: New test.

--- gcc/fortran/trans-openmp.c	(revision 221775)
+++ gcc/fortran/trans-openmp.c	(revision 221776)
@@ -3255,6 +3255,19 @@ gfc_trans_omp_do (gfc_code *code, gfc_ex
 	  inits.safe_push (e);
 	}
 
+      if (dovar_found == 2
+	  && op == EXEC_OMP_SIMD
+	  && collapse == 1
+	  && !simple)
+	{
+	  for (tmp = omp_clauses; tmp; tmp = OMP_CLAUSE_CHAIN (tmp))
+	    if (OMP_CLAUSE_CODE (tmp) == OMP_CLAUSE_LINEAR
+		&& OMP_CLAUSE_DECL (tmp) == dovar)
+	      {
+		OMP_CLAUSE_LINEAR_NO_COPYIN (tmp) = 1;
+		break;
+	      }
+	}
       if (!dovar_found)
 	{
 	  if (op == EXEC_OMP_SIMD)
@@ -3263,6 +3276,7 @@ gfc_trans_omp_do (gfc_code *code, gfc_ex
 		{
 		  tmp = build_omp_clause (input_location, OMP_CLAUSE_LINEAR);
 		  OMP_CLAUSE_LINEAR_STEP (tmp) = step;
+		  OMP_CLAUSE_LINEAR_NO_COPYIN (tmp) = 1;
 		}
 	      else
 		tmp = build_omp_clause (input_location, OMP_CLAUSE_LASTPRIVATE);
@@ -3330,7 +3344,7 @@ gfc_trans_omp_do (gfc_code *code, gfc_ex
 	  else if (collapse == 1)
 	    {
 	      tmp = build_omp_clause (input_location, OMP_CLAUSE_LINEAR);
-	      OMP_CLAUSE_LINEAR_STEP (tmp) = step;
+	      OMP_CLAUSE_LINEAR_STEP (tmp) = build_int_cst (type, 1);
 	      OMP_CLAUSE_LINEAR_NO_COPYIN (tmp) = 1;
 	      OMP_CLAUSE_LINEAR_NO_COPYOUT (tmp) = 1;
 	    }
--- libgomp/testsuite/libgomp.fortran/pr65597.f90	(revision 0)
+++ libgomp/testsuite/libgomp.fortran/pr65597.f90	(revision 221776)
@@ -0,0 +1,21 @@
+! PR fortran/65597
+! { dg-do run }
+
+  integer :: i, a(151)
+  a(:) = 0
+  !$omp do simd
+    do i = 1, 151, 31
+      a(i) = a(i) + 1
+    end do
+  !$omp do simd linear (i: 31)
+    do i = 1, 151, 31
+      a(i) = a(i) + 1
+    end do
+  do i = 1, 151
+    if (mod (i, 31) .eq. 1) then
+      if (a(i) .ne. 2) call abort
+    else
+      if (a(i) .ne. 0) call abort
+    end if
+  end do
+end
2015-06-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2015-04-07  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/65680
	* expr.c (get_inner_reference): Handle bit_offset that doesn't fit
	into signed HOST_WIDE_INT the same as negative bit_offset.

	* gcc.c-torture/compile/pr65680.c: New test.

--- gcc/expr.c	(revision 221898)
+++ gcc/expr.c	(revision 221899)
@@ -6873,7 +6873,7 @@ get_inner_reference (tree exp, HOST_WIDE
   if (offset)
     {
       /* Avoid returning a negative bitpos as this may wreak havoc later.  */
-      if (bit_offset.is_negative ())
+      if (bit_offset.is_negative () || !bit_offset.fits_shwi ())
         {
 	  double_int mask
 	    = double_int::mask (BITS_PER_UNIT == 8
--- gcc/testsuite/gcc.c-torture/compile/pr65680.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/compile/pr65680.c	(revision 221899)
@@ -0,0 +1,20 @@
+/* PR middle-end/65680 */
+/* { dg-do compile { target lp64 } } */
+
+struct S
+{
+  int f : 1;
+} a[100000000000000001][3];
+
+void
+foo (void)
+{
+  struct S b = { 0 };
+  a[100000000000000000][0] = b;
+}
+
+void
+bar (void)
+{
+  a[100000000000000000][0].f = 1;
+}
2015-06-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2015-05-04  Jakub Jelinek  <jakub@redhat.com>
 
	PR tree-optimization/65984
	* ubsan.c: Include tree-cfg.h.
	(instrument_bool_enum_load): Use stmt_ends_bb_p instead of
	stmt_could_throw_p test, rename can_throw variable to ends_bb.

	* c-c++-common/ubsan/pr65984.c: New test.

--- gcc/ubsan.c	(revision 222775)
+++ gcc/ubsan.c	(revision 222776)
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3.
 #include "gimplify-me.h"
 #include "intl.h"
 #include "tree-eh.h"
+#include "tree-cfg.h"
 
 /* Map from a tree to a VAR_DECL tree.  */
 
@@ -808,7 +809,7 @@ instrument_bool_enum_load (gimple_stmt_i
       || TREE_CODE (gimple_assign_lhs (stmt)) != SSA_NAME)
     return;
 
-  bool can_throw = stmt_could_throw_p (stmt);
+  bool ends_bb = stmt_ends_bb_p (stmt);
   location_t loc = gimple_location (stmt);
   tree lhs = gimple_assign_lhs (stmt);
   tree ptype = build_pointer_type (TREE_TYPE (rhs));
@@ -820,7 +821,7 @@ instrument_bool_enum_load (gimple_stmt_i
   tree mem = build2 (MEM_REF, utype, gimple_assign_lhs (g),
 		     build_int_cst (atype, 0));
   tree urhs = make_ssa_name (utype, NULL);
-  if (can_throw)
+  if (ends_bb)
     {
       gimple_assign_set_lhs (stmt, urhs);
       g = gimple_build_assign_with_ops (NOP_EXPR, lhs, urhs, NULL_TREE);
@@ -859,7 +860,7 @@ instrument_bool_enum_load (gimple_stmt_i
   gimple_set_location (g, loc);
   gsi_insert_after (gsi, g, GSI_NEW_STMT);
 
-  if (!can_throw)
+  if (!ends_bb)
     {
       gimple_assign_set_rhs_with_ops (&gsi2, NOP_EXPR, urhs, NULL_TREE);
       update_stmt (stmt);
--- gcc/testsuite/c-c++-common/ubsan/pr65984.c	(revision 0)
+++ gcc/testsuite/c-c++-common/ubsan/pr65984.c	(revision 222776)
@@ -0,0 +1,23 @@
+/* PR tree-optimization/65984 */
+/* { dg-do compile } */
+/* { dg-options "-fnon-call-exceptions -fsanitize=bool,enum" } */
+
+#ifndef __cplusplus
+#define bool _Bool
+#endif
+
+enum E { E0, E1, E2 };
+enum E e[2];
+bool *b;
+
+int
+foo (int i)
+{
+  return e[i];
+}
+
+int
+bar (int i)
+{
+  return b[i];
+}
2015-06-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2015-05-13  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/66133
	* omp-low.c (expand_omp_taskreg): For GIMPLE_OMP_TASK expansion,
	make sure it is never noreturn, even when the task body does not
	return.
	(lower_omp_taskreg): For GIMPLE_OMP_TASK, emit GIMPLE_OMP_CONTINUE
	right before GIMPLE_OMP_RETURN.
	(make_gimple_omp_edges): Accept GIMPLE_OMP_CONTINUE as ->cont
	for GIMPLE_OMP_TASK.  For GIMPLE_OMP_RETURN corresponding to
	GIMPLE_OMP_TASK add an EDGE_ABNORMAL edge from entry to exit.

	* testsuite/libgomp.c/pr66133.c: New test.

--- gcc/omp-low.c	(revision 223519)
+++ gcc/omp-low.c	(revision 223520)
@@ -4786,7 +4786,10 @@ expand_omp_taskreg (struct omp_region *r
   child_cfun = DECL_STRUCT_FUNCTION (child_fn);
 
   entry_bb = region->entry;
-  exit_bb = region->exit;
+  if (gimple_code (entry_stmt) == GIMPLE_OMP_TASK)
+    exit_bb = region->cont;
+  else
+    exit_bb = region->exit;
 
   if (is_combined_parallel (region))
     ws_args = region->ws_args;
@@ -4835,7 +4838,9 @@ expand_omp_taskreg (struct omp_region *r
 	 variable.  In which case, we need to keep the assignment.  */
       if (gimple_omp_taskreg_data_arg (entry_stmt))
 	{
-	  basic_block entry_succ_bb = single_succ (entry_bb);
+	  basic_block entry_succ_bb
+	    = single_succ_p (entry_bb) ? single_succ (entry_bb)
+				       : FALLTHRU_EDGE (entry_bb)->dest;
 	  gimple_stmt_iterator gsi;
 	  tree arg, narg;
 	  gimple parcopy_stmt = NULL;
@@ -4924,14 +4929,28 @@ expand_omp_taskreg (struct omp_region *r
       gsi_remove (&gsi, true);
       e = split_block (entry_bb, stmt);
       entry_bb = e->dest;
-      single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
+      edge e2 = NULL;
+      if (gimple_code (entry_stmt) == GIMPLE_OMP_PARALLEL)
+	single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
+      else
+	{
+	  e2 = make_edge (e->src, BRANCH_EDGE (entry_bb)->dest, EDGE_ABNORMAL);
+	  gcc_assert (e2->dest == region->exit);
+	  remove_edge (BRANCH_EDGE (entry_bb));
+	  set_immediate_dominator (CDI_DOMINATORS, e2->dest, e->src);
+	  gsi = gsi_last_bb (region->exit);
+	  gcc_assert (!gsi_end_p (gsi)
+		      && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
+	  gsi_remove (&gsi, true);
+	}
 
-      /* Convert GIMPLE_OMP_RETURN into a RETURN_EXPR.  */
+      /* Convert GIMPLE_OMP_{RETURN,CONTINUE} into a RETURN_EXPR.  */
       if (exit_bb)
 	{
 	  gsi = gsi_last_bb (exit_bb);
 	  gcc_assert (!gsi_end_p (gsi)
-		      && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
+		      && (gimple_code (gsi_stmt (gsi))
+			  == (e2 ? GIMPLE_OMP_CONTINUE : GIMPLE_OMP_RETURN)));
 	  stmt = gimple_build_return (NULL);
 	  gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
 	  gsi_remove (&gsi, true);
@@ -4952,6 +4971,14 @@ expand_omp_taskreg (struct omp_region *r
       new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb, block);
       if (exit_bb)
 	single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
+      if (e2)
+	{
+	  basic_block dest_bb = e2->dest;
+	  if (!exit_bb)
+	    make_edge (new_bb, dest_bb, EDGE_FALLTHRU);
+	  remove_edge (e2);
+	  set_immediate_dominator (CDI_DOMINATORS, dest_bb, new_bb);
+	}
       /* When the OMP expansion process cannot guarantee an up-to-date
          loop tree arrange for the child function to fixup loops.  */
       if (loops_state_satisfies_p (LOOPS_NEED_FIXUP))
@@ -9701,6 +9728,10 @@ lower_omp_taskreg (gimple_stmt_iterator
     gimple_seq_add_stmt (&new_body, gimple_build_label (ctx->cancel_label));
   gimple_seq_add_seq (&new_body, par_olist);
   new_body = maybe_catch_exception (new_body);
+  if (gimple_code (stmt) == GIMPLE_OMP_TASK)
+    gimple_seq_add_stmt (&new_body,
+			 gimple_build_omp_continue (integer_zero_node,
+						    integer_zero_node));
   gimple_seq_add_stmt (&new_body, gimple_build_omp_return (false));
   gimple_omp_set_body (stmt, new_body);
 
@@ -10701,6 +10732,10 @@ make_gimple_omp_edges (basic_block bb, s
 	 somewhere other than the next block.  This will be
 	 created later.  */
       cur_region->exit = bb;
+      if (cur_region->type == GIMPLE_OMP_TASK)
+	/* Add an edge corresponding to not scheduling the task
+	   immediately.  */
+	make_edge (cur_region->entry, bb, EDGE_ABNORMAL);
       fallthru = cur_region->type != GIMPLE_OMP_SECTION;
       cur_region = cur_region->outer;
       break;
@@ -10749,6 +10784,10 @@ make_gimple_omp_edges (basic_block bb, s
 	  }
 	  break;
 
+	case GIMPLE_OMP_TASK:
+	  fallthru = true;
+	  break;
+
 	default:
 	  gcc_unreachable ();
 	}
--- libgomp/testsuite/libgomp.c/pr66133.c	(revision 0)
+++ libgomp/testsuite/libgomp.c/pr66133.c	(revision 223520)
@@ -0,0 +1,35 @@
+/* PR middle-end/66133 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fopenmp" } */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+volatile int x;
+
+__attribute__((noinline)) void
+foo (void)
+{
+  if (x == 0)
+    {
+      #pragma omp task
+	{
+	  usleep (2000);
+	  exit (0);
+	}
+    }
+  else
+    abort ();
+}
+
+int
+main ()
+{
+  #pragma omp parallel num_threads (2)
+    {
+      #pragma omp barrier
+      #pragma omp single
+	foo ();
+    }
+  exit (0);
+}
diff mbox

Patch

--- gcc/tree-eh.c	(revision 220800)
+++ gcc/tree-eh.c	(revision 220801)
@@ -884,10 +884,10 @@  eh_region_may_contain_throw (eh_region r
 /* We want to transform
 	try { body; } catch { stuff; }
    to
-	normal_seqence:
+	normal_sequence:
 	  body;
 	  over:
-	eh_seqence:
+	eh_sequence:
 	  landing_pad:
 	  stuff;
 	  goto over;
@@ -1813,6 +1813,12 @@  lower_catch (struct leh_state *state, gt
   this_state.cur_region = state->cur_region;
   this_state.ehp_region = try_region;
 
+  /* Add eh_seq from lowering EH in the cleanup sequence after the cleanup
+     itself, so that e.g. for coverage purposes the nested cleanups don't
+     appear before the cleanup body.  See PR64634 for details.  */
+  gimple_seq old_eh_seq = eh_seq;
+  eh_seq = NULL;
+
   out_label = NULL;
   cleanup = gimple_try_cleanup (tp);
   for (gsi = gsi_start (cleanup);
@@ -1849,7 +1855,11 @@  lower_catch (struct leh_state *state, gt
 
   gimple_try_set_cleanup (tp, new_seq);
 
-  return frob_into_branch_around (tp, try_region, out_label);
+  gimple_seq new_eh_seq = eh_seq;
+  eh_seq = old_eh_seq;
+  gimple_seq ret_seq = frob_into_branch_around (tp, try_region, out_label);
+  gimple_seq_add_seq (&eh_seq, new_eh_seq);
+  return ret_seq;
 }
 
 /* A subroutine of lower_eh_constructs_1.  Lower a GIMPLE_TRY with a
--- gcc/testsuite/g++.dg/gcov/gcov-15.C	(revision 0)
+++ gcc/testsuite/g++.dg/gcov/gcov-15.C	(revision 220801)
@@ -0,0 +1,26 @@ 
+// PR gcov-profile/64634
+// { dg-options "-fprofile-arcs -ftest-coverage" }
+// { dg-do run { target native } }
+
+void catchEx ()		// count(1)
+{
+  __builtin_exit (0);	// count(1)
+  try
+  {}
+  catch (int)
+  {}
+}
+
+int main ()		// count(1)
+{
+  try
+  {
+    throw 5;		// count(1)
+  }
+  catch (...)		// count(1)
+  {
+    catchEx ();		// count(1)
+  }
+}
+
+// { dg-final { run-gcov gcov-15.C } }