From: eggert@twinsun.COM (Paul Eggert)
Subject: GCC 2.2.2 patch to improve quality of code for (expr&const)!=0
Organization: GNUs Not Usenet
Distribution: gnu
Date: Tue, 1 Sep 1992 23:10:58 GMT

The following patch uniformly improves the quality of the generated code for
for all programs that I have looked at on my machine (Sparc, SunOS 4.1.2);
this includes the entire GCC source code.  For example, given the program

	void f() { if (g() & 32768) h(); }

the patched GCC generates two fewer machine instructions by avoiding an
unnecessary shift and compare, as follows (diff --side-by-side output):

----- GCC 2.2.2 -----			----- GCC 2.2.2 with patch -----
_f:					_f:
	save %sp,-112,%sp			save %sp,-112,%sp
	call _g,0				call _g,0
	nop					nop
	sethi %hi(-32768),%o1	      |		sethi %hi(32768),%o1
	and %o0,%o1,%o0		      |		andcc %o0,%o1,%g0
	sll %o0,16,%o0		      <
	cmp %o0,0		      <
	be L2					be L2
	nop					nop
	call _h,0				call _h,0
	nop					nop
L2:					L2:
	ret					ret
	restore					restore


I'm fairly sure the patch does not introduce a compiler bug on any 2's
complement host, but I'm not sure whether it leads to better quality code on
all hosts.  If this patch loses on some hosts, perhaps a configuration
variable is needed to include it conditionally.


Tue Sep  1 22:55:59 1992  Paul Eggert  (eggert@twinsun.com)

	* c-convert.c, cp-cvt.c (convert_to_integer): Prefer unsigned
	arithmetic if the output type is unsigned and is no more precise than
	the computation type.  This avoids unnecessary sign extension.

