PATCH: C++ front end & register vars

Andrew Haley aph@pasanda.cygnus.co.uk
Sun Jan 16 04:06:00 GMT 2000


I think we're not properly emitting USE notes for register variables
when compiling C++ in whole-function mode.  The stupid register
allocator depends on these notes in order to allocate registers
correctly, so any C++ code using register vars will probably be
incorrect.

The symptom is that registers are incorrectly re-used.  Consider this
fragment of C++ code:

  for (register short int  i = number_of_operations; --i >= 0; )
    {
      unsigned int  tmp;
      
      if ((tmp = (***p)()) > max)
	{
	  max = tmp;
	}
    }

the current x86 egcs C++ compiler generates:

	movw	number_of_operations, %ax	# 22	*movhi_1/2	[length = 7]
	.p2align 4
.L3:
	decw	%ax	# 28	*addhi_1/1	[length = 2]
	testw	%ax, %ax	# 29	cmphi_0/1	[length = 4]
	jns	.L6	# 30	*jcc_1	[length = 2]
	jmp	.L4	# 31	jump	[length = 2]
	.p2align 4,,7
.L6:
	movl	p, %eax	# 43	*movsi_1/1	[length = 6]
	movl	(%eax), %edx	# 45	*movsi_1/1	[length = 2]

[ ... ]

Note here that the loop index variable (ax) is nuked by insn # 43.

I've written a patch which ensures that expand_end_bindings is passed
a list of the the register variables use at the end of a scope.  With
this patch, the compiler generates:

	movw	number_of_operations, %bx	# 22	*movhi_1/2	[length = 7]
	.p2align 4
.L3:
	decw	%bx	# 28	*addhi_1/1	[length = 2]
	testw	%bx, %bx	# 29	cmphi_0/1	[length = 4]
	jns	.L6	# 30	*jcc_1	[length = 2]
	jmp	.L4	# 31	jump	[length = 2]
	.p2align 4,,7
.L6:
	movl	p, %eax	# 43	*movsi_1/1	[length = 6]
	movl	(%eax), %edx	# 45	*movsi_1/1	[length = 2]

Which is correct; it's using bx for the loop index instead of ax.

I don't know the C++ front end at all well; persuading it to generate
the USE notes was tricky, and I'm pretty sure that there must be a
better way of doing it than the solution I found.  IMO the stupid
allocator is more trouble than it's worth, but we had that argument
last year.

Nonetheless, I offer you this patch.

Andrew.

2000-01-14  Andrew Haley  <aph@cygnus.com>

	* semantics.c (regdecls): New variable.
	(expand_stmt): Keep a copy of all register variables used in a
	scope and pass them to expand_end_bindings at the end of the
	scope.

Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/semantics.c,v
retrieving revision 1.121
diff -c -2 -p -r1.121 semantics.c
*** semantics.c	2000/01/11 02:43:00	1.121
--- semantics.c	2000/01/14 17:25:50
*************** static tree maybe_convert_cond PROTO((tr
*** 50,53 ****
--- 50,57 ----
  static tree simplify_aggr_init_exprs_r PROTO((tree *, int *, void *));
  
+ /* regdecls is used when we have to keep track of declared register
+    variables because of the stupid allocator. */
+ static tree regdecls;
+ 
  /* Record the fact that STMT was the last statement added to the
     statement tree.  */
*************** expand_stmt (t)
*** 2352,2355 ****
--- 2356,2368 ----
  		  expand_anon_union_decl (decl, NULL_TREE, 
  					  DECL_ANON_UNION_ELEMS (decl));
+ 		/* If we're using the stupid allocator and this is a
+ 		   register variable we'll need to emit a reference at
+ 		   the end of its scope. */
+ 		if (obey_regdecls && DECL_REGISTER (decl))
+ 		  {
+ 		    tree node = TREE_VALUE(regdecls);
+ 		    TREE_VALUE (regdecls) = copy_node (decl);
+ 		    TREE_CHAIN (TREE_VALUE (regdecls)) = node;
+ 		  }
  	      }
  	    else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))
*************** expand_stmt (t)
*** 2516,2524 ****
  	    {
  	      if (SCOPE_BEGIN_P (t))
! 		expand_start_bindings_and_block (2 * SCOPE_NULLIFIED_P (t),
! 						 SCOPE_STMT_BLOCK (t));
  	      else if (SCOPE_END_P (t))
! 		expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 
! 				     SCOPE_PARTIAL_P (t));
  	    }
  	  else if (!SCOPE_NULLIFIED_P (t))
--- 2529,2552 ----
  	    {
  	      if (SCOPE_BEGIN_P (t))
! 		{
! 		  if (obey_regdecls)
! 		    regdecls = tree_cons (NULL_TREE, NULL_TREE, regdecls);
! 		  expand_start_bindings_and_block (2 * SCOPE_NULLIFIED_P (t),
! 						   SCOPE_STMT_BLOCK (t));
! 		}
  	      else if (SCOPE_END_P (t))
! 		{
! 		  if (obey_regdecls)
! 		    {
! 		      expand_end_bindings (TREE_VALUE (regdecls), 
! 					   !SCOPE_NULLIFIED_P (t),
! 					   SCOPE_PARTIAL_P (t));
! 
! 		      regdecls = TREE_CHAIN (regdecls);
! 		    }
! 		  else
! 		    expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 
! 					 SCOPE_PARTIAL_P (t));
! 		}
  	    }
  	  else if (!SCOPE_NULLIFIED_P (t))
*************** expand_body (fn)
*** 2639,2642 ****
--- 2667,2672 ----
    int saved_lineno;
    char *saved_input_filename;
+ 
+   regdecls = NULL_TREE;
  
    /* When the parser calls us after finishing the body of a template



More information about the Gcc-patches mailing list