v850 -O3 stdarg miscompilation

Jim Wilson wilson@redhat.com
Fri Sep 20 12:25:00 GMT 2002


The v850 port is using a global variable to communicate info from the RTL
generation pass to the assembly output pass.  This assumes one pass always
immediately follows the other.  This assumption fails when inline and/or
nested functions are present.

Here is a simple testcase.
#include <stdarg.h>
#include <stdio.h>

static void var_func(char *buf, char *fmt, ...)
{
  va_list va;
  va_start( va, fmt );
  vsprintf( buf, fmt, va );
  va_end( va );
}

void main()
{
}
If you compile this with -O3, then the assembly code for main is
_main:
	jarl __save_r6_r9,r10
	jmp [r31]
The __save_r6_r9 helper function is only supposed to be called in stdarg
function prologues.

This patch fixes the problem by using a cumulative args_info field instead
of the global variable.  This info is carried along with the function, and
hence is always safe.

This patch was regression tested for a v850-elf target using an uberbaum
tree and running make check in the gcc directory.  This patch eliminates
4 gcc and 4 objc testsuite failures.
FAIL: gcc.c-torture/execute/920625-1.c execution,  -O3 -fomit-frame-pointer
FAIL: gcc.c-torture/execute/920625-1.c execution,  -O3 -fomit-frame-pointer -\funroll-loops
FAIL: gcc.c-torture/execute/920625-1.c execution,  -O3 -fomit-frame-pointer -\funroll-all-loops -finline-functions
FAIL: gcc.c-torture/execute/920625-1.c execution,  -O3 -g

FAIL: objc/execute/va_method.m execution,  -O3 -fomit-frame-pointer
FAIL: objc/execute/va_method.m execution,  -O3 -fomit-frame-pointer -funroll-\loops
FAIL: objc/execute/va_method.m execution,  -O3 -fomit-frame-pointer -funroll-\all-loops -finline-functions
FAIL: objc/execute/va_method.m execution,  -O3 -g

I have checked in this patch.

2002-09-20  Jim Wilson  <wilson@redhat.com>

	* config/v850/v850.c (current_function_anonymous_args): Delete.
	(expand_prologue): Use current_function_args_info.anonymous_args.
	(expand_epilogue): Delete use of current_function_anonymous_args.
	* config/v850/v850.h (struct cum_arg): Add anonymous_args field.
	(INIT_CUMULATIVE_ARGS): Clear anonymous_args field.
	(current_function_anonymous_args): Delete extern declaration.
	(SETUP_INCOMING_VARARGS): Set anonymous_args field.

Index: v850.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/v850/v850.c,v
retrieving revision 1.66
diff -p -r1.66 v850.c
*** v850.c	18 Sep 2002 11:43:44 -0000	1.66
--- v850.c	20 Sep 2002 19:08:34 -0000
*************** static void v850_encode_data_area    PAR
*** 61,69 ****
  static void v850_encode_section_info PARAMS ((tree, int));
  static const char *v850_strip_name_encoding PARAMS ((const char *));
  
- /* True if the current function has anonymous arguments.  */
- int current_function_anonymous_args;
- 
  /* Information about the various small memory areas.  */
  struct small_memory_info small_memory[ (int)SMALL_MEMORY_max ] =
  {
--- 61,66 ----
*************** expand_prologue ()
*** 1656,1662 ****
      }
  
    /* Save arg registers to the stack if necessary.  */
!   else if (current_function_anonymous_args)
      {
        if (TARGET_PROLOG_FUNCTION)
  	{
--- 1653,1659 ----
      }
  
    /* Save arg registers to the stack if necessary.  */
!   else if (current_function_args_info.anonymous_args)
      {
        if (TARGET_PROLOG_FUNCTION)
  	{
*************** Saved %d bytes via epilogue function (%d
*** 2063,2069 ****
  	emit_jump_insn (gen_return ());
      }
  
-   current_function_anonymous_args = 0;
    v850_interrupt_cache_p = FALSE;
    v850_interrupt_p = FALSE;
  }
--- 2060,2065 ----
Index: v850.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/v850/v850.h,v
retrieving revision 1.73
diff -p -r1.73 v850.h
*** v850.h	18 Sep 2002 11:43:44 -0000	1.73
--- v850.h	20 Sep 2002 19:08:34 -0000
*************** enum reg_class
*** 713,719 ****
     such as FUNCTION_ARG to determine where the next arg should go.  */
  
  #define CUMULATIVE_ARGS struct cum_arg
! struct cum_arg { int nbytes; };
  
  /* Define where to put the arguments to a function.
     Value is zero to push the argument on the stack,
--- 713,719 ----
     such as FUNCTION_ARG to determine where the next arg should go.  */
  
  #define CUMULATIVE_ARGS struct cum_arg
! struct cum_arg { int nbytes; int anonymous_args; };
  
  /* Define where to put the arguments to a function.
     Value is zero to push the argument on the stack,
*************** struct cum_arg { int nbytes; };
*** 739,745 ****
     For a library call, FNTYPE is 0.  */
  
  #define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT)	\
!  ((CUM).nbytes = 0)
  
  /* Update the data in CUM to advance over an argument
     of mode MODE and data type TYPE.
--- 739,745 ----
     For a library call, FNTYPE is 0.  */
  
  #define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT)	\
!  ((CUM).nbytes = 0, (CUM).anonymous_args = 0)
  
  /* Update the data in CUM to advance over an argument
     of mode MODE and data type TYPE.
*************** struct cum_arg { int nbytes; };
*** 758,767 ****
     space allocated by the caller.  */
  #define OUTGOING_REG_PARM_STACK_SPACE
  
- extern int current_function_anonymous_args;
  /* Do any setup necessary for varargs/stdargs functions.  */
  #define SETUP_INCOMING_VARARGS(CUM, MODE, TYPE, PAS, SECOND) \
!   current_function_anonymous_args = (!TARGET_GHS ? 1 : 0);
  
  /* Implement `va_arg'.  */
  #define EXPAND_BUILTIN_VA_ARG(valist, type) \
--- 758,766 ----
     space allocated by the caller.  */
  #define OUTGOING_REG_PARM_STACK_SPACE
  
  /* Do any setup necessary for varargs/stdargs functions.  */
  #define SETUP_INCOMING_VARARGS(CUM, MODE, TYPE, PAS, SECOND) \
!   (CUM).anonymous_args = (!TARGET_GHS ? 1 : 0);
  
  /* Implement `va_arg'.  */
  #define EXPAND_BUILTIN_VA_ARG(valist, type) \



More information about the Gcc-patches mailing list