[gnu.gcc.bug] GNU CC Version 1.34 bug report

bignum@math.keio.ac.jp (NIIMI Makoto) (02/03/90)

My friend ,Mr. Seyama, porting GNU CC to OS-9/68000.
He fond some bugs, but he can not mail to you.
So, I forward his mail to you.
If you want to contact him, please mail to me.
------------------------------------------------------------------------
GNU CC Version 1.34 bug report

  I am poting GNU CC Version 1.34 to OS-9/68000 which is a unix link
operating system running on Motorola 680XX.  Main differences as long as
gcc porting is concerned, are

  (1)  C libraries of OS-9/68000 uses registers for passing parameters.
  (2)  OS-9/68000 requires base register for accessing data area.

Beside the second difference, here is a bug report of -mregparm feature
of gcc.  Although that feature is in only test stage, l hope this report
will be of some help. 

This report also includes these independent of -mregparm.  At first such
bugs are reported. 


(1) Assume STRUCTURE_SIZE_BOUNDARY is not defined, (or defined to be 8). 

(1-1) Then

  struct z1 { char a;}

have 8 bit alignment, and if function `foo' has an argument of type
`struct z1', calling sequence of `foo' contains instruction
`subq.l #3,sp' to get PARM_BOUNDARY (32bit) alignment. 
    
The following is my patch (store_one_arg in expr.c).

static void
store_one_arg (arg, argblock, may_be_alloca)
     ...
{
...
  if (arg->reg != 0 && arg->partial == 0)
    ...
  else if (TYPE_MODE (TREE_TYPE (pval)) != BLKmode)
    ...
  else if (arg->stack != 0)
    ...
  else
    {
      /* BLKmode, at least partly to be pushed.  */
      ...
      if (arg->size.var != 0)
	...
      else
	{
	  register tree size = size_in_bytes (TREE_TYPE (pval));
	  /* PUSH_ROUNDING has no effect on us, because
	     emit_push_insn for BLKmode is careful to avoid it.  */
/* CHANGED */
#ifndef PUSH_ROUNDING
	  excess = arg->size.constant - TREE_INT_CST_LOW (size);
#else
	  excess = arg->size.constant - PUSH_ROUNDING (TREE_INT_CST_LOW (size));
#endif
	  size_rtx = expand_expr (size, 0, VOIDmode, 0);
	}
      ...
    }
  ...
}

(1-2) If function `bar' takes an argument of type

  struct z2 { char a; char b;},

calling sequence of `bar' contains instructions

  move.b -1(fp),-(sp)
  move.b -2(fp),-(sp)

to set up argument.

The following is my patch (emit_push_insn in expr.c).

static void
emit_push_insn (x, mode, size, align, partial, reg, extra, args_addr, args_so_far)
     ...
{
  ...

  if (partial > 0)
    ...

  if (extra)
    ...
 
  if (mode == BLKmode)
    {
      ...
      if (size == 0)
	...

      if (partial != 0)
	...

#ifdef PUSH_ROUNDING
/* ADDED */
      align = PUSH_ROUNDING (align);

      ...
#endif /* PUSH_ROUNDING */
   
	{
	  /* Otherwise make space on the stack and copy the data
	     to the address of that space.  */

	  /* First deduct part put into registers from the size we need.  */
	  if (partial != 0)
	    ...

/* ADDED */
#ifdef PUSH_ROUNDING
	  if (args_addr == 0
	      && GET_CODE (size) == CONST_INT
	      && PUSH_ROUNDING (INTVAL (size)) != INTVAL (size))
	    size = gen_rtx (CONST_INT, VOIDmode, PUSH_ROUNDING (INTVAL (size)));
#endif
	  ....
    }
  else if (partial > 0)
    ...
  else
    ...
  ...
}

(1-3) A question.  if a variable `x' of type

  struct z3 { short a; int b; short c;}

comes into registers, member `x.b' can be correctly accessed ?.  (In
this case, `x.b' is stored across two registers). 


(2) Block profile code generation. 

(2-1) (final in final.c) Becase the last insn may be a (conditional)
branch, `new_block' must be checked after exiting main `for' loop. 

