diff mbox

PATCH RFA: Split stack [1/7]: Basic infrastructure

Message ID mcrr5gl77zd.fsf@google.com
State New
Headers show

Commit Message

Ian Lance Taylor Sept. 22, 2010, 10:01 p.m. UTC
This is the first of 7 patches adding support for discontiguous stacks
to gcc.  With the new -fsplit-stack option, the compiler inserts a small
prologue into every function which checks whether there is enough stack
space for the function frame.  If there is not, the function calls a
helper routine in libgcc which allocates a new stack segment and
switches the function to run on the newly allocated stack.  The effect
is that stacks never overflow, unless the program as a whole runs out of
memory.  This is useful for highly threaded programs, as it is no longer
essential to figure out how much stack space to allocate for each
thread.

There are more details at http://gcc.gnu.org/wiki/SplitStacks .  I have
implemented this for x86 and x86_64 GNU/Linux.

I wrote this feature for use with the Go compiler.  As Go makes it very
easy to create new threads, it is very desirable to not have to worry
about allocating stacks for each thread.  There are straightforward Go
programs which fail without split stacks but succeed with them.

Although the feature was created for Go, I believe it can be generally
useful for code written in other languages.  This series of patches is
intended to add this functionality to the main compiler, in advance of
the merge of the actual Go frontend.

The seven patches together were bootstrapped and tested on
x86_64-unknown-linux-gnu.

This first of seven patches simply provides basic infrastructure for the
option.  The only mildly interesting part of this patch is that
-fsplit-stack causes the driver to pass --wrap=pthread_create to the
linker.  This is used in libgcc to set up the stack overflow information
for each newly created thread.

This patch is partially under my bailiwick as middle-end maintainer, and
is partially part of gcc driver program and the C frontend (for the new
no_split_stack function attribute).  OK for mainline?

Ian


gcc/ChangeLog:

2010-09-21  Ian Lance Taylor  <iant@google.com>

	* common.opt (fsplit-stack): New option.
	* opts.c (decode_options): Set flag_split_stack to final value.
	* target.def (supports_split_stack): New hook.
	* gcc.c (STACK_SPLIT_SPEC): Define.
	(LINK_COMMAND_SPEC): Use STACK_SPLIT_SPEC.
	* doc/invoke.texi (Option Summary): Mention -fsplit-stack.
	(Code Gen Options): Document -fsplit-stack.
	* doc/extend.texi (Function Attributes): Mention no_split_stack.
	(Function Attributes): Document no_split_stack.
	* doc/tm.texi.in (Stack Smashing Protection): Add @hook
	TARGET_SUPPORTS_SPLIT_STACK.
	* doc/tm.texi: Rebuild.

gcc/c-family/ChangeLog:

2010-09-21  Ian Lance Taylor  <iant@google.com>

	* c-common.c (c_common_attribute_table): Add no_split_stack.
	(handle_no_split_stack_attribute): New static function.

Comments

Richard Henderson Sept. 23, 2010, 4:54 p.m. UTC | #1
On 09/22/2010 03:01 PM, Ian Lance Taylor wrote:
> +DEFHOOK
> +(supports_split_stack,
> + "Whether this target supports splitting the stack.  This is called\
> + after options have been parsed, so the target may reject splitting\
> + the stack in some configurations.  The default version of this hook\
> + returns false.  If REPORT is true, this function may issue a warning\
> + or error; if REPORT is false, it must simply return a value",

@var{report}, I think.  Certainly not all-caps.

Otherwise it looks ok to me.


r~
Ian Lance Taylor Sept. 23, 2010, 7:17 p.m. UTC | #2
Richard Henderson <rth@redhat.com> writes:

> On 09/22/2010 03:01 PM, Ian Lance Taylor wrote:
>> +DEFHOOK
>> +(supports_split_stack,
>> + "Whether this target supports splitting the stack.  This is called\
>> + after options have been parsed, so the target may reject splitting\
>> + the stack in some configurations.  The default version of this hook\
>> + returns false.  If REPORT is true, this function may issue a warning\
>> + or error; if REPORT is false, it must simply return a value",
>
> @var{report}, I think.  Certainly not all-caps.

Thanks.  Fixed in my tree.

Ian
Ian Lance Taylor Sept. 27, 2010, 7:49 p.m. UTC | #3
I have committed the -fsplit-stack support as revision 164661.

The split branch is now retired.

Ian
diff mbox

Patch

Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 164490)
+++ gcc/doc/invoke.texi	(working copy)
@@ -924,7 +924,7 @@  See S/390 and zSeries Options.
 -fshort-double  -fshort-wchar @gol
 -fverbose-asm  -fpack-struct[=@var{n}]  -fstack-check @gol
 -fstack-limit-register=@var{reg}  -fstack-limit-symbol=@var{sym} @gol
--fno-stack-limit @gol
+-fno-stack-limit -fsplit-stack @gol
 -fleading-underscore  -ftls-model=@var{model} @gol
 -ftrapv  -fwrapv  -fbounds-check @gol
 -fvisibility}
