This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Introduce -fwrapp and make -fno-strict-overflow imply it (PR middle-end/82694)


On Fri, 12 Jan 2018, Jakub Jelinek wrote:

> Hi!
> 
> Apparently Linux kernel contains various UB code that has been worked around
> through -fno-strict-overflow in 7.x and before, but when
> POINTER_TYPE_OVERFLOW_UNDEFINED has been removed it now fails to boot.
> 
> The following patch follows the comments in the PR, essentially reverts
> Bin's removal of that, except that it is now controlled by a separate option
> and is included in TYPE_OVERFLOW_{WRAPS,UNDEFINED} macros.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

This is ok with the name of the option/flag changed as suggested
by Martin.

Thanks,
Richard.

> 2018-01-12  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR middle-end/82694
> 	* common.opt (fstrict-overflow): No longer an alias.
> 	(fwrapp): New option.
> 	* tree.h (TYPE_OVERFLOW_WRAPS, TYPE_OVERFLOW_UNDEFINED): Define
> 	also for pointer types based on flag_wrapp.
> 	* opts.c (common_handle_option) <case OPT_fstrict_overflow>: Set
> 	opts->x_flag_wrap[pv] to !value, clear opts->x_flag_trapv if
> 	opts->x_flag_wrapv got set.
> 	* fold-const.c (fold_comparison, fold_binary_loc): Revert 2017-08-01
> 	changes, just use TYPE_OVERFLOW_UNDEFINED on pointer type instead of
> 	POINTER_TYPE_OVERFLOW_UNDEFINED.
> 	* match.pd: Likewise in address comparison pattern.
> 	* doc/invoke.texi: Document -fwrapv and -fstrict-overflow.
> 
> 	* gcc.dg/no-strict-overflow-7.c: Revert 2017-08-01 changes.
> 	* gcc.dg/tree-ssa/pr81388-1.c: Likewise.
> 
> --- gcc/common.opt.jj	2018-01-03 10:19:54.936533922 +0100
> +++ gcc/common.opt	2018-01-12 14:53:28.254485349 +0100
> @@ -2411,8 +2411,8 @@ Common Report Var(flag_strict_aliasing)
>  Assume strict aliasing rules apply.
>  
>  fstrict-overflow
> -Common NegativeAlias Alias(fwrapv)
> -Treat signed overflow as undefined.  Negated as -fwrapv.
> +Common Report
> +Treat signed overflow as undefined.  Negated as -fwrapv -fwrapp.
>  
>  fsync-libcalls
>  Common Report Var(flag_sync_libcalls) Init(1)
> @@ -2860,6 +2860,10 @@ fwhole-program
>  Common Report Var(flag_whole_program) Init(0)
>  Perform whole program optimizations.
>  
> +fwrapp
> +Common Report Var(flag_wrapp) Optimization
> +Assume pointer overflow wraps around.
> +
>  fwrapv
>  Common Report Var(flag_wrapv) Optimization
>  Assume signed arithmetic overflow wraps around.
> --- gcc/tree.h.jj	2018-01-11 18:58:50.993392760 +0100
> +++ gcc/tree.h	2018-01-12 15:04:14.480526788 +0100
> @@ -829,13 +829,16 @@ extern void omp_clause_range_check_faile
>  /* Same as TYPE_UNSIGNED but converted to SIGNOP.  */
>  #define TYPE_SIGN(NODE) ((signop) TYPE_UNSIGNED (NODE))
>  
> -/* True if overflow wraps around for the given integral type.  That
> +/* True if overflow wraps around for the given integral or pointer type.  That
>     is, TYPE_MAX + 1 == TYPE_MIN.  */
>  #define TYPE_OVERFLOW_WRAPS(TYPE) \
> -  (ANY_INTEGRAL_TYPE_CHECK(TYPE)->base.u.bits.unsigned_flag || flag_wrapv)
> +  (POINTER_TYPE_P (TYPE)					\
> +   ? flag_wrapp							\
> +   : (ANY_INTEGRAL_TYPE_CHECK(TYPE)->base.u.bits.unsigned_flag	\
> +      || flag_wrapv))
>  
> -/* True if overflow is undefined for the given integral type.  We may
> -   optimize on the assumption that values in the type never overflow.
> +/* True if overflow is undefined for the given integral or pointer type.
> +   We may optimize on the assumption that values in the type never overflow.
>  
>     IMPORTANT NOTE: Any optimization based on TYPE_OVERFLOW_UNDEFINED
>     must issue a warning based on warn_strict_overflow.  In some cases
> @@ -843,8 +846,10 @@ extern void omp_clause_range_check_faile
>     other cases it will be appropriate to simply set a flag and let the
>     caller decide whether a warning is appropriate or not.  */
>  #define TYPE_OVERFLOW_UNDEFINED(TYPE)				\
> -  (!ANY_INTEGRAL_TYPE_CHECK(TYPE)->base.u.bits.unsigned_flag	\
> -   && !flag_wrapv && !flag_trapv)
> +  (POINTER_TYPE_P (TYPE)					\
> +   ? !flag_wrapp						\
> +   : (!ANY_INTEGRAL_TYPE_CHECK(TYPE)->base.u.bits.unsigned_flag	\
> +      && !flag_wrapv && !flag_trapv))
>  
>  /* True if overflow for the given integral type should issue a
>     trap.  */
> --- gcc/opts.c.jj	2018-01-03 10:19:56.142534113 +0100
> +++ gcc/opts.c	2018-01-12 14:55:06.670494955 +0100
> @@ -2465,6 +2465,13 @@ common_handle_option (struct gcc_options
>  	opts->x_flag_wrapv = 0;
>        break;
>  
> +    case OPT_fstrict_overflow:
> +      opts->x_flag_wrapv = !value;
> +      opts->x_flag_wrapp = !value;
> +      if (!value)
> +	opts->x_flag_trapv = 0;
> +      break;
> +
>      case OPT_fipa_icf:
>        opts->x_flag_ipa_icf_functions = value;
>        opts->x_flag_ipa_icf_variables = value;
> --- gcc/fold-const.c.jj	2018-01-04 22:08:04.394684734 +0100
> +++ gcc/fold-const.c	2018-01-12 15:06:20.040532446 +0100
> @@ -8551,9 +8551,13 @@ fold_comparison (location_t loc, enum tr
>  	{
>  	  /* We can fold this expression to a constant if the non-constant
>  	     offset parts are equal.  */
> -	  if (offset0 == offset1
> -	      || (offset0 && offset1
> -		  && operand_equal_p (offset0, offset1, 0)))
> +	  if ((offset0 == offset1
> +	       || (offset0 && offset1
> +		   && operand_equal_p (offset0, offset1, 0)))
> +	      && (equality_code
> +		  || (indirect_base0
> +		      && (DECL_P (base0) || CONSTANT_CLASS_P (base0)))
> +		  || TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0))))
>  	    {
>  	      if (!equality_code
>  		  && maybe_ne (bitpos0, bitpos1)
> @@ -8612,7 +8616,11 @@ fold_comparison (location_t loc, enum tr
>  	     because pointer arithmetic is restricted to retain within an
>  	     object and overflow on pointer differences is undefined as of
>  	     6.5.6/8 and /9 with respect to the signed ptrdiff_t.  */
> -	  else if (known_eq (bitpos0, bitpos1))
> +	  else if (known_eq (bitpos0, bitpos1)
> +		   && (equality_code
> +		       || (indirect_base0
> +			   && (DECL_P (base0) || CONSTANT_CLASS_P (base0)))
> +		       || TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0))))
>  	    {
>  	      /* By converting to signed sizetype we cover middle-end pointer
>  	         arithmetic which operates on unsigned pointer types of size
> @@ -9721,8 +9729,8 @@ fold_binary_loc (location_t loc, enum tr
>  
>  	  /* With undefined overflow prefer doing association in a type
>  	     which wraps on overflow, if that is one of the operand types.  */
> -	  if (POINTER_TYPE_P (type)
> -	      || (INTEGRAL_TYPE_P (type) && !TYPE_OVERFLOW_WRAPS (type)))
> +	  if ((POINTER_TYPE_P (type) || INTEGRAL_TYPE_P (type))
> +	      && !TYPE_OVERFLOW_WRAPS (type))
>  	    {
>  	      if (INTEGRAL_TYPE_P (TREE_TYPE (arg0))
>  		  && TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0)))
> @@ -9735,8 +9743,8 @@ fold_binary_loc (location_t loc, enum tr
>  
>  	  /* With undefined overflow we can only associate constants with one
>  	     variable, and constants whose association doesn't overflow.  */
> -	  if (POINTER_TYPE_P (atype)
> -	      || (INTEGRAL_TYPE_P (atype) && !TYPE_OVERFLOW_WRAPS (atype)))
> +	  if ((POINTER_TYPE_P (atype) || INTEGRAL_TYPE_P (atype))
> +	      && !TYPE_OVERFLOW_WRAPS (atype))
>  	    {
>  	      if ((var0 && var1) || (minus_var0 && minus_var1))
>  		{
> --- gcc/match.pd.jj	2018-01-09 21:53:38.366577609 +0100
> +++ gcc/match.pd	2018-01-12 16:17:01.677944553 +0100
> @@ -3610,7 +3610,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>  		    || TREE_CODE (base1) == STRING_CST))
>           equal = (base0 == base1);
>       }
> -     (if (equal == 1)
> +     (if (equal == 1
> +	  && (cmp == EQ_EXPR || cmp == NE_EXPR
> +	      /* If the offsets are equal we can ignore overflow.  */
> +	      || known_eq (off0, off1)
> +	      || TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
> +		 /* Or if we compare using pointers to decls or strings.  */
> +	      || (POINTER_TYPE_P (TREE_TYPE (@2))
> +		  && (DECL_P (base0) || TREE_CODE (base0) == STRING_CST))))
>        (switch
>         (if (cmp == EQ_EXPR && (known_eq (off0, off1) || known_ne (off0, off1)))
>  	{ constant_boolean_node (known_eq (off0, off1), type); })
> --- gcc/doc/invoke.texi.jj	2018-01-12 11:36:20.115225557 +0100
> +++ gcc/doc/invoke.texi	2018-01-12 16:14:11.369911474 +0100
> @@ -12576,6 +12576,18 @@ The options @option{-ftrapv} and @option
>  using @option{-ftrapv} @option{-fwrapv} @option{-fno-wrapv} on the command-line
>  results in @option{-ftrapv} being effective.
>  
> +@item -fwrapp
> +@opindex fwrapp
> +This option instructs the compiler to assume that pointer arithmetic
> +overflow on addition and subtraction wraps around using twos-complement
> +representation.  This flag disables some optimizations which assume
> +pointer overflow is invalid.
> +
> +@item -fstrict-overflow
> +@opindex fstrict-overflow
> +This option implies @option{-fno-wrapv} @option{-fno-wrapp} and when negated
> +implies @option{-fwrapv} @option{-fwrapp}.
> +
>  @item -fexceptions
>  @opindex fexceptions
>  Enable exception handling.  Generates extra code needed to propagate
> --- gcc/testsuite/gcc.dg/tree-ssa/pr81388-1.c.jj	2017-08-01 12:14:27.740533590 +0200
> +++ gcc/testsuite/gcc.dg/tree-ssa/pr81388-1.c	2018-01-12 16:22:34.427009184 +0100
> @@ -1,5 +1,5 @@
>  /* { dg-do compile } */
> -/* { dg-options "-O2 -fno-strict-overflow -fdump-tree-tailc-details" } */
> +/* { dg-options "-O2 -fno-strict-overflow -fdump-tree-ivcanon-details" } */
>  
>  void bar();
>  void foo(char *dst)
> @@ -11,6 +11,4 @@ void foo(char *dst)
>    } while (dst < end);
>  }
>  
> -/* The loop only iterates once because pointer overflow always has undefined
> -   semantics.  As a result, call to bar becomes tail call.  */
> -/* { dg-final { scan-tree-dump-times "Found tail call " 1 "tailc" } } */
> +/* { dg-final { scan-tree-dump " zero if " "ivcanon" } } */
> --- gcc/testsuite/gcc.dg/no-strict-overflow-7.c.jj	2017-08-01 12:14:27.941531251 +0200
> +++ gcc/testsuite/gcc.dg/no-strict-overflow-7.c	2018-01-12 16:19:55.224978262 +0100
> @@ -3,8 +3,8 @@
>  
>  /* Source: Ian Lance Taylor.  Dual of strict-overflow-6.c.  */
>  
> -/* We can simplify the conditional because pointer overflow always has
> -   undefined semantics.  */
> +/* We can only simplify the conditional when using strict overflow
> +   semantics.  */
>  
>  int
>  foo (char* p)
> @@ -12,4 +12,4 @@ foo (char* p)
>    return p + 1000 < p;
>  }
>  
> -/* { dg-final { scan-tree-dump "return 0" "optimized" } } */
> +/* { dg-final { scan-tree-dump "\[+\]\[ \]*1000" "optimized" } } */
> 
> 	Jakub
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]