Index: gcc/gcc/config/i386/i386.c =================================================================== --- gcc.orig/gcc/config/i386/i386.c 2010-12-03 10:12:09.000000000 +0100 +++ gcc/gcc/config/i386/i386.c 2010-12-03 11:54:08.811957100 +0100 @@ -5428,6 +5428,19 @@ ix86_eax_live_at_start_p (void) return REGNO_REG_SET_P (df_get_live_out (ENTRY_BLOCK_PTR), 0); } +static bool +ix86_keep_aggregate_return_pointer (tree fntype) +{ + if (lookup_attribute ("keep_aggregate_return_pointer", + TYPE_ATTRIBUTES (fntype))) + return true; + if (lookup_attribute ("dont_keep_aggregate_return_pointer", + TYPE_ATTRIBUTES (fntype))) + return false; + + return KEEP_AGGREGATE_RETURN_POINTER != 0; +} + /* Value is the number of bytes of arguments automatically popped when returning from a subroutine call. FUNDECL is the declaration node of the function (as a tree), @@ -5472,7 +5485,7 @@ ix86_return_pops_args (tree fundecl, tre /* Lose any fake structure return argument if it is passed on the stack. */ if (aggregate_value_p (TREE_TYPE (funtype), fundecl) - && !KEEP_AGGREGATE_RETURN_POINTER) + && !ix86_keep_aggregate_return_pointer (funtype)) { int nregs = ix86_function_regparm (funtype, fundecl); if (nregs == 0) @@ -29052,6 +29065,59 @@ x86_order_regs_for_local_alloc (void) reg_alloc_order [pos++] = 0; } +/* Handle a "dont_keep_aggregate_return_pointer" or + "keep_aggregate_return_pointer" attribut; arguments as + in struct attribute_spec handler. */ +static tree +ix86_handle_keep_aggregate_return_ptr_attrib (tree *node, tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, + bool *no_add_attrs) +{ + if (TREE_CODE (*node) != FUNCTION_TYPE + && TREE_CODE (*node) != METHOD_TYPE + && TREE_CODE (*node) != FIELD_DECL + && TREE_CODE (*node) != TYPE_DECL) + { + warning (OPT_Wattributes, "%qE attribute only applies to functions", + name); + *no_add_attrs = true; + return NULL_TREE; + } + if (TARGET_64BIT) + { + warning (OPT_Wattributes, "%qE attribute only available for 32-bit", + name); + *no_add_attrs = true; + return NULL_TREE; + } + if (is_attribute_p ("dont_keep_aggregate_return_pointer", name)) + { + if (lookup_attribute ("keep_aggregate_return_pointer", + TYPE_ATTRIBUTES (*node))) + { + error ("dont_keep_aggregate_return_pointer and " + "keep_aggregate_return_pointer attributes " + "are not compatible"); + } + return NULL_TREE; + } + else if (is_attribute_p ("keep_aggregate_return_pointer", name)) + { + if (lookup_attribute ("dont_keep_aggregate_return_pointer", + TYPE_ATTRIBUTES (*node))) + { + error ("keep_aggregate_return_pointer and " + "dont_keep_aggregate_return_pointer attributes " + "are not compatible"); + } + + return NULL_TREE; + } + + return NULL_TREE; +} + /* Handle a "ms_abi" or "sysv" attribute; arguments as in struct attribute_spec.handler. */ static tree @@ -32221,6 +32287,10 @@ static const struct attribute_spec ix86_ { "ms_abi", 0, 0, false, true, true, ix86_handle_abi_attribute }, { "sysv_abi", 0, 0, false, true, true, ix86_handle_abi_attribute }, { "ms_hook_prologue", 0, 0, true, false, false, ix86_handle_fndecl_attribute }, + { "dont_keep_aggregate_return_pointer", 0, 0, false, true, true, + ix86_handle_keep_aggregate_return_ptr_attrib }, + { "keep_aggregate_return_pointer", 0, 0, false, true, true, + ix86_handle_keep_aggregate_return_ptr_attrib }, /* End element. */ { NULL, 0, 0, false, false, false, NULL } }; Index: gcc/gcc/doc/extend.texi =================================================================== --- gcc.orig/gcc/doc/extend.texi 2010-11-22 14:41:40.000000000 +0100 +++ gcc/gcc/doc/extend.texi 2010-12-03 12:20:06.487884300 +0100 @@ -2823,6 +2823,19 @@ when targeting Windows. On all other sy Note, the @code{ms_abi} attribute for Windows targets currently requires the @option{-maccumulate-outgoing-args} option. +@item dont_keep_aggregate_return_pointer/keep_aggregate_return_pointer +@cindex @code{dont_keep_aggregate_return_pointer} attribute +@cindex @code{keep_aggregate_return_pointer} attribute + +On 32-bit i?86-*-* targets, you can control by those attributes for +aggregate return in memory, if the caller is responsible to pop the hidden +pointer together with the rest of the arguments, or if the callee is responsible +to pop hidden pointer. + +For i?86-netware, the caller pops the stack for the hidden arguments pointing +to aggregate return value. This differs from the default i386 ABI which assumes +that the callee pops the stack for hidden pointer. + @item ms_hook_prologue @cindex @code{ms_hook_prologue} attribute Index: gcc/gcc/testsuite/gcc.target/i386/aggregate-ret1.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc/gcc/testsuite/gcc.target/i386/aggregate-ret1.c 2010-12-03 12:04:11.558266500 +0100 @@ -0,0 +1,28 @@ +/* target/36834 */ +/* Check that, with keep_aggregate_return_pointer attribute, callee does + not pop the stack for the implicit pointer arg when returning a large + structure in memory. */ +/* { dg-do compile { target i?86-*-* } } */ + +struct foo { + int a; + int b; + int c; + int d; +}; + +__attribute__ ((keep_aggregate_return_pointer)) +struct foo +bar (void) +{ + struct foo retval; + retval.a = 1; + retval.b = 2; + retval.c = 3; + retval.d = 4; + return retval; +} + +/* { dg-final { scan-assembler-not "ret\[ \t\]\\\$4" } } */ + + Index: gcc/gcc/testsuite/gcc.target/i386/aggregate-ret2.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc/gcc/testsuite/gcc.target/i386/aggregate-ret2.c 2010-12-03 12:07:19.688082500 +0100 @@ -0,0 +1,28 @@ +/* target/36834 */ +/* Check that, with dont_keep_aggregate_return_pointer attribute, callee + pops the stack for the implicit pointer arg when returning a large + structure in memory. */ +/* { dg-do compile { target i?86-*-* } } */ + +struct foo { + int a; + int b; + int c; + int d; +}; + +__attribute__ ((dont_keep_aggregate_return_pointer)) +struct foo +bar (void) +{ + struct foo retval; + retval.a = 1; + retval.b = 2; + retval.c = 3; + retval.d = 4; + return retval; +} + +/* { dg-final { scan-assembler "ret\[ \t\]\\\$4" } } */ + +