@@ -17916,6 +17916,25 @@  and grows downwards, you can use the fla
 @option{-Wl,--defsym,__stack_limit=0x7ffe0000} to enforce a stack limit
 of 128KB@.  Note that this may only work with the GNU linker.
 
+@item -fsplit-stack
+@opindex fsplit-stack
+Generate code to automatically split the stack before it overflows.
+The resulting program has a discontiguous stack which can only
+overflow if the program is unable to allocate any more memory.  This
+is most useful when running threaded programs, as it is no longer
+necessary to calculate a good stack size to use for each thread.  This
+is currently only implemented for the i386 and x86_64 backends running
+GNU/Linux.
+
+When code compiled with @option{-fsplit-stack} calls code compiled
+without @option{-fsplit-stack}, there may not be much stack space
+available for the latter code to run.  If compiling all code,
+including library code, with @option{-fsplit-stack} is not an option,
+then the linker can fix up these calls so that the code compiled
+without @option{-fsplit-stack} always has a large stack.  Support for
+this is implemented in the gold linker in GNU binutils release 2.21
+and later.
+
 @item -fleading-underscore
 @opindex fleading-underscore
 This option and its counterpart, @option{-fno-leading-underscore}, forcibly
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 164490)
+++ gcc/doc/extend.texi	(working copy)
@@ -1926,7 +1926,8 @@  attributes are currently defined for fun
 @code{returns_twice}, @code{noinline}, @code{noclone},
 @code{always_inline}, @code{flatten}, @code{pure}, @code{const},
 @code{nothrow}, @code{sentinel}, @code{format}, @code{format_arg},
-@code{no_instrument_function}, @code{section}, @code{constructor},
+@code{no_instrument_function}, @code{no_split_stack},
+@code{section}, @code{constructor},
 @code{destructor}, @code{used}, @code{unused}, @code{deprecated},
 @code{weak}, @code{malloc}, @code{alias}, @code{ifunc},
 @code{warn_unused_result}, @code{nonnull}, @code{gnu_inline},
@@ -2831,6 +2832,14 @@  If @option{-finstrument-functions} is gi
 be generated at entry and exit of most user-compiled functions.
 Functions with this attribute will not be so instrumented.
 
+@item no_split_stack
+@cindex @code{no_split_stack} function attribute
+@opindex fsplit-stack
+If @option{-fsplit-stack} is given, functions will have a small
+prologue which decides whether to split the stack.  Functions with the
+@code{no_split_stack} attribute will not have that prologue, and thus
+may run with only a small amount of stack space available.
+
 @item noinline
 @cindex @code{noinline} function attribute
 This function attribute prevents a function from being considered for
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi	(revision 164490)
+++ gcc/doc/tm.texi	(working copy)
@@ -4960,6 +4960,10 @@  The default version of this hook invokes
 normally defined in @file{libgcc2.c}.
 @end deftypefn
 
+@deftypefn {Target Hook} bool TARGET_SUPPORTS_SPLIT_STACK (bool)
+Whether this target supports splitting the stack.  This is called after options have been parsed, so the target may reject splitting the stack in some configurations.  The default version of this hook returns false.  If REPORT is true, this function may issue a warning or error; if REPORT is false, it must simply return a value
+@end deftypefn
+
 @node Varargs
 @section Implementing the Varargs Macros
 @cindex varargs implementation
Index: gcc/doc/tm.texi.in
===================================================================
--- gcc/doc/tm.texi.in	(revision 164490)
+++ gcc/doc/tm.texi.in	(working copy)
@@ -4960,6 +4960,8 @@  The default version of this hook invokes
 normally defined in @file{libgcc2.c}.
 @end deftypefn
 
+@hook TARGET_SUPPORTS_SPLIT_STACK
+
 @node Varargs
 @section Implementing the Varargs Macros
 @cindex varargs implementation
Index: gcc/target.def
===================================================================
--- gcc/target.def	(revision 164490)
+++ gcc/target.def	(working copy)
@@ -1679,6 +1679,16 @@  DEFHOOK
  tree, (void),
  default_external_stack_protect_fail)
 
