This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Fix i386 local and fastcall functions handling
- From: Jan Hubicka <jh at suse dot cz>
- To: gcc-patches at gcc dot gnu dot org, rth at redhat dot com
- Date: Fri, 15 Aug 2003 10:40:23 +0200
- Subject: Fix i386 local and fastcall functions handling
Hi,
this patch brings into sync 3 places where amount of register arguments is
computed and fixes bugs in local functions returning structures and some cases
of fastcall problems.
Regtested/bootstrapped i386.
OK?
Honza
Wed Aug 13 21:00:51 CEST 2003 Jan Hubicka <jh@suse.cz>
* i386.c (ix86_fntype_regparm): Rename from ...
(ix86_function_regparm): ... this one; add fastcall and local
functions.
(ix86_function_ok_for_sibcall): Update.
(ix86_return_pops_args): Likewise.
(init_cumulative_args): Likewise.
(x86_can_output_mi_thunk): Likewise.
(function_arg): Fix formating.
(x86_this_parameter): Fix fastcall.
(x86_output_mi_thunk): Likewise.
diff -Nrc3p gcc.old/config/i386/i386.c gcc/config/i386/i386.c
*** gcc.old/config/i386/i386.c Mon Aug 4 22:43:01 2003
--- gcc/config/i386/i386.c Wed Aug 13 20:36:30 2003
*************** static unsigned int ix86_select_alt_pic_
*** 866,872 ****
static int ix86_save_reg (unsigned int, int);
static void ix86_compute_frame_layout (struct ix86_frame *);
static int ix86_comp_type_attributes (tree, tree);
! static int ix86_fntype_regparm (tree);
const struct attribute_spec ix86_attribute_table[];
static bool ix86_function_ok_for_sibcall (tree, tree);
static tree ix86_handle_cdecl_attribute (tree *, tree, tree, int, bool *);
--- 866,872 ----
static int ix86_save_reg (unsigned int, int);
static void ix86_compute_frame_layout (struct ix86_frame *);
static int ix86_comp_type_attributes (tree, tree);
! static int ix86_function_regparm (tree, tree);
const struct attribute_spec ix86_attribute_table[];
static bool ix86_function_ok_for_sibcall (tree, tree);
static tree ix86_handle_cdecl_attribute (tree *, tree, tree, int, bool *);
*************** ix86_function_ok_for_sibcall (tree decl,
*** 1532,1550 ****
such registers are not used for passing parameters. */
if (!decl && !TARGET_64BIT)
{
! int regparm = ix86_regparm;
! tree attr, type;
/* We're looking at the CALL_EXPR, we need the type of the function. */
type = TREE_OPERAND (exp, 0); /* pointer expression */
type = TREE_TYPE (type); /* pointer type */
type = TREE_TYPE (type); /* function type */
! attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (type));
! if (attr)
! regparm = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr)));
!
! if (regparm >= 3)
{
/* ??? Need to count the actual number of registers to be used,
not the possible number of registers. Fix later. */
--- 1532,1545 ----
such registers are not used for passing parameters. */
if (!decl && !TARGET_64BIT)
{
! tree type;
/* We're looking at the CALL_EXPR, we need the type of the function. */
type = TREE_OPERAND (exp, 0); /* pointer expression */
type = TREE_TYPE (type); /* pointer type */
type = TREE_TYPE (type); /* function type */
! if (ix86_function_regparm (type, NULL) >= 3)
{
/* ??? Need to count the actual number of registers to be used,
not the possible number of registers. Fix later. */
*************** ix86_handle_regparm_attribute (tree *nod
*** 1637,1645 ****
}
if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node)))
! {
! error ("fastcall and regparm attributes are not compatible");
! }
}
return NULL_TREE;
--- 1632,1640 ----
}
if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node)))
! {
! error ("fastcall and regparm attributes are not compatible");
! }
}
return NULL_TREE;
*************** ix86_comp_type_attributes (tree type1, t
*** 1670,1687 ****
return 1;
}
! /* Return the regparm value for a fuctio with the indicated TYPE. */
static int
! ix86_fntype_regparm (tree type)
{
tree attr;
! attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (type));
! if (attr)
! return TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr)));
! else
! return ix86_regparm;
}
/* Value is the number of bytes of arguments automatically
--- 1665,1713 ----
return 1;
}
! /* Return the regparm value for a fuctio with the indicated TYPE and DECL.
! DECL may be NULL when calling function indirectly
! or considerling a libcall. */
static int
! ix86_function_regparm (tree type, tree decl)
{
tree attr;
+ int regparm = ix86_regparm;
+ bool user_convention = false;
! if (!TARGET_64BIT)
! {
! attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (type));
! if (attr)
! {
! regparm = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr)));
! user_convention = true;
! }
!
! if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type)))
! {
! regparm = 2;
! user_convention = true;
! }
!
! /* Use register calling convention for local functions when possible. */
! if (!TARGET_64BIT && !user_convention && decl
! && flag_unit_at_a_time)
! {
! struct cgraph_local_info *i = cgraph_local_info (decl);
! if (i && i->local)
! {
! /* We can't use regparm(3) for nested functions as these use
! static chain pointer in third argument. */
! if (DECL_CONTEXT (decl) && !DECL_NO_STATIC_CHAIN (decl))
! regparm = 2;
! else
! regparm = 3;
! }
! }
! }
! return regparm;
}
/* Value is the number of bytes of arguments automatically
*************** ix86_return_pops_args (tree fundecl, tre
*** 1725,1731 ****
if (aggregate_value_p (TREE_TYPE (funtype))
&& !TARGET_64BIT)
{
! int nregs = ix86_fntype_regparm (funtype);
if (!nregs)
return GET_MODE_SIZE (Pmode);
--- 1751,1757 ----
if (aggregate_value_p (TREE_TYPE (funtype))
&& !TARGET_64BIT)
{
! int nregs = ix86_function_regparm (funtype, fundecl);
if (!nregs)
return GET_MODE_SIZE (Pmode);
*************** init_cumulative_args (CUMULATIVE_ARGS *c
*** 1767,1773 ****
{
static CUMULATIVE_ARGS zero_cum;
tree param, next_param;
- bool user_convention = false;
if (TARGET_DEBUG_ARG)
{
--- 1793,1798 ----
*************** init_cumulative_args (CUMULATIVE_ARGS *c
*** 1786,1803 ****
*cum = zero_cum;
/* Set up the number of registers to use for passing arguments. */
! cum->nregs = ix86_regparm;
cum->sse_nregs = SSE_REGPARM_MAX;
- if (fntype && !TARGET_64BIT)
- {
- tree attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (fntype));
-
- if (attr)
- {
- cum->nregs = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr)));
- user_convention = true;
- }
- }
cum->maybe_vaarg = false;
/* Use ecx and edx registers if function has fastcall attribute */
--- 1811,1821 ----
*cum = zero_cum;
/* Set up the number of registers to use for passing arguments. */
! if (fntype)
! cum->nregs = ix86_function_regparm (fntype, fndecl);
! else
! cum->nregs = ix86_regparm;
cum->sse_nregs = SSE_REGPARM_MAX;
cum->maybe_vaarg = false;
/* Use ecx and edx registers if function has fastcall attribute */
*************** init_cumulative_args (CUMULATIVE_ARGS *c
*** 1807,1829 ****
{
cum->nregs = 2;
cum->fastcall = 1;
- user_convention = true;
- }
- }
-
- /* Use register calling convention for local functions when possible. */
- if (!TARGET_64BIT && !user_convention && fndecl
- && flag_unit_at_a_time)
- {
- struct cgraph_local_info *i = cgraph_local_info (fndecl);
- if (i && i->local)
- {
- /* We can't use regparm(3) for nested functions as these use
- static chain pointer in third argument. */
- if (DECL_CONTEXT (fndecl) && !DECL_NO_STATIC_CHAIN (fndecl))
- cum->nregs = 2;
- else
- cum->nregs = 3;
}
}
--- 1825,1830 ----
*************** function_arg (CUMULATIVE_ARGS *cum, /* c
*** 2501,2507 ****
/* ECX not EAX is the first allocated register. */
if (regno == 0)
! regno = 2;
}
ret = gen_rtx_REG (mode, regno);
}
--- 2502,2508 ----
/* ECX not EAX is the first allocated register. */
if (regno == 0)
! regno = 2;
}
ret = gen_rtx_REG (mode, regno);
}
*************** x86_this_parameter (tree function)
*** 15069,15075 ****
return gen_rtx_REG (DImode, x86_64_int_parameter_registers[n]);
}
! if (ix86_fntype_regparm (type) > 0)
{
tree parm;
--- 15070,15076 ----
return gen_rtx_REG (DImode, x86_64_int_parameter_registers[n]);
}
! if (ix86_function_regparm (type, function) > 0)
{
tree parm;
*************** x86_this_parameter (tree function)
*** 15079,15087 ****
for (; parm; parm = TREE_CHAIN (parm))
if (TREE_VALUE (parm) == void_type_node)
break;
! /* If not, the this parameter is in %eax. */
if (parm)
! return gen_rtx_REG (SImode, 0);
}
if (aggregate_value_p (TREE_TYPE (type)))
--- 15080,15093 ----
for (; parm; parm = TREE_CHAIN (parm))
if (TREE_VALUE (parm) == void_type_node)
break;
! /* If not, the this parameter is in the first argument. */
if (parm)
! {
! int regno = 0;
! if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type)))
! regno = 2;
! return gen_rtx_REG (SImode, 0);
! }
}
if (aggregate_value_p (TREE_TYPE (type)))
*************** x86_can_output_mi_thunk (tree thunk ATTR
*** 15102,15108 ****
return true;
/* For 32-bit, everything's fine if we have one free register. */
! if (ix86_fntype_regparm (TREE_TYPE (function)) < 3)
return true;
/* Need a free register for vcall_offset. */
--- 15108,15114 ----
return true;
/* For 32-bit, everything's fine if we have one free register. */
! if (ix86_function_regparm (TREE_TYPE (function), function) < 3)
return true;
/* Need a free register for vcall_offset. */
*************** x86_output_mi_thunk (FILE *file ATTRIBUT
*** 15173,15179 ****
if (TARGET_64BIT)
tmp = gen_rtx_REG (DImode, FIRST_REX_INT_REG + 2 /* R10 */);
else
! tmp = gen_rtx_REG (SImode, 2 /* ECX */);
xops[0] = gen_rtx_MEM (Pmode, this_reg);
xops[1] = tmp;
--- 15179,15191 ----
if (TARGET_64BIT)
tmp = gen_rtx_REG (DImode, FIRST_REX_INT_REG + 2 /* R10 */);
else
! {
! int tmp_regno = 2 /* ECX */;
! if (lookup_attribute ("fastcall",
! TYPE_ATTRIBUTES (TREE_TYPE (function))))
! tmp_regno = 0 /* EAX */;
! tmp = gen_rtx_REG (SImode, tmp_regno);
! }
xops[0] = gen_rtx_MEM (Pmode, this_reg);
xops[1] = tmp;