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]

Fix a cse problem with libcalls


The Blackfin port that I'm working on uses an outgoing argument area; all calls construct their arguments in this reserved space above the stack pointer. This is quite normal and done by other ports as well. Nested calls are handled properly in calls.c by creating a save area as needed and copying already constructed arguments to it when we encounter a second call while evaluating arguments.

The attached testcase has a nested libcall (for the division). Initial RTL generation is correct:

(insn 13 12 14 (set (reg:DI 52)
        (mem:DI (plus:SI (reg/f:SI 47 virtual-outgoing-args)
                (const_int 8 [0x8])) [0 S8 A32])) -1 (nil)
    (nil))
 - this copies the already constructed arguments to pseudo

(insn 15 14 16 (set (mem:SI (plus:SI (reg/f:SI 47 virtual-outgoing-args)
                (const_int 12 [0xc])) [0 S4 A32])
        (reg:SI 53)) -1 (nil)
    (insn_list:REG_LIBCALL 22 (nil)))
 - this sets one of the stack args for the following libcall.

[...]
(call_insn/u 19 18 20 (set (reg:DF 0 R0)
        (call (mem:SI (symbol_ref:SI ("__divdf3") [flags 0x41]) [0 S4 A32])
            (const_int 16 [0x10]))) -1 (nil)
    (expr_list:REG_EH_REGION (const_int -1 [0xffffffff])
        (nil))
    (expr_list (use (reg:DF 2 R2))
        (expr_list (use (reg:DF 0 R0))
            (nil))))
 - the libcall

(insn 20 19 23 (set (mem:DI (plus:SI (reg/f:SI 47 virtual-outgoing-args)
                (const_int 8 [0x8])) [0 S8 A32])
        (reg:DI 52)) -1 (nil)
    (nil))
 - restore the arguments for the outer call.

Then, it all gets completely messed up by CSE, which believes the store of insn 15 doesn't conflict with anything because it is in a libcall block. Hence, we turn insn 20 into

(insn 20 19 23 (set (mem:DI (plus:SI (reg/f:SI 47 virtual-outgoing-args)
                (const_int 8 [0x8])) [0 S8 A32])
        (mem:DI (plus:SI (reg/f:SI 47 virtual-outgoing-args)
                (const_int 8 [0x8])) -1 (nil)
    (nil))

which is a no-op move that subsequently gets deleted.

I've committed the patch below, which disables this excessive attempt at cleverness. Bootstrapped on i686-linux; I've also verified that for a fairly large number of testcases, an sh-elf compiler (which should be a relatively heavy user of libcalls) produces exactly the same output as before. I've also committed the testcase as execute/20041113-1.c.


Bernd
#include <stdarg.h>

void test (int x, ...)
{
    va_list ap;
    int i;
    va_start (ap, x);
    if (va_arg (ap, int) != 1)
	abort ();
    if (va_arg (ap, int) != 2)
	abort ();
    if (va_arg (ap, int) != 3)
	abort ();
    if (va_arg (ap, int) != 4)
	abort ();
}

double a = 40.0;

int main(int argc, char *argv[])
{
    test(0, 1, 2, 3, (int)(a / 10.0));
    exit (0);
}
	* cse.c (cse_insn): Stores in a libcall sequence can invalidate
	previous loads.

Index: cse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cse.c,v
retrieving revision 1.320
diff -c -p -r1.320 cse.c
*** cse.c	2 Nov 2004 17:59:41 -0000	1.320
--- cse.c	13 Nov 2004 13:57:25 -0000
*************** cse_insn (rtx insn, rtx libcall_insn)
*** 5683,5694 ****
  	  if (REG_P (dest) || GET_CODE (dest) == SUBREG)
  	    invalidate (dest, VOIDmode);
  	  else if (MEM_P (dest))
! 	    {
! 	      /* Outgoing arguments for a libcall don't
! 		 affect any recorded expressions.  */
! 	      if (! libcall_insn || insn == libcall_insn)
! 		invalidate (dest, VOIDmode);
! 	    }
  	  else if (GET_CODE (dest) == STRICT_LOW_PART
  		   || GET_CODE (dest) == ZERO_EXTRACT)
  	    invalidate (XEXP (dest, 0), GET_MODE (dest));
--- 5683,5689 ----
  	  if (REG_P (dest) || GET_CODE (dest) == SUBREG)
  	    invalidate (dest, VOIDmode);
  	  else if (MEM_P (dest))
! 	    invalidate (dest, VOIDmode);
  	  else if (GET_CODE (dest) == STRICT_LOW_PART
  		   || GET_CODE (dest) == ZERO_EXTRACT)
  	    invalidate (XEXP (dest, 0), GET_MODE (dest));
*************** cse_insn (rtx insn, rtx libcall_insn)
*** 5856,5867 ****
  	if (REG_P (dest) || GET_CODE (dest) == SUBREG)
  	  invalidate (dest, VOIDmode);
  	else if (MEM_P (dest))
! 	  {
! 	    /* Outgoing arguments for a libcall don't
! 	       affect any recorded expressions.  */
! 	    if (! libcall_insn || insn == libcall_insn)
! 	      invalidate (dest, VOIDmode);
! 	  }
  	else if (GET_CODE (dest) == STRICT_LOW_PART
  		 || GET_CODE (dest) == ZERO_EXTRACT)
  	  invalidate (XEXP (dest, 0), GET_MODE (dest));
--- 5851,5857 ----
  	if (REG_P (dest) || GET_CODE (dest) == SUBREG)
  	  invalidate (dest, VOIDmode);
  	else if (MEM_P (dest))
! 	  invalidate (dest, VOIDmode);
  	else if (GET_CODE (dest) == STRICT_LOW_PART
  		 || GET_CODE (dest) == ZERO_EXTRACT)
  	  invalidate (XEXP (dest, 0), GET_MODE (dest));

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