(2-2) (final in final.c) When `code_label' insn is used as a base
address of jump table, do not generat profile code. 

(2-3) (BLOCK_PROFILER in tm-m68k.h) Since `addq.l #1,...' clobbers the
condition code register, CC_STATUS_INIT must be issued. 

(2-4) For emity function `void do_nothing (void) {}', no profile code is
generated.  Is it desirable ?. 

(2-5) Detect conditional branches in parallel expression ?.  (e.g.  insn
using `dbra')


(3) Misc. 

(3-1) combine_instructions (combine.c) Count up `total_distrib_*'. 

(3-2) round_push (explow.c) `else' after `if (align == 1) ;' is missed ?. 

(3-3) epand_call (expr.c) Argument NAMED of FUCNTION_ARG and
FUNCTION_ARG_PARTIAL_NREGS are incorrect if PUSH_ARG_REVERSED.  In that
case, not `i < n_named_args' but `num_actuals - 1 - i < n_named_args'
must be used. 


Now I report bugs of -mregparm feature.


(4) move_movables (loop.c) To find the insn loading function address,
skip `(insn ...  (use ...))'. 

static void
move_movables (movables, threshold, insn_count, loop_start, end, nregs)
     ...
{
  ...
  for (m = movables; m; m = m->next)
    {
      /* Describe this movable insn.  */

      if (loop_dump_stream)
	...
      if (!m->done
	  && (! m->cond
	      || (1 == invariant_p (m->set_src)
		  && (m->consec == 0
		      || 1 == consec_sets_invariant_p (SET_DEST (PATTERN (m->insn)),
						       m->consec + 1,
						       m->insn))))
	  && (! m->forces || m->forces->done))
	{
	  ...
	  if (loop_dump_stream)
	    ...

	  if (moved_once[regno])
	    ...

	  if (already_moved[regno]
	      || (threshold * savings * m->lifetime) >= insn_count
	      || (m->forces && m->forces->done
		  && n_times_used[m->forces->regno] == 1))
	    {
	      ...
	      for (count = m->consec; count >= 0; count--)
		{
		  ...
		  if (temp = find_reg_note (p, REG_LIBCALL, 0))
		    ...
		  if (temp = find_reg_note (p, REG_RETVAL, 0))
		    {
		      ...
/* THIS LOOP => */      for (temp = XEXP (temp, 0); temp != p;
			   temp = NEXT_INSN (temp))
			{


(5) Order of allocating registers for parameters are reveresed in
`emit_library_call' (expr.c).  For example, consider the call of
function

  int foo (int a, int b).

If `foo' is not a library function then expand_call set value of `a' in
d0 and `b' in d1.  But if `foo' is a library function such as __divsi3,
`emit_library_call' set value of `b' in d0 and `a' in d1. 


(6) Conflict between FUNCTION_VALUE_REGNO_P and FUNCTION_ARG_REGNO_P. 
If function value is returned via d0 and function arguments are passed
via d0 and d1, both macro return t for regno 0.  On the other hand,
try_combine (combine.c) uses FUNCTION_VALUE_REGNO_P to inhibit
instruction combination.  Consequently try_combine also inhibits
instruction combination using register which is used to pass argument. 
Is it desirable ?. 


(7)  BLKmode arguments passed by regsiters.
If a function takes a BLKmode argument and that argument is passied via
registers, `assign_parms' (stmt.c) use `move_block_form_reg' to save
arguments into stack slot and `store_one_arg' use `move_block_to_reg' to
set arguments into registers.  Both `move_block_from_reg' and
`move_block_to_reg' can move only BLKmode whose sizeof is a multiple of
UNITS_PER_WORD, if sizeof is 1 2 or 6 then only a part of argument is
passed. 


(8)  Final question.  `save_for_inline'  (integrate.c)
I found a forward reference in the chain of insns (REG_NOTES format `u')
when compiling the dhry benchmark program Version 2.1. 

  gcc -O -finline-functions -mc68000 -msoft-float -S dhry-2.c

Generated code of Proc_8 is different from the code generated without
the option `-finline-fucntions'. 


                            90/01/31   Atsushi Seyama

                            5-7-20 HIGASI MACHI, HOYA, TOKYO, JAPAN
-------------------
;;;  Keio University
;;;    Faculty of Science and Technology
;;;      Department of Math
;;;		Makoto Niimi
;;;		bignum@math.keio.ac.jp