Improve ECF_NOTHROW flags for direct internal functions

Message ID 87k222frr1.fsf@linaro.org
State New
Headers show

Commit Message

Richard Sandiford Aug. 17, 2017, 9:49 a.m.
Internal functions that map directly to an optab can only throw an
exception for -fnon-call-exceptions.  This patch handles that in
internal_fn_flags, in a similar way to ATTR_*NOTHROW in builtins.def.

(Functions that don't throw even for flag_non_call_exceptions should be
explicitly marked ECF_NOTHROW in internal-fn.def.)

Tested on aarch64-linux-gnu and x86_64-linux-gnu.  OK to install?

Richard


2017-08-17  Richard Sandiford  <richard.sandiford@linaro.org>

gcc/
	* internal-fn.h (internal_fn_flags): Just declare and move
	the actual implementation out-of-line to...
	* internal-fn.c (internal_fn_flags): ...here.  Set ECF_NOTHROW for
	directly-mapped internal functions if !flag_non_call_exceptions.

Comments

Richard Biener Aug. 17, 2017, 10:29 a.m. | #1
On Thu, Aug 17, 2017 at 11:49 AM, Richard Sandiford
<richard.sandiford@linaro.org> wrote:
> Internal functions that map directly to an optab can only throw an

> exception for -fnon-call-exceptions.  This patch handles that in

> internal_fn_flags, in a similar way to ATTR_*NOTHROW in builtins.def.

>

> (Functions that don't throw even for flag_non_call_exceptions should be

> explicitly marked ECF_NOTHROW in internal-fn.def.)

>

> Tested on aarch64-linux-gnu and x86_64-linux-gnu.  OK to install?


Hmm.  Note the outcome of flag_non_call_exceptions depends on the
current function and thus IPA passes querying flags would need to
push an appropriate function context.  This means the function should
get a struct function * argument and opt_for_fn (fn, flag_non_call_exceptions)
should be used.  It doesn't help very much that all callers don't have
any such context either which means this "optimization" looks like
in the wrong place :/  (the global value of flag_non_call_exceptions in
the IPA case isn't necessarily conservative).

So if you insist then add a comment and add a && cfun check so
we're sure we are in non-IPA context (or in properly setup context).

Richard.

> Richard

>

>

> 2017-08-17  Richard Sandiford  <richard.sandiford@linaro.org>

>

> gcc/

>         * internal-fn.h (internal_fn_flags): Just declare and move

>         the actual implementation out-of-line to...

>         * internal-fn.c (internal_fn_flags): ...here.  Set ECF_NOTHROW for

>         directly-mapped internal functions if !flag_non_call_exceptions.

>

> Index: gcc/internal-fn.h

> ===================================================================

> --- gcc/internal-fn.h   2017-02-23 19:54:03.000000000 +0000

> +++ gcc/internal-fn.h   2017-08-17 09:05:37.459968561 +0100

> @@ -107,15 +107,7 @@ internal_fn_name (enum internal_fn fn)

>    return internal_fn_name_array[(int) fn];

>  }

>

> -/* Return the ECF_* flags for function FN.  */

> -

> -extern const int internal_fn_flags_array[];

> -

> -static inline int

> -internal_fn_flags (enum internal_fn fn)

> -{

> -  return internal_fn_flags_array[(int) fn];

> -}

> +extern int internal_fn_flags (enum internal_fn fn);

>

>  /* Return fnspec for function FN.  */

>

> Index: gcc/internal-fn.c

> ===================================================================

> --- gcc/internal-fn.c   2017-08-10 14:36:07.453493083 +0100

> +++ gcc/internal-fn.c   2017-08-17 09:05:37.459968561 +0100

> @@ -2814,3 +2814,18 @@ expand_PHI (internal_fn, gcall *)

>  {

>      gcc_unreachable ();

>  }

> +

> +/* Return the ECF_* flags for function FN.  */

> +

> +int

> +internal_fn_flags (enum internal_fn fn)

> +{

> +  int flags = internal_fn_flags_array[(int) fn];

> +  /* Functions that map to optabs can only throw a catchable exception

> +     when non-call exceptions are enabled.  The non-call exceptions in

> +     these cases will typically come from things like IEEE exceptions,

> +     divide by zero errors and SEGVs.  */

> +  if (direct_internal_fn_p (fn) && !flag_non_call_exceptions)

> +    flags |= ECF_NOTHROW;

> +  return flags;

> +}
Richard Sandiford Aug. 17, 2017, 11:06 a.m. | #2
Richard Biener <richard.guenther@gmail.com> writes:
> On Thu, Aug 17, 2017 at 11:49 AM, Richard Sandiford

> <richard.sandiford@linaro.org> wrote:

>> Internal functions that map directly to an optab can only throw an

>> exception for -fnon-call-exceptions.  This patch handles that in

>> internal_fn_flags, in a similar way to ATTR_*NOTHROW in builtins.def.

>>

>> (Functions that don't throw even for flag_non_call_exceptions should be

>> explicitly marked ECF_NOTHROW in internal-fn.def.)

>>

>> Tested on aarch64-linux-gnu and x86_64-linux-gnu.  OK to install?

>

> Hmm.  Note the outcome of flag_non_call_exceptions depends on the

> current function and thus IPA passes querying flags would need to

> push an appropriate function context.  This means the function should

> get a struct function * argument and opt_for_fn (fn, flag_non_call_exceptions)

> should be used.  It doesn't help very much that all callers don't have

> any such context either which means this "optimization" looks like

> in the wrong place :/  (the global value of flag_non_call_exceptions in

> the IPA case isn't necessarily conservative).

>

> So if you insist then add a comment and add a && cfun check so

> we're sure we are in non-IPA context (or in properly setup context).


Bah.  In that case, what should happen if a -fno-non-call-exceptions
function is inlined into an -fnon-call-exceptions one?  Should the call
keep the NOTHROWness of the original function, or should it lose
NOTHROWness (and thus gain an exception edge)?

I guess the path of least resistance would be to add an extra check
for this case in the places that need it, rather than relying solely
on gimple_call_flags.

Thanks,
Richard


>

> Richard.

>

>> Richard

>>

>>

>> 2017-08-17  Richard Sandiford  <richard.sandiford@linaro.org>

>>

>> gcc/

>>         * internal-fn.h (internal_fn_flags): Just declare and move

>>         the actual implementation out-of-line to...

>>         * internal-fn.c (internal_fn_flags): ...here.  Set ECF_NOTHROW for

>>         directly-mapped internal functions if !flag_non_call_exceptions.

>>

>> Index: gcc/internal-fn.h

>> ===================================================================

>> --- gcc/internal-fn.h   2017-02-23 19:54:03.000000000 +0000

>> +++ gcc/internal-fn.h   2017-08-17 09:05:37.459968561 +0100

>> @@ -107,15 +107,7 @@ internal_fn_name (enum internal_fn fn)

>>    return internal_fn_name_array[(int) fn];

>>  }

>>

>> -/* Return the ECF_* flags for function FN.  */

>> -

>> -extern const int internal_fn_flags_array[];

>> -

>> -static inline int

>> -internal_fn_flags (enum internal_fn fn)

>> -{

>> -  return internal_fn_flags_array[(int) fn];

>> -}

>> +extern int internal_fn_flags (enum internal_fn fn);

>>

>>  /* Return fnspec for function FN.  */

>>

>> Index: gcc/internal-fn.c

>> ===================================================================

>> --- gcc/internal-fn.c   2017-08-10 14:36:07.453493083 +0100