===================================================================
RCS file: c-convert.c,v
retrieving revision 2.2
diff -c -r2.2 c-convert.c
*** c-convert.c	1992/04/21 18:00:03	2.2
--- c-convert.c	1992/09/01 22:55:59
***************
*** 232,242 ****
  		  {
  		    /* Don't do unsigned arithmetic where signed was wanted,
  		       or vice versa.
! 		       Exception: if either of the original operands were
  		       unsigned then can safely do the work as unsigned.
  		       And we may need to do it as unsigned
  		       if we truncate to the original size.  */
! 		    typex = ((TREE_UNSIGNED (TREE_TYPE (expr))
  			      || TREE_UNSIGNED (TREE_TYPE (arg0))
  			      || TREE_UNSIGNED (TREE_TYPE (arg1)))
  			     ? unsigned_type (typex) : signed_type (typex));
--- 232,247 ----
  		  {
  		    /* Don't do unsigned arithmetic where signed was wanted,
  		       or vice versa.
! 		       Exception 1: if we will eventually truncate
! 		       the result to unsigned, then do the work as unsigned;
! 		       this can prevent unnecessary sign-extension.
! 		       Exception 2: if either of the original operands were
  		       unsigned then can safely do the work as unsigned.
  		       And we may need to do it as unsigned
  		       if we truncate to the original size.  */
! 		    typex = (((outprec <= TYPE_PRECISION (typex)
! 			       && TREE_UNSIGNED (type))
! 			      || TREE_UNSIGNED (TREE_TYPE (expr))
  			      || TREE_UNSIGNED (TREE_TYPE (arg0))
  			      || TREE_UNSIGNED (TREE_TYPE (arg1)))
  			     ? unsigned_type (typex) : signed_type (typex));
***************
*** 284,290 ****
  	      {
  		/* Don't do unsigned arithmetic where signed was wanted,
  		   or vice versa.  */
! 		typex = (TREE_UNSIGNED (TREE_TYPE (expr))
  			 ? unsigned_type (typex) : signed_type (typex));
  		return convert (type,
  				build_unary_op (ex_form,
--- 289,297 ----
  	      {
  		/* Don't do unsigned arithmetic where signed was wanted,
  		   or vice versa.  */
! 		typex = (((outprec <= TYPE_PRECISION (typex)
! 			   && TREE_UNSIGNED (type))
! 			  || TREE_UNSIGNED (TREE_TYPE (expr)))
  			 ? unsigned_type (typex) : signed_type (typex));
  		return convert (type,
  				build_unary_op (ex_form,
***************
*** 327,333 ****
  		  {
  		    /* Don't do unsigned arithmetic where signed was wanted,
  		       or vice versa.  */
! 		    typex = (TREE_UNSIGNED (TREE_TYPE (expr))
  			     ? unsigned_type (typex) : signed_type (typex));
  		    return convert (type,
  				    fold (build (COND_EXPR, typex,
--- 334,342 ----
  		  {
  		    /* Don't do unsigned arithmetic where signed was wanted,
  		       or vice versa.  */
! 		    typex = (((outprec <= TYPE_PRECISION (typex)
! 			       && TREE_UNSIGNED (type))
! 			      || TREE_UNSIGNED (TREE_TYPE (expr)))
  			     ? unsigned_type (typex) : signed_type (typex));
  		    return convert (type,
  				    fold (build (COND_EXPR, typex,
===================================================================
RCS file: cp-cvt.c,v
retrieving revision 2.2
diff -c -r2.2 cp-cvt.c
*** cp-cvt.c	1992/04/23 03:18:58	2.2
--- cp-cvt.c	1992/09/01 22:56:05
***************
*** 831,842 ****
  		  {
  		    /* Don't do unsigned arithmetic where signed was wanted,
  		       or vice versa.
! 		       Exception: if the original operands were unsigned
! 		       then can safely do the work as unsigned.
  		       And we may need to do it as unsigned
  		       if we truncate to the original size.  */
! 		    typex = ((TREE_UNSIGNED (TREE_TYPE (expr))
! 			      || TREE_UNSIGNED (TREE_TYPE (arg0)))
  			     ? unsigned_type (typex) : signed_type (typex));
  		    return convert (type,
  				    build_binary_op_nodefault (ex_form,
--- 831,848 ----
  		  {
  		    /* Don't do unsigned arithmetic where signed was wanted,
  		       or vice versa.
! 		       Exception 1: if we will eventually truncate
! 		       the result, then do the work as unsigned;
! 		       this can prevent unnecessary sign-extension.
! 		       Exception 2: if either of the original operands were
! 		       unsigned then can safely do the work as unsigned.
  		       And we may need to do it as unsigned
  		       if we truncate to the original size.  */
! 		    typex = (((outprec <= TYPE_PRECISION (typex)
! 			       && TREE_UNSIGNED (type))
! 			      || TREE_UNSIGNED (TREE_TYPE (expr))
! 			      || TREE_UNSIGNED (TREE_TYPE (arg0))
! 			      || TREE_UNSIGNED (TREE_TYPE (arg1)))
  			     ? unsigned_type (typex) : signed_type (typex));
  		    return convert (type,
  				    build_binary_op_nodefault (ex_form,
***************
*** 883,889 ****
  	      {
  		/* Don't do unsigned arithmetic where signed was wanted,
  		   or vice versa.  */
! 		typex = (TREE_UNSIGNED (TREE_TYPE (expr))
  			 ? unsigned_type (typex) : signed_type (typex));
  		return convert (type,
  				build_unary_op (ex_form,
--- 889,897 ----
  	      {
  		/* Don't do unsigned arithmetic where signed was wanted,
  		   or vice versa.  */
! 		typex = (((outprec <= TYPE_PRECISION (typex)
! 			   && TREE_UNSIGNED (type))
! 			  || TREE_UNSIGNED (TREE_TYPE (expr)))
  			 ? unsigned_type (typex) : signed_type (typex));
  		return convert (type,
  				build_unary_op (ex_form,
***************
*** 926,932 ****
  		  {
  		    /* Don't do unsigned arithmetic where signed was wanted,
  		       or vice versa.  */
! 		    typex = (TREE_UNSIGNED (TREE_TYPE (expr))
  			     ? unsigned_type (typex) : signed_type (typex));
  		    return convert (type,
  				    fold (build (COND_EXPR, typex,
--- 934,942 ----
  		  {
  		    /* Don't do unsigned arithmetic where signed was wanted,
  		       or vice versa.  */
! 		    typex = (((outprec <= TYPE_PRECISION (typex)
! 			       && TREE_UNSIGNED (type))
! 			      || TREE_UNSIGNED (TREE_TYPE (expr)))
  			     ? unsigned_type (typex) : signed_type (typex));
  		    return convert (type,
  				    fold (build (COND_EXPR, typex,

Newsgroups: gnu.gcc.bug