delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1997/06/26/17:28:48

Date: Thu, 26 Jun 1997 14:27:17 -0700 (PDT)
Message-Id: <199706262127.OAA25663@adit.ap.net>
Mime-Version: 1.0
To: djgpp AT delorie DOT com
From: Nate Eldredge <eldredge AT ap DOT net>
Subject: Bug (?) in GCC - discarded struct returns

I've found a problem with GCC that I don't know whether to describe as a bug
or just compiler stupidity. The problem is that when calling a function
returning a struct several times and ignoring the return value, space is
allocated on the stack for *each* of the ignored structs. (Confusing, I
know.) Perhaps my (long) example will help explain:
-- cut --
#include <string.h>

/* A large struct type */

struct big_struct
{
  char string_member[1000];
  int more_data;
} ;

/* A function returning a big_struct */

struct big_struct do_something(void)
{
  struct big_struct local_struct;

  /* ... Imagine this function doing * 
   *  something of interest here ... */


  /* Now fill local_struct with some stuff */
  strcpy(local_struct.string_member,"hi there");
  local_struct.more_data = 12345;
  
  /* And return it */
  return local_struct;
}

int main(void)
{
  /* Although no local variables, main requires stack space           *
   * of sizeof(struct big_struct) * (number of calls to do_something) */

  /* Suppose we want to do_something a lot */
  do_something();
  do_something();
  do_something();
  do_something();
  do_something();
  do_something();
  
  return 0;
}
--cut--
If you compile this and look at the resulting assembly, you will notice that
main allocates about 6000 bytes on the stack. The returned struct from each
call to do_something is placed in a slot of its own, as if it were a local
variable. Since it's never used again, this is a big waste of 5K. If
big_struct were much larger, or there were more calls to do_something, you
might overflow your stack, causing bafflement ("I don't use big auto arrays
or anything!").

I realize part of this is a side effect of Gnu CC's clever struct-returning
scheme (the address of where it will go is passed as an invisible
parameter). *Some* address has to be passed, with space to hold the data, so
stack space is allocated. One would hope, however, that the compiler would
be smart enough to have them all dump their ignored structs into the same
stack slot.

To work around, you could explicitly assign the results to a variable and
then not use it:
--cut--
int main(void)
{
  struct big_struct garbage_can; /* :) */
  garbage_can = do_something();
  garbage_can = do_something();
  /* etc... */
  return 0;
}
--cut--

Turning on optimizations has no effect on this problem (except that -O3 or
-finline-functions make it a lot harder to see). Unless someone can think of
a justification for this inefficiency, I'm going to report it to GNU. 


Nate Eldredge
eldredge AT ap DOT net



- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019