>> +++ gcc/internal-fn.c   2017-08-17 09:05:37.459968561 +0100

>> @@ -2814,3 +2814,18 @@ expand_PHI (internal_fn, gcall *)

>>  {

>>      gcc_unreachable ();

>>  }

>> +

>> +/* Return the ECF_* flags for function FN.  */

>> +

>> +int

>> +internal_fn_flags (enum internal_fn fn)

>> +{

>> +  int flags = internal_fn_flags_array[(int) fn];

>> +  /* Functions that map to optabs can only throw a catchable exception

>> +     when non-call exceptions are enabled.  The non-call exceptions in

>> +     these cases will typically come from things like IEEE exceptions,

>> +     divide by zero errors and SEGVs.  */

>> +  if (direct_internal_fn_p (fn) && !flag_non_call_exceptions)

>> +    flags |= ECF_NOTHROW;

>> +  return flags;

>> +}
Richard Biener Aug. 17, 2017, 2:40 p.m. | #3
On Thu, Aug 17, 2017 at 1:06 PM, Richard Sandiford
<richard.sandiford@linaro.org> wrote
> Richard Biener <richard.guenther@gmail.com> writes:

>> On Thu, Aug 17, 2017 at 11:49 AM, Richard Sandiford

>> <richard.sandiford@linaro.org> wrote:

>>> Internal functions that map directly to an optab can only throw an

>>> exception for -fnon-call-exceptions.  This patch handles that in

>>> internal_fn_flags, in a similar way to ATTR_*NOTHROW in builtins.def.

>>>

>>> (Functions that don't throw even for flag_non_call_exceptions should be

>>> explicitly marked ECF_NOTHROW in internal-fn.def.)

>>>

>>> Tested on aarch64-linux-gnu and x86_64-linux-gnu.  OK to install?

>>

>> Hmm.  Note the outcome of flag_non_call_exceptions depends on the

>> current function and thus IPA passes querying flags would need to

>> push an appropriate function context.  This means the function should

>> get a struct function * argument and opt_for_fn (fn, flag_non_call_exceptions)

>> should be used.  It doesn't help very much that all callers don't have

>> any such context either which means this "optimization" looks like

>> in the wrong place :/  (the global value of flag_non_call_exceptions in

>> the IPA case isn't necessarily conservative).

>>

>> So if you insist then add a comment and add a && cfun check so

>> we're sure we are in non-IPA context (or in properly setup context).

>

> Bah.  In that case, what should happen if a -fno-non-call-exceptions

> function is inlined into an -fnon-call-exceptions one?  Should the call

> keep the NOTHROWness of the original function, or should it lose

> NOTHROWness (and thus gain an exception edge)?


nothrow-ness is tracked on the GIMPLE stmt via gimple_call_[set_]nothrow_p,
GIMPLE shouldn't look at flag_non_call_exceptions, it is basically part
of the IL.

> I guess the path of least resistance would be to add an extra check

> for this case in the places that need it, rather than relying solely

> on gimple_call_flags.


Well, gimple_call_flags works fine already (looking at the above in
addition to internal_fn_flags).  call_expr_flags looks like it might not.

Richard.

>

> Thanks,

> Richard

>

>

>>

>> Richard.

>>

>>> Richard

>>>

>>>

>>> 2017-08-17  Richard Sandiford  <richard.sandiford@linaro.org>

>>>

>>> gcc/

>>>         * internal-fn.h (internal_fn_flags): Just declare and move

>>>         the actual implementation out-of-line to...

>>>         * internal-fn.c (internal_fn_flags): ...here.  Set ECF_NOTHROW for

>>>         directly-mapped internal functions if !flag_non_call_exceptions.

>>>

>>> Index: gcc/internal-fn.h

>>> ===================================================================

>>> --- gcc/internal-fn.h   2017-02-23 19:54:03.000000000 +0000

>>> +++ gcc/internal-fn.h   2017-08-17 09:05:37.459968561 +0100

>>> @@ -107,15 +107,7 @@ internal_fn_name (enum internal_fn fn)

>>>    return internal_fn_name_array[(int) fn];

>>>  }

>>>

>>> -/* Return the ECF_* flags for function FN.  */

>>> -

>>> -extern const int internal_fn_flags_array[];

>>> -

>>> -static inline int

>>> -internal_fn_flags (enum internal_fn fn)

>>> -{

>>> -  return internal_fn_flags_array[(int) fn];

>>> -}

>>> +extern int internal_fn_flags (enum internal_fn fn);

>>>

>>>  /* Return fnspec for function FN.  */

>>>

>>> Index: gcc/internal-fn.c

>>> ===================================================================

>>> --- gcc/internal-fn.c   2017-08-10 14:36:07.453493083 +0100

>>> +++ gcc/internal-fn.c   2017-08-17 09:05:37.459968561 +0100

>>> @@ -2814,3 +2814,18 @@ expand_PHI (internal_fn, gcall *)

>>>  {

>>>      gcc_unreachable ();

>>>  }

>>> +

>>> +/* Return the ECF_* flags for function FN.  */

>>> +

>>> +int

>>> +internal_fn_flags (enum internal_fn fn)

>>> +{

>>> +  int flags = internal_fn_flags_array[(int) fn];

>>> +  /* Functions that map to optabs can only throw a catchable exception

>>> +     when non-call exceptions are enabled.  The non-call exceptions in

>>> +     these cases will typically come from things like IEEE exceptions,

>>> +     divide by zero errors and SEGVs.  */

>>> +  if (direct_internal_fn_p (fn) && !flag_non_call_exceptions)

>>> +    flags |= ECF_NOTHROW;

>>> +  return flags;

>>> +}
Richard Sandiford Aug. 28, 2017, 8:16 a.m. | #4
Richard Biener <richard.guenther@gmail.com> writes:
> On Thu, Aug 17, 2017 at 1:06 PM, Richard Sandiford

> <richard.sandiford@linaro.org> wrote

>> Richard Biener <richard.guenther@gmail.com> writes:

>>> On Thu, Aug 17, 2017 at 11:49 AM, Richard Sandiford

>>> <richard.sandiford@linaro.org> wrote:

>>>> Internal functions that map directly to an optab can only throw an

>>>> exception for -fnon-call-exceptions.  This patch handles that in

>>>> internal_fn_flags, in a similar way to ATTR_*NOTHROW in builtins.def.

>>>>

>>>> (Functions that don't throw even for flag_non_call_exceptions should be

>>>> explicitly marked ECF_NOTHROW in internal-fn.def.)

>>>>

>>>> Tested on aarch64-linux-gnu and x86_64-linux-gnu.  OK to install?

>>>

>>> Hmm.  Note the outcome of flag_non_call_exceptions depends on the

>>> current function and thus IPA passes querying flags would need to

>>> push an appropriate function context.  This means the function should

>>> get a struct function * argument and opt_for_fn (fn,

>>> flag_non_call_exceptions)

>>> should be used.  It doesn't help very much that all callers don't have

>>> any such context either which means this "optimization" looks like

>>> in the wrong place :/  (the global value of flag_non_call_exceptions in

>>> the IPA case isn't necessarily conservative).

>>>

>>> So if you insist then add a comment and add a && cfun check so

>>> we're sure we are in non-IPA context (or in properly setup context).

>>

>> Bah.  In that case, what should happen if a -fno-non-call-exceptions

>> function is inlined into an -fnon-call-exceptions one?  Should the call

>> keep the NOTHROWness of the original function, or should it lose

>> NOTHROWness (and thus gain an exception edge)?

>

> nothrow-ness is tracked on the GIMPLE stmt via gimple_call_[set_]nothrow_p,

> GIMPLE shouldn't look at flag_non_call_exceptions, it is basically part

> of the IL.

>

>> I guess the path of least resistance would be to add an extra check

>> for this case in the places that need it, rather than relying solely

>> on gimple_call_flags.

>

> Well, gimple_call_flags works fine already (looking at the above in

> addition to internal_fn_flags).  call_expr_flags looks like it might not.


OK, how does this look?  Only the gimple flags matter for the use
case I've seen (which is covered by the SVE tests, but hard to
test as-is).

Tested on aarch64-linux-gnu and x86_64-linux-gnu.

Thanks,
Richard


2017-08-28  Richard Sandiford  <richard.sandiford@linaro.org>

gcc/
	* gimplify.c (gimplify_call_expr): Copy the nothrow flag to
	calls to internal functions.
	(gimplify_modify_expr): Likewise.
	* tree-call-cdce.c (use_internal_fn): Likewise.
	* tree-ssa-math-opts.c (pass_cse_reciprocals::execute): Likewise.
	(convert_to_divmod): Set the nothrow flag.
	* tree-if-conv.c (predicate_mem_writes):  Likewise.
	* tree-vect-stmts.c (vectorizable_mask_load_store): Likewise.
	(vectorizable_call): Likewise.
	(vectorizable_store): Likewise.
	(vectorizable_load): Likewise.
	* tree-vect-patterns.c (vect_recog_pow_pattern): Likewise.
	(vect_recog_mask_conversion_pattern): Likewise.

Index: gcc/gimplify.c
===================================================================
*** gcc/gimplify.c	2017-08-17 13:17:21.266412322 +0100
--- gcc/gimplify.c	2017-08-28 09:10:13.246297839 +0100
*************** gimplify_call_expr (tree *expr_p, gimple
*** 3150,3156 ****
  
        if (EXPR_CILK_SPAWN (*expr_p))
          gimplify_cilk_detach (pre_p);
!       gimple *call = gimple_build_call_internal_vec (ifn, vargs);
        gimplify_seq_add_stmt (pre_p, call);
        return GS_ALL_DONE;
      }
--- 3150,3157 ----
  
        if (EXPR_CILK_SPAWN (*expr_p))
          gimplify_cilk_detach (pre_p);
!       gcall *call = gimple_build_call_internal_vec (ifn, vargs);
!       gimple_call_set_nothrow (call, TREE_NOTHROW (*expr_p));
        gimplify_seq_add_stmt (pre_p, call);
        return GS_ALL_DONE;
      }
*************** gimplify_modify_expr (tree *expr_p, gimp
*** 5636,5641 ****
--- 5637,5643 ----
  	      vargs.quick_push (CALL_EXPR_ARG (*from_p, i));
  	    }
  	  call_stmt = gimple_build_call_internal_vec (ifn, vargs);
+ 	  gimple_call_set_nothrow (call_stmt, TREE_NOTHROW (*from_p));
  	  gimple_set_location (call_stmt, EXPR_LOCATION (*expr_p));
  	}
        else
Index: gcc/tree-call-cdce.c
===================================================================
*** gcc/tree-call-cdce.c	2017-06-30 12:50:38.243662675 +0100
--- gcc/tree-call-cdce.c	2017-08-28 09:10:13.246297839 +0100
*************** use_internal_fn (gcall *call)
*** 1019,1024 ****
--- 1019,1025 ----
      args.safe_push (gimple_call_arg (call, i));
    gcall *new_call = gimple_build_call_internal_vec (ifn, args);
    gimple_set_location (new_call, gimple_location (call));
+   gimple_call_set_nothrow (new_call, gimple_call_nothrow_p (call));
  
    /* Transfer the LHS to the new call.  */
    tree lhs = gimple_call_lhs (call);
Index: gcc/tree-ssa-math-opts.c
===================================================================
*** gcc/tree-ssa-math-opts.c	2017-08-24 08:46:02.098124751 +0100
--- gcc/tree-ssa-math-opts.c	2017-08-28 09:10:13.247297839 +0100
*************** pass_cse_reciprocals::execute (function
*** 690,695 ****
--- 690,697 ----
  			  gimple_set_vdef (stmt2, gimple_vdef (call));
  			  SSA_NAME_DEF_STMT (gimple_vdef (stmt2)) = stmt2;
  			}
+ 		      gimple_call_set_nothrow (stmt2,
+ 					       gimple_call_nothrow_p (call));
  		      gimple_set_vuse (stmt2, gimple_vuse (call));
  		      gimple_stmt_iterator gsi2 = gsi_for_stmt (call);
  		      gsi_replace (&gsi2, stmt2, true);
*************** convert_to_divmod (gassign *stmt)
*** 4100,4105 ****
--- 4102,4109 ----
    tree res = make_temp_ssa_name (build_complex_type (TREE_TYPE (op1)),
  				 call_stmt, "divmod_tmp");
    gimple_call_set_lhs (call_stmt, res);
+   /* We rejected throwing statements above.  */
+   gimple_call_set_nothrow (call_stmt, true);
  
    /* Insert the call before top_stmt.  */
    gimple_stmt_iterator top_stmt_gsi = gsi_for_stmt (top_stmt);
Index: gcc/tree-if-conv.c
===================================================================
*** gcc/tree-if-conv.c	2017-08-22 17:13:27.429500899 +0100
--- gcc/tree-if-conv.c	2017-08-28 09:10:13.246297839 +0100
*************** predicate_mem_writes (loop_p loop)
*** 2219,2225 ****
  	    tree lhs = gimple_assign_lhs (stmt);
  	    tree rhs = gimple_assign_rhs1 (stmt);
  	    tree ref, addr, ptr, mask;
! 	    gimple *new_stmt;
  	    gimple_seq stmts = NULL;
  	    int bitsize = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (lhs)));
  	    ref = TREE_CODE (lhs) == SSA_NAME ? rhs : lhs;
--- 2219,2225 ----
  	    tree lhs = gimple_assign_lhs (stmt);
  	    tree rhs = gimple_assign_rhs1 (stmt);
  	    tree ref, addr, ptr, mask;
! 	    gcall *new_stmt;
  	    gimple_seq stmts = NULL;
  	    int bitsize = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (lhs)));
  	    ref = TREE_CODE (lhs) == SSA_NAME ? rhs : lhs;
*************** predicate_mem_writes (loop_p loop)
*** 2281,2286 ****
--- 2281,2287 ----
  		gimple_set_vdef (new_stmt, gimple_vdef (stmt));
  		SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
  	      }
+ 	    gimple_call_set_nothrow (new_stmt, true);
  
  	    gsi_replace (&gsi, new_stmt, true);
  	  }
Index: gcc/tree-vect-stmts.c
===================================================================
*** gcc/tree-vect-stmts.c	2017-08-22 17:13:27.429500899 +0100
--- gcc/tree-vect-stmts.c	2017-08-28 09:10:13.248297839 +0100
*************** vectorizable_mask_load_store (gimple *st
*** 2364,2372 ****
  				  misalign);
  	  tree ptr = build_int_cst (TREE_TYPE (gimple_call_arg (stmt, 1)),
  				    misalign ? least_bit_hwi (misalign) : align);
! 	  new_stmt
  	    = gimple_build_call_internal (IFN_MASK_STORE, 4, dataref_ptr,
  					  ptr, vec_mask, vec_rhs);
  	  vect_finish_stmt_generation (stmt, new_stmt, gsi);
  	  if (i == 0)
  	    STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = new_stmt;
--- 2364,2374 ----
  				  misalign);
  	  tree ptr = build_int_cst (TREE_TYPE (gimple_call_arg (stmt, 1)),
  				    misalign ? least_bit_hwi (misalign) : align);
! 	  gcall *call
  	    = gimple_build_call_internal (IFN_MASK_STORE, 4, dataref_ptr,
  					  ptr, vec_mask, vec_rhs);
+ 	  gimple_call_set_nothrow (call, true);
+ 	  new_stmt = call;
  	  vect_finish_stmt_generation (stmt, new_stmt, gsi);
  	  if (i == 0)
  	    STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = new_stmt;
*************** vectorizable_mask_load_store (gimple *st
*** 2414,2429 ****
  				  misalign);
  	  tree ptr = build_int_cst (TREE_TYPE (gimple_call_arg (stmt, 1)),
  				    misalign ? least_bit_hwi (misalign) : align);
! 	  new_stmt
  	    = gimple_build_call_internal (IFN_MASK_LOAD, 3, dataref_ptr,
  					  ptr, vec_mask);
! 	  gimple_call_set_lhs (new_stmt, make_ssa_name (vec_dest));
! 	  vect_finish_stmt_generation (stmt, new_stmt, gsi);
  	  if (i == 0)
! 	    STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = new_stmt;
  	  else
! 	    STMT_VINFO_RELATED_STMT (prev_stmt_info) = new_stmt;
! 	  prev_stmt_info = vinfo_for_stmt (new_stmt);
  	}
      }
  
--- 2416,2432 ----
  				  misalign);
  	  tree ptr = build_int_cst (TREE_TYPE (gimple_call_arg (stmt, 1)),
  				    misalign ? least_bit_hwi (misalign) : align);
! 	  gcall *call
  	    = gimple_build_call_internal (IFN_MASK_LOAD, 3, dataref_ptr,
  					  ptr, vec_mask);
! 	  gimple_call_set_lhs (call, make_ssa_name (vec_dest));
! 	  gimple_call_set_nothrow (call, true);
! 	  vect_finish_stmt_generation (stmt, call, gsi);
  	  if (i == 0)
! 	    STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = call;
  	  else
! 	    STMT_VINFO_RELATED_STMT (prev_stmt_info) = call;
! 	  prev_stmt_info = vinfo_for_stmt (call);
  	}
      }
  
*************** vectorizable_call (gimple *gs, gimple_st
*** 2867,2874 ****
  		  if (modifier == NARROW)
  		    {
  		      tree half_res = make_ssa_name (vectype_in);
! 		      new_stmt = gimple_build_call_internal_vec (ifn, vargs);
! 		      gimple_call_set_lhs (new_stmt, half_res);
  		      vect_finish_stmt_generation (stmt, new_stmt, gsi);
  		      if ((i & 1) == 0)
  			{
--- 2870,2880 ----
  		  if (modifier == NARROW)
  		    {
  		      tree half_res = make_ssa_name (vectype_in);
! 		      gcall *call
! 			= gimple_build_call_internal_vec (ifn, vargs);
! 		      gimple_call_set_lhs (call, half_res);
! 		      gimple_call_set_nothrow (call, true);
! 		      new_stmt = call;
  		      vect_finish_stmt_generation (stmt, new_stmt, gsi);
  		      if ((i & 1) == 0)
  			{
*************** vectorizable_call (gimple *gs, gimple_st
*** 2881,2892 ****
  		    }
  		  else
  		    {
  		      if (ifn != IFN_LAST)
! 			new_stmt = gimple_build_call_internal_vec (ifn, vargs);
  		      else
! 			new_stmt = gimple_build_call_vec (fndecl, vargs);
! 		      new_temp = make_ssa_name (vec_dest, new_stmt);
! 		      gimple_call_set_lhs (new_stmt, new_temp);
  		    }
  		  vect_finish_stmt_generation (stmt, new_stmt, gsi);
  		  SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt);
--- 2887,2901 ----
  		    }
  		  else
  		    {
+ 		      gcall *call;
  		      if (ifn != IFN_LAST)
! 			call = gimple_build_call_internal_vec (ifn, vargs);
  		      else
! 			call = gimple_build_call_vec (fndecl, vargs);
! 		      new_temp = make_ssa_name (vec_dest, call);
! 		      gimple_call_set_lhs (call, new_temp);
! 		      gimple_call_set_nothrow (call, true);
! 		      new_stmt = call;
  		    }
  		  vect_finish_stmt_generation (stmt, new_stmt, gsi);
  		  SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt);
*************** vectorizable_call (gimple *gs, gimple_st
*** 2934,2941 ****
  	  else if (modifier == NARROW)
  	    {
  	      tree half_res = make_ssa_name (vectype_in);
! 	      new_stmt = gimple_build_call_internal_vec (ifn, vargs);
! 	      gimple_call_set_lhs (new_stmt, half_res);
  	      vect_finish_stmt_generation (stmt, new_stmt, gsi);
  	      if ((j & 1) == 0)
  		{
--- 2943,2952 ----
  	  else if (modifier == NARROW)
  	    {
  	      tree half_res = make_ssa_name (vectype_in);
! 	      gcall *call = gimple_build_call_internal_vec (ifn, vargs);
! 	      gimple_call_set_lhs (call, half_res);
! 	      gimple_call_set_nothrow (call, true);
! 	      new_stmt = call;
  	      vect_finish_stmt_generation (stmt, new_stmt, gsi);
  	      if ((j & 1) == 0)
  		{
*************** vectorizable_call (gimple *gs, gimple_st
*** 2948,2959 ****
  	    }
  	  else
  	    {
  	      if (ifn != IFN_LAST)
! 		new_stmt = gimple_build_call_internal_vec (ifn, vargs);
  	      else
! 		new_stmt = gimple_build_call_vec (fndecl, vargs);
  	      new_temp = make_ssa_name (vec_dest, new_stmt);
! 	      gimple_call_set_lhs (new_stmt, new_temp);
  	    }
  	  vect_finish_stmt_generation (stmt, new_stmt, gsi);
  
--- 2959,2973 ----
  	    }
  	  else
  	    {
+ 	      gcall *call;
  	      if (ifn != IFN_LAST)
! 		call = gimple_build_call_internal_vec (ifn, vargs);
  	      else
! 		call = gimple_build_call_vec (fndecl, vargs);
  	      new_temp = make_ssa_name (vec_dest, new_stmt);
! 	      gimple_call_set_lhs (call, new_temp);
! 	      gimple_call_set_nothrow (call, true);
! 	      new_stmt = call;
  	    }
  	  vect_finish_stmt_generation (stmt, new_stmt, gsi);
  
*************** vectorizable_call (gimple *gs, gimple_st
*** 2996,3007 ****
  		      vargs.quick_push (vec_oprndsk[i]);
  		      vargs.quick_push (vec_oprndsk[i + 1]);
  		    }
  		  if (ifn != IFN_LAST)
! 		    new_stmt = gimple_build_call_internal_vec (ifn, vargs);
  		  else
! 		    new_stmt = gimple_build_call_vec (fndecl, vargs);
! 		  new_temp = make_ssa_name (vec_dest, new_stmt);
! 		  gimple_call_set_lhs (new_stmt, new_temp);
  		  vect_finish_stmt_generation (stmt, new_stmt, gsi);
  		  SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt);
  		}
--- 3010,3024 ----
  		      vargs.quick_push (vec_oprndsk[i]);
  		      vargs.quick_push (vec_oprndsk[i + 1]);
  		    }
+ 		  gcall *call;
  		  if (ifn != IFN_LAST)
! 		    call = gimple_build_call_internal_vec (ifn, vargs);
  		  else
! 		    call = gimple_build_call_vec (fndecl, vargs);
! 		  new_temp = make_ssa_name (vec_dest, call);
! 		  gimple_call_set_lhs (call, new_temp);
! 		  gimple_call_set_nothrow (call, true);
! 		  new_stmt = call;
  		  vect_finish_stmt_generation (stmt, new_stmt, gsi);
  		  SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt);
  		}
*************** vectorizable_store (gimple *stmt, gimple
*** 6356,6363 ****
  	  /* Emit:
  	       MEM_REF[...all elements...] = STORE_LANES (VEC_ARRAY).  */
  	  data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type);
! 	  new_stmt = gimple_build_call_internal (IFN_STORE_LANES, 1, vec_array);
! 	  gimple_call_set_lhs (new_stmt, data_ref);
  	  vect_finish_stmt_generation (stmt, new_stmt, gsi);
  	}
        else
--- 6373,6383 ----
  	  /* Emit:
  	       MEM_REF[...all elements...] = STORE_LANES (VEC_ARRAY).  */
  	  data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type);
! 	  gcall *call = gimple_build_call_internal (IFN_STORE_LANES, 1,
! 						    vec_array);
! 	  gimple_call_set_lhs (call, data_ref);
! 	  gimple_call_set_nothrow (call, true);
! 	  new_stmt = call;
  	  vect_finish_stmt_generation (stmt, new_stmt, gsi);
  	}
        else
*************** vectorizable_load (gimple *stmt, gimple_
*** 7448,7455 ****
  	  /* Emit:
  	       VEC_ARRAY = LOAD_LANES (MEM_REF[...all elements...]).  */
  	  data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type);
! 	  new_stmt = gimple_build_call_internal (IFN_LOAD_LANES, 1, data_ref);
! 	  gimple_call_set_lhs (new_stmt, vec_array);
  	  vect_finish_stmt_generation (stmt, new_stmt, gsi);
  
  	  /* Extract each vector into an SSA_NAME.  */
--- 7468,7478 ----
  	  /* Emit:
  	       VEC_ARRAY = LOAD_LANES (MEM_REF[...all elements...]).  */
  	  data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type);
! 	  gcall *call = gimple_build_call_internal (IFN_LOAD_LANES, 1,
! 						    data_ref);
! 	  gimple_call_set_lhs (call, vec_array);
! 	  gimple_call_set_nothrow (call, true);
! 	  new_stmt = call;
  	  vect_finish_stmt_generation (stmt, new_stmt, gsi);
  
  	  /* Extract each vector into an SSA_NAME.  */
Index: gcc/tree-vect-patterns.c
===================================================================
*** gcc/tree-vect-patterns.c	2017-08-21 15:50:48.663709938 +0100
--- gcc/tree-vect-patterns.c	2017-08-28 09:10:13.247297839 +0100
*************** vect_recog_pow_pattern (vec<gimple *> *s
*** 1085,1090 ****
--- 1085,1091 ----
  	  gcall *stmt = gimple_build_call_internal (IFN_SQRT, 1, base);
  	  var = vect_recog_temp_ssa_var (TREE_TYPE (base), stmt);
  	  gimple_call_set_lhs (stmt, var);
+ 	  gimple_call_set_nothrow (stmt, true);
  	  return stmt;
  	}
      }
*************** vect_recog_mask_conversion_pattern (vec<
*** 3867,3873 ****
    stmt_vec_info stmt_vinfo = vinfo_for_stmt (last_stmt);
    stmt_vec_info pattern_stmt_info;
    vec_info *vinfo = stmt_vinfo->vinfo;
-   gimple *pattern_stmt;
  
    /* Check for MASK_LOAD ans MASK_STORE calls requiring mask conversion.  */
    if (is_gimple_call (last_stmt)
--- 3868,3873 ----
*************** vect_recog_mask_conversion_pattern (vec<
*** 3875,3880 ****
--- 3875,3881 ----
        && (gimple_call_internal_fn (last_stmt) == IFN_MASK_STORE
  	  || gimple_call_internal_fn (last_stmt) == IFN_MASK_LOAD))
      {
+       gcall *pattern_stmt;
        bool load = (gimple_call_internal_fn (last_stmt) == IFN_MASK_LOAD);
  
        if (load)
*************** vect_recog_mask_conversion_pattern (vec<
*** 3918,3923 ****
--- 3919,3925 ----
  					  tmp,
  					  gimple_call_arg (last_stmt, 3));
  
+       gimple_call_set_nothrow (pattern_stmt, true);
  
        pattern_stmt_info = new_stmt_vec_info (pattern_stmt, vinfo);
        set_vinfo_for_stmt (pattern_stmt, pattern_stmt_info);
*************** vect_recog_mask_conversion_pattern (vec<
*** 3940,3945 ****
--- 3942,3948 ----
    if (!is_gimple_assign (last_stmt))
      return NULL;
  
+   gimple *pattern_stmt;
    lhs = gimple_assign_lhs (last_stmt);
    rhs1 = gimple_assign_rhs1 (last_stmt);
    rhs_code = gimple_assign_rhs_code (last_stmt);
Richard Biener Aug. 28, 2017, 12:39 p.m. | #5
On Mon, Aug 28, 2017 at 10:16 AM, Richard Sandiford
<richard.sandiford@linaro.org> wrote:
> Richard Biener <richard.guenther@gmail.com> writes:

>> On Thu, Aug 17, 2017 at 1:06 PM, Richard Sandiford

>> <richard.sandiford@linaro.org> wrote

>>> Richard Biener <richard.guenther@gmail.com> writes:

>>>> On Thu, Aug 17, 2017 at 11:49 AM, Richard Sandiford

>>>> <richard.sandiford@linaro.org> wrote:

>>>>> Internal functions that map directly to an optab can only throw an

>>>>> exception for -fnon-call-exceptions.  This patch handles that in

>>>>> internal_fn_flags, in a similar way to ATTR_*NOTHROW in builtins.def.

>>>>>

>>>>> (Functions that don't throw even for flag_non_call_exceptions should be

>>>>> explicitly marked ECF_NOTHROW in internal-fn.def.)

>>>>>

>>>>> Tested on aarch64-linux-gnu and x86_64-linux-gnu.  OK to install?

>>>>

>>>> Hmm.  Note the outcome of flag_non_call_exceptions depends on the

>>>> current function and thus IPA passes querying flags would need to

>>>> push an appropriate function context.  This means the function should

>>>> get a struct function * argument and opt_for_fn (fn,

>>>> flag_non_call_exceptions)

>>>> should be used.  It doesn't help very much that all callers don't have

>>>> any such context either which means this "optimization" looks like

>>>> in the wrong place :/  (the global value of flag_non_call_exceptions in

>>>> the IPA case isn't necessarily conservative).

>>>>

>>>> So if you insist then add a comment and add a && cfun check so

>>>> we're sure we are in non-IPA context (or in properly setup context).

>>>

>>> Bah.  In that case, what should happen if a -fno-non-call-exceptions

>>> function is inlined into an -fnon-call-exceptions one?  Should the call

>>> keep the NOTHROWness of the original function, or should it lose

>>> NOTHROWness (and thus gain an exception edge)?

>>

>> nothrow-ness is tracked on the GIMPLE stmt via gimple_call_[set_]nothrow_p,

>> GIMPLE shouldn't look at flag_non_call_exceptions, it is basically part

>> of the IL.

>>

>>> I guess the path of least resistance would be to add an extra check

>>> for this case in the places that need it, rather than relying solely

>>> on gimple_call_flags.

>>

>> Well, gimple_call_flags works fine already (looking at the above in

>> addition to internal_fn_flags).  call_expr_flags looks like it might not.

>

> OK, how does this look?  Only the gimple flags matter for the use

> case I've seen (which is covered by the SVE tests, but hard to

> test as-is).

>

> Tested on aarch64-linux-gnu and x86_64-linux-gnu.


Ok.

Thanks,
Richard.

> Thanks,

> Richard

>

>

> 2017-08-28  Richard Sandiford  <richard.sandiford@linaro.org>

>

> gcc/

>         * gimplify.c (gimplify_call_expr): Copy the nothrow flag to

>         calls to internal functions.

>         (gimplify_modify_expr): Likewise.

>         * tree-call-cdce.c (use_internal_fn): Likewise.

>         * tree-ssa-math-opts.c (pass_cse_reciprocals::execute): Likewise.

>         (convert_to_divmod): Set the nothrow flag.

>         * tree-if-conv.c (predicate_mem_writes):  Likewise.

>         * tree-vect-stmts.c (vectorizable_mask_load_store): Likewise.

>         (vectorizable_call): Likewise.

>         (vectorizable_store): Likewise.

>         (vectorizable_load): Likewise.

>         * tree-vect-patterns.c (vect_recog_pow_pattern): Likewise.

>         (vect_recog_mask_conversion_pattern): Likewise.

>

> Index: gcc/gimplify.c

> ===================================================================

> *** gcc/gimplify.c      2017-08-17 13:17:21.266412322 +0100

> --- gcc/gimplify.c      2017-08-28 09:10:13.246297839 +0100

> *************** gimplify_call_expr (tree *expr_p, gimple

> *** 3150,3156 ****

>

>         if (EXPR_CILK_SPAWN (*expr_p))

>           gimplify_cilk_detach (pre_p);

> !       gimple *call = gimple_build_call_internal_vec (ifn, vargs);

>         gimplify_seq_add_stmt (pre_p, call);

>         return GS_ALL_DONE;

>       }

> --- 3150,3157 ----

>

>         if (EXPR_CILK_SPAWN (*expr_p))

>           gimplify_cilk_detach (pre_p);

> !       gcall *call = gimple_build_call_internal_vec (ifn, vargs);

> !       gimple_call_set_nothrow (call, TREE_NOTHROW (*expr_p));

>         gimplify_seq_add_stmt (pre_p, call);

>         return GS_ALL_DONE;

>       }

> *************** gimplify_modify_expr (tree *expr_p, gimp

> *** 5636,5641 ****

> --- 5637,5643 ----

>               vargs.quick_push (CALL_EXPR_ARG (*from_p, i));

>             }

>           call_stmt = gimple_build_call_internal_vec (ifn, vargs);

> +         gimple_call_set_nothrow (call_stmt, TREE_NOTHROW (*from_p));

>           gimple_set_location (call_stmt, EXPR_LOCATION (*expr_p));

>         }

>         else

> Index: gcc/tree-call-cdce.c

> ===================================================================

> *** gcc/tree-call-cdce.c        2017-06-30 12:50:38.243662675 +0100

> --- gcc/tree-call-cdce.c        2017-08-28 09:10:13.246297839 +0100

> *************** use_internal_fn (gcall *call)

> *** 1019,1024 ****

> --- 1019,1025 ----

>       args.safe_push (gimple_call_arg (call, i));

>     gcall *new_call = gimple_build_call_internal_vec (ifn, args);

>     gimple_set_location (new_call, gimple_location (call));

> +   gimple_call_set_nothrow (new_call, gimple_call_nothrow_p (call));

>

>     /* Transfer the LHS to the new call.  */

>     tree lhs = gimple_call_lhs (call);

> Index: gcc/tree-ssa-math-opts.c

> ===================================================================

> *** gcc/tree-ssa-math-opts.c    2017-08-24 08:46:02.098124751 +0100

> --- gcc/tree-ssa-math-opts.c    2017-08-28 09:10:13.247297839 +0100

> *************** pass_cse_reciprocals::execute (function

> *** 690,695 ****

> --- 690,697 ----

>                           gimple_set_vdef (stmt2, gimple_vdef (call));

>                           SSA_NAME_DEF_STMT (gimple_vdef (stmt2)) = stmt2;

>                         }

> +                     gimple_call_set_nothrow (stmt2,

> +                                              gimple_call_nothrow_p (call));

>                       gimple_set_vuse (stmt2, gimple_vuse (call));

>                       gimple_stmt_iterator gsi2 = gsi_for_stmt (call);

>                       gsi_replace (&gsi2, stmt2, true);

> *************** convert_to_divmod (gassign *stmt)

> *** 4100,4105 ****

> --- 4102,4109 ----

>     tree res = make_temp_ssa_name (build_complex_type (TREE_TYPE (op1)),

>                                  call_stmt, "divmod_tmp");

>     gimple_call_set_lhs (call_stmt, res);

> +   /* We rejected throwing statements above.  */

> +   gimple_call_set_nothrow (call_stmt, true);

>

>     /* Insert the call before top_stmt.  */

>     gimple_stmt_iterator top_stmt_gsi = gsi_for_stmt (top_stmt);

> Index: gcc/tree-if-conv.c

> ===================================================================

> *** gcc/tree-if-conv.c  2017-08-22 17:13:27.429500899 +0100

> --- gcc/tree-if-conv.c  2017-08-28 09:10:13.246297839 +0100

> *************** predicate_mem_writes (loop_p loop)

> *** 2219,2225 ****

>             tree lhs = gimple_assign_lhs (stmt);

>             tree rhs = gimple_assign_rhs1 (stmt);

>             tree ref, addr, ptr, mask;

> !           gimple *new_stmt;

>             gimple_seq stmts = NULL;

>             int bitsize = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (lhs)));

>             ref = TREE_CODE (lhs) == SSA_NAME ? rhs : lhs;

> --- 2219,2225 ----

>             tree lhs = gimple_assign_lhs (stmt);

>             tree rhs = gimple_assign_rhs1 (stmt);

>             tree ref, addr, ptr, mask;

> !           gcall *new_stmt;

>             gimple_seq stmts = NULL;

>             int bitsize = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (lhs)));

>             ref = TREE_CODE (lhs) == SSA_NAME ? rhs : lhs;

> *************** predicate_mem_writes (loop_p loop)

> *** 2281,2286 ****

> --- 2281,2287 ----

>                 gimple_set_vdef (new_stmt, gimple_vdef (stmt));

>                 SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;

>               }

> +           gimple_call_set_nothrow (new_stmt, true);

>

>             gsi_replace (&gsi, new_stmt, true);

>           }

> Index: gcc/tree-vect-stmts.c

> ===================================================================

> *** gcc/tree-vect-stmts.c       2017-08-22 17:13:27.429500899 +0100

> --- gcc/tree-vect-stmts.c       2017-08-28 09:10:13.248297839 +0100

> *************** vectorizable_mask_load_store (gimple *st

> *** 2364,2372 ****

>                                   misalign);

>           tree ptr = build_int_cst (TREE_TYPE (gimple_call_arg (stmt, 1)),

>                                     misalign ? least_bit_hwi (misalign) : align);

> !         new_stmt

>             = gimple_build_call_internal (IFN_MASK_STORE, 4, dataref_ptr,

>                                           ptr, vec_mask, vec_rhs);

>           vect_finish_stmt_generation (stmt, new_stmt, gsi);

>           if (i == 0)

>             STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = new_stmt;

> --- 2364,2374 ----

>                                   misalign);

>           tree ptr = build_int_cst (TREE_TYPE (gimple_call_arg (stmt, 1)),

>                                     misalign ? least_bit_hwi (misalign) : align);

> !         gcall *call

>             = gimple_build_call_internal (IFN_MASK_STORE, 4, dataref_ptr,

>                                           ptr, vec_mask, vec_rhs);

> +         gimple_call_set_nothrow (call, true);

> +         new_stmt = call;

>           vect_finish_stmt_generation (stmt, new_stmt, gsi);

>           if (i == 0)

>             STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = new_stmt;

> *************** vectorizable_mask_load_store (gimple *st

> *** 2414,2429 ****

>                                   misalign);

>           tree ptr = build_int_cst (TREE_TYPE (gimple_call_arg (stmt, 1)),

>                                     misalign ? least_bit_hwi (misalign) : align);

> !         new_stmt

>             = gimple_build_call_internal (IFN_MASK_LOAD, 3, dataref_ptr,

>                                           ptr, vec_mask);

> !         gimple_call_set_lhs (new_stmt, make_ssa_name (vec_dest));

> !         vect_finish_stmt_generation (stmt, new_stmt, gsi);

>           if (i == 0)

> !           STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = new_stmt;

>           else

> !           STMT_VINFO_RELATED_STMT (prev_stmt_info) = new_stmt;

> !         prev_stmt_info = vinfo_for_stmt (new_stmt);

>         }

>       }

>

> --- 2416,2432 ----

>                                   misalign);

>           tree ptr = build_int_cst (TREE_TYPE (gimple_call_arg (stmt, 1)),

>                                     misalign ? least_bit_hwi (misalign) : align);

> !         gcall *call

>             = gimple_build_call_internal (IFN_MASK_LOAD, 3, dataref_ptr,

>                                           ptr, vec_mask);

> !         gimple_call_set_lhs (call, make_ssa_name (vec_dest));

> !         gimple_call_set_nothrow (call, true);

> !         vect_finish_stmt_generation (stmt, call, gsi);

>           if (i == 0)

> !           STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = call;

>           else

> !           STMT_VINFO_RELATED_STMT (prev_stmt_info) = call;

> !         prev_stmt_info = vinfo_for_stmt (call);

>         }

>       }

>

> *************** vectorizable_call (gimple *gs, gimple_st

> *** 2867,2874 ****

>                   if (modifier == NARROW)

>                     {

>                       tree half_res = make_ssa_name (vectype_in);

> !                     new_stmt = gimple_build_call_internal_vec (ifn, vargs);

> !                     gimple_call_set_lhs (new_stmt, half_res);

>                       vect_finish_stmt_generation (stmt, new_stmt, gsi);

>                       if ((i & 1) == 0)

>                         {

> --- 2870,2880 ----

>                   if (modifier == NARROW)

>                     {

>                       tree half_res = make_ssa_name (vectype_in);

> !                     gcall *call

> !                       = gimple_build_call_internal_vec (ifn, vargs);

> !                     gimple_call_set_lhs (call, half_res);

> !                     gimple_call_set_nothrow (call, true);

> !                     new_stmt = call;

>                       vect_finish_stmt_generation (stmt, new_stmt, gsi);

>                       if ((i & 1) == 0)

>                         {

> *************** vectorizable_call (gimple *gs, gimple_st

> *** 2881,2892 ****

>                     }

>                   else

>                     {

>                       if (ifn != IFN_LAST)

> !                       new_stmt = gimple_build_call_internal_vec (ifn, vargs);

>                       else

> !                       new_stmt = gimple_build_call_vec (fndecl, vargs);

> !                     new_temp = make_ssa_name (vec_dest, new_stmt);

> !                     gimple_call_set_lhs (new_stmt, new_temp);

>                     }

>                   vect_finish_stmt_generation (stmt, new_stmt, gsi);

>                   SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt);

> --- 2887,2901 ----

>                     }

>                   else

>                     {

> +                     gcall *call;

>                       if (ifn != IFN_LAST)

> !                       call = gimple_build_call_internal_vec (ifn, vargs);

>                       else

> !                       call = gimple_build_call_vec (fndecl, vargs);

> !                     new_temp = make_ssa_name (vec_dest, call);

> !                     gimple_call_set_lhs (call, new_temp);

> !                     gimple_call_set_nothrow (call, true);

> !                     new_stmt = call;

>                     }

>                   vect_finish_stmt_generation (stmt, new_stmt, gsi);

>                   SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt);

> *************** vectorizable_call (gimple *gs, gimple_st

> *** 2934,2941 ****

>           else if (modifier == NARROW)

>             {

>               tree half_res = make_ssa_name (vectype_in);

> !             new_stmt = gimple_build_call_internal_vec (ifn, vargs);

> !             gimple_call_set_lhs (new_stmt, half_res);

>               vect_finish_stmt_generation (stmt, new_stmt, gsi);

>               if ((j & 1) == 0)

>                 {

> --- 2943,2952 ----

>           else if (modifier == NARROW)

>             {

>               tree half_res = make_ssa_name (vectype_in);

> !             gcall *call = gimple_build_call_internal_vec (ifn, vargs);

> !             gimple_call_set_lhs (call, half_res);

> !             gimple_call_set_nothrow (call, true);

> !             new_stmt = call;

>               vect_finish_stmt_generation (stmt, new_stmt, gsi);

>               if ((j & 1) == 0)

>                 {

> *************** vectorizable_call (gimple *gs, gimple_st

> *** 2948,2959 ****

>             }

>           else

>             {

>               if (ifn != IFN_LAST)

> !               new_stmt = gimple_build_call_internal_vec (ifn, vargs);

>               else

> !               new_stmt = gimple_build_call_vec (fndecl, vargs);

>               new_temp = make_ssa_name (vec_dest, new_stmt);

> !             gimple_call_set_lhs (new_stmt, new_temp);

>             }

>           vect_finish_stmt_generation (stmt, new_stmt, gsi);

>

> --- 2959,2973 ----

>             }

>           else

>             {

> +             gcall *call;

>               if (ifn != IFN_LAST)

> !               call = gimple_build_call_internal_vec (ifn, vargs);

>               else

> !               call = gimple_build_call_vec (fndecl, vargs);

>               new_temp = make_ssa_name (vec_dest, new_stmt);

> !             gimple_call_set_lhs (call, new_temp);

> !             gimple_call_set_nothrow (call, true);

> !             new_stmt = call;

>             }

>           vect_finish_stmt_generation (stmt, new_stmt, gsi);

>

> *************** vectorizable_call (gimple *gs, gimple_st

> *** 2996,3007 ****

>                       vargs.quick_push (vec_oprndsk[i]);

>                       vargs.quick_push (vec_oprndsk[i + 1]);

>                     }

>                   if (ifn != IFN_LAST)

> !                   new_stmt = gimple_build_call_internal_vec (ifn, vargs);

>                   else

> !                   new_stmt = gimple_build_call_vec (fndecl, vargs);

> !                 new_temp = make_ssa_name (vec_dest, new_stmt);

> !                 gimple_call_set_lhs (new_stmt, new_temp);

>                   vect_finish_stmt_generation (stmt, new_stmt, gsi);

>                   SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt);

>                 }

> --- 3010,3024 ----

>                       vargs.quick_push (vec_oprndsk[i]);

>                       vargs.quick_push (vec_oprndsk[i + 1]);

>                     }

> +                 gcall *call;

>                   if (ifn != IFN_LAST)

> !                   call = gimple_build_call_internal_vec (ifn, vargs);

>                   else

> !                   call = gimple_build_call_vec (fndecl, vargs);

> !                 new_temp = make_ssa_name (vec_dest, call);

> !                 gimple_call_set_lhs (call, new_temp);

> !                 gimple_call_set_nothrow (call, true);

> !                 new_stmt = call;

>                   vect_finish_stmt_generation (stmt, new_stmt, gsi);

>                   SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt);

>                 }

> *************** vectorizable_store (gimple *stmt, gimple

> *** 6356,6363 ****

>           /* Emit:

>                MEM_REF[...all elements...] = STORE_LANES (VEC_ARRAY).  */

>           data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type);

> !         new_stmt = gimple_build_call_internal (IFN_STORE_LANES, 1, vec_array);

> !         gimple_call_set_lhs (new_stmt, data_ref);

>           vect_finish_stmt_generation (stmt, new_stmt, gsi);

>         }

>         else

> --- 6373,6383 ----

>           /* Emit:

>                MEM_REF[...all elements...] = STORE_LANES (VEC_ARRAY).  */

>           data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type);

> !         gcall *call = gimple_build_call_internal (IFN_STORE_LANES, 1,

> !                                                   vec_array);

> !         gimple_call_set_lhs (call, data_ref);

> !         gimple_call_set_nothrow (call, true);

> !         new_stmt = call;

>           vect_finish_stmt_generation (stmt, new_stmt, gsi);

>         }

>         else

> *************** vectorizable_load (gimple *stmt, gimple_

> *** 7448,7455 ****

>           /* Emit:

>                VEC_ARRAY = LOAD_LANES (MEM_REF[...all elements...]).  */

>           data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type);

> !         new_stmt = gimple_build_call_internal (IFN_LOAD_LANES, 1, data_ref);

> !         gimple_call_set_lhs (new_stmt, vec_array);

>           vect_finish_stmt_generation (stmt, new_stmt, gsi);

>

>           /* Extract each vector into an SSA_NAME.  */

> --- 7468,7478 ----

>           /* Emit:

>                VEC_ARRAY = LOAD_LANES (MEM_REF[...all elements...]).  */

>           data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type);

> !         gcall *call = gimple_build_call_internal (IFN_LOAD_LANES, 1,

> !                                                   data_ref);

> !         gimple_call_set_lhs (call, vec_array);

> !         gimple_call_set_nothrow (call, true);

> !         new_stmt = call;

>           vect_finish_stmt_generation (stmt, new_stmt, gsi);

>

>           /* Extract each vector into an SSA_NAME.  */

> Index: gcc/tree-vect-patterns.c

> ===================================================================

> *** gcc/tree-vect-patterns.c    2017-08-21 15:50:48.663709938 +0100

> --- gcc/tree-vect-patterns.c    2017-08-28 09:10:13.247297839 +0100

> *************** vect_recog_pow_pattern (vec<gimple *> *s

> *** 1085,1090 ****

> --- 1085,1091 ----

>           gcall *stmt = gimple_build_call_internal (IFN_SQRT, 1, base);

>           var = vect_recog_temp_ssa_var (TREE_TYPE (base), stmt);

>           gimple_call_set_lhs (stmt, var);

> +         gimple_call_set_nothrow (stmt, true);

>           return stmt;

>         }

>       }

> *************** vect_recog_mask_conversion_pattern (vec<

> *** 3867,3873 ****

>     stmt_vec_info stmt_vinfo = vinfo_for_stmt (last_stmt);

>     stmt_vec_info pattern_stmt_info;

>     vec_info *vinfo = stmt_vinfo->vinfo;

> -   gimple *pattern_stmt;

>

>     /* Check for MASK_LOAD ans MASK_STORE calls requiring mask conversion.  */

>     if (is_gimple_call (last_stmt)

> --- 3868,3873 ----

> *************** vect_recog_mask_conversion_pattern (vec<

> *** 3875,3880 ****

> --- 3875,3881 ----

>         && (gimple_call_internal_fn (last_stmt) == IFN_MASK_STORE

>           || gimple_call_internal_fn (last_stmt) == IFN_MASK_LOAD))

>       {

> +       gcall *pattern_stmt;

>         bool load = (gimple_call_internal_fn (last_stmt) == IFN_MASK_LOAD);

>

>         if (load)

> *************** vect_recog_mask_conversion_pattern (vec<

> *** 3918,3923 ****

> --- 3919,3925 ----

>                                           tmp,

>                                           gimple_call_arg (last_stmt, 3));

>

> +       gimple_call_set_nothrow (pattern_stmt, true);

>

>         pattern_stmt_info = new_stmt_vec_info (pattern_stmt, vinfo);

>         set_vinfo_for_stmt (pattern_stmt, pattern_stmt_info);

> *************** vect_recog_mask_conversion_pattern (vec<

> *** 3940,3945 ****

> --- 3942,3948 ----

>     if (!is_gimple_assign (last_stmt))

>       return NULL;

>

> +   gimple *pattern_stmt;

>     lhs = gimple_assign_lhs (last_stmt);

>     rhs1 = gimple_assign_rhs1 (last_stmt);

>     rhs_code = gimple_assign_rhs_code (last_stmt);

Patch

Index: gcc/internal-fn.h
===================================================================
--- gcc/internal-fn.h	2017-02-23 19:54:03.000000000 +0000
+++ gcc/internal-fn.h	2017-08-17 09:05:37.459968561 +0100
@@ -107,15 +107,7 @@  internal_fn_name (enum internal_fn fn)
   return internal_fn_name_array[(int) fn];
 }
 
-/* Return the ECF_* flags for function FN.  */
-
-extern const int internal_fn_flags_array[];
-
-static inline int
-internal_fn_flags (enum internal_fn fn)
-{
-  return internal_fn_flags_array[(int) fn];
-}
+extern int internal_fn_flags (enum internal_fn fn);
 
 /* Return fnspec for function FN.  */
 
Index: gcc/internal-fn.c
===================================================================
--- gcc/internal-fn.c	2017-08-10 14:36:07.453493083 +0100
+++ gcc/internal-fn.c	2017-08-17 09:05:37.459968561 +0100
@@ -2814,3 +2814,18 @@  expand_PHI (internal_fn, gcall *)
 {
     gcc_unreachable ();
 }
+
+/* Return the ECF_* flags for function FN.  */
+
+int
+internal_fn_flags (enum internal_fn fn)
+{
+  int flags = internal_fn_flags_array[(int) fn];
+  /* Functions that map to optabs can only throw a catchable exception
+     when non-call exceptions are enabled.  The non-call exceptions in
+     these cases will typically come from things like IEEE exceptions,
+     divide by zero errors and SEGVs.  */
+  if (direct_internal_fn_p (fn) && !flag_non_call_exceptions)
+    flags |= ECF_NOTHROW;
+  return flags;
+}