+DEFHOOK
+(supports_split_stack,
+ "Whether this target supports splitting the stack.  This is called\
+ after options have been parsed, so the target may reject splitting\
+ the stack in some configurations.  The default version of this hook\
+ returns false.  If REPORT is true, this function may issue a warning\
+ or error; if REPORT is false, it must simply return a value",
+ bool, (bool),
+ hook_bool_bool_false)
+
 /* Returns NULL if target supports the insn within a doloop block,
    otherwise it returns an error message.  */
 DEFHOOK
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 164490)
+++ gcc/c-family/c-common.c	(working copy)
@@ -357,6 +357,7 @@  static tree handle_type_generic_attribut
 static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *);
 static tree handle_target_attribute (tree *, tree, tree, int, bool *);
 static tree handle_optimize_attribute (tree *, tree, tree, int, bool *);
+static tree handle_no_split_stack_attribute (tree *, tree, tree, int, bool *);
 static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
 
 static void check_function_nonnull (tree, int, tree *);
@@ -658,6 +659,8 @@  const struct attribute_spec c_common_att
 			      handle_target_attribute },
   { "optimize",               1, -1, true, false, false,
 			      handle_optimize_attribute },
+  { "no_split_stack",	      0, 0, true,  false, false,
+			      handle_no_split_stack_attribute },
   /* For internal use (marking of builtins and runtime functions) only.
      The name contains space to prevent its usage in source code.  */
   { "fn spec",	 	      1, 1, false, true, true,
@@ -7816,6 +7819,32 @@  handle_optimize_attribute (tree *node, t
 
   return NULL_TREE;
 }
+
+/* Handle a "no_split_stack" attribute.  */
+
+static tree
+handle_no_split_stack_attribute (tree *node, tree name,
+				 tree ARG_UNUSED (args),
+				 int ARG_UNUSED (flags),
+				 bool *no_add_attrs)
+{
+  tree decl = *node;
+
+  if (TREE_CODE (decl) != FUNCTION_DECL)
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+		"%qE attribute applies only to functions", name);
+      *no_add_attrs = true;
+    }
+  else if (DECL_INITIAL (decl))
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+		"can%'t set %qE attribute after definition", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
 
 /* Check for valid arguments being passed to a function.
    ATTRS is a list of attributes.  There are NARGS arguments in the array
Index: gcc/gcc.c
===================================================================
--- gcc/gcc.c	(revision 164490)
+++ gcc/gcc.c	(working copy)
@@ -584,6 +584,16 @@  proper position among the other output f
 #define MFLIB_SPEC "%{fmudflap|fmudflapth: -export-dynamic}"
 #endif
 
+/* When using -fsplit-stack we need to wrap pthread_create, in order
+   to initialize the stack guard.  We always use wrapping, rather than
+   shared library ordering, and we keep the wrapper function in
+   libgcc.  This is not yet a real spec, though it could become one;
+   it is currently just stuffed into LINK_SPEC.  FIXME: This wrapping
+   only works with GNU ld and gold.  FIXME: This is incompatible with
+   -fmudflap when linking statically, which wants to do its own
+   wrapping.  */
+#define STACK_SPLIT_SPEC " %{fsplit-stack: --wrap=pthread_create}"
+
 /* config.h can define LIBGCC_SPEC to override how and when libgcc.a is
    included.  */
 #ifndef LIBGCC_SPEC
@@ -696,7 +706,8 @@  proper position among the other output f
    "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\
     %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
     %{static:} %{L*} %(mfwrap) %(link_libgcc) %o\
-    %{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)} %(mflib)\
+    %{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)}\
+    %(mflib) " STACK_SPLIT_SPEC "\
     %{fprofile-arcs|fprofile-generate*|coverage:-lgcov}\
     %{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\
     %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}}"
Index: gcc/opts.c
===================================================================
--- gcc/opts.c	(revision 164490)
+++ gcc/opts.c	(working copy)
@@ -1086,6 +1086,20 @@  decode_options (unsigned int argc, const
      check option consistency.  */
   if (flag_lto && flag_whopr)
     error ("-flto and -fwhopr are mutually exclusive");
+
+  /* We initialize flag_split_stack to -1 so that targets can set a
+     default value if they choose based on other options.  */
+  if (flag_split_stack == -1)
+    flag_split_stack = 0;
+  else
+    {
+      if (!targetm.supports_split_stack (true))
+	{
+	  error ("%<-fsplit-stack%> is not supported by "
+		 "this compiler configuration");
+	  flag_split_stack = 0;
+	}
+    }
 }
 
 #define LEFT_COLUMN	27
Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 164490)
+++ gcc/common.opt	(working copy)
@@ -1249,6 +1249,10 @@  fsplit-ivs-in-unroller
 Common Report Var(flag_split_ivs_in_unroller) Init(1) Optimization
 Split lifetimes of induction variables when loops are unrolled
 
+fsplit-stack
+Common Report Var(flag_split_stack) Init(-1)
+Generate discontiguous stack frames
+
 fsplit-wide-types
 Common Report Var(flag_split_wide_types) Optimization
 Split wide types into independent registers