This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Question about how to re-initialize call_used registers via init_regs()
- From: Jan Hubicka <hubicka at ucw dot cz>
- To: Kai Tietz <Kai dot Tietz at onevision dot com>
- Cc: Jan Hubicka <hubicka at ucw dot cz>, gcc-patches at gcc dot gnu dot org, Jan Hubicka <jh at suse dot cz>, Michael Meissner <meissner at linux dot vnet dot ibm dot com>, Richard Guenther <rguenther at suse dot de>, ktietz70 at googlemail dot com
- Date: Sun, 7 Dec 2008 16:28:18 +0100
- Subject: Re: Question about how to re-initialize call_used registers via init_regs()
- References: <20081205113135.GA15467@atrey.karlin.mff.cuni.cz> <OF18B91104.4670A037-ONC1257516.004EA165-C1257516.004F5EA3@onevision.de>
Hi,
this is my current version of patch. I've made
CONDITIONAL_CALL_USED_REGISTERS to initialize regs correctly so we don't
need to initialize multiple times and also use rtl expansion hook to
initialize them instead of re-computing each time we switch function
context.
Patch also add proper clobbering code to call instructions when calling
MS->SYSV
Does it seems to run? If not can I have testcases? :))
Honza
Index: gcc/tree.c
===================================================================
*** gcc/tree.c (revision 142536)
--- gcc/tree.c (working copy)
*************** get_callee_fndecl (const_tree call)
*** 6854,6859 ****
--- 6854,6861 ----
if (TREE_CODE (addr) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (addr, 0)) == FUNCTION_DECL)
return TREE_OPERAND (addr, 0);
+ if (TREE_CODE(addr) == FUNCTION_DECL)
+ return addr;
/* We couldn't figure out what was being called. */
return NULL_TREE;
Index: gcc/function.c
===================================================================
*** gcc/function.c (revision 142536)
--- gcc/function.c (working copy)
*************** aggregate_value_p (const_tree exp, const
*** 1766,1772 ****
{
case CALL_EXPR:
fndecl = get_callee_fndecl (fntype);
! fntype = fndecl ? TREE_TYPE (fndecl) : 0;
break;
case FUNCTION_DECL:
fndecl = fntype;
--- 1766,1773 ----
{
case CALL_EXPR:
fndecl = get_callee_fndecl (fntype);
! fntype = fndecl ? TREE_TYPE (fndecl)
! : TREE_TYPE (CALL_EXPR_FN (fntype));
break;
case FUNCTION_DECL:
fndecl = fntype;
Index: gcc/calls.c
===================================================================
*** gcc/calls.c (revision 142536)
--- gcc/calls.c (working copy)
*************** static int compute_argument_block_size (
*** 136,142 ****
static void initialize_argument_information (int, struct arg_data *,
struct args_size *, int,
tree, tree,
! tree, CUMULATIVE_ARGS *, int,
rtx *, int *, int *, int *,
bool *, bool);
static void compute_argument_addresses (struct arg_data *, rtx, int);
--- 136,142 ----
static void initialize_argument_information (int, struct arg_data *,
struct args_size *, int,
tree, tree,
! tree, tree, CUMULATIVE_ARGS *, int,
rtx *, int *, int *, int *,
bool *, bool);
static void compute_argument_addresses (struct arg_data *, rtx, int);
*************** initialize_argument_information (int num
*** 938,944 ****
struct args_size *args_size,
int n_named_args ATTRIBUTE_UNUSED,
tree exp, tree struct_value_addr_value,
! tree fndecl,
CUMULATIVE_ARGS *args_so_far,
int reg_parm_stack_space,
rtx *old_stack_level, int *old_pending_adj,
--- 938,944 ----
struct args_size *args_size,
int n_named_args ATTRIBUTE_UNUSED,
tree exp, tree struct_value_addr_value,
! tree fndecl, tree fntype,
CUMULATIVE_ARGS *args_so_far,
int reg_parm_stack_space,
rtx *old_stack_level, int *old_pending_adj,
*************** initialize_argument_information (int num
*** 1119,1125 ****
mode = TYPE_MODE (type);
unsignedp = TYPE_UNSIGNED (type);
! if (targetm.calls.promote_function_args (fndecl ? TREE_TYPE (fndecl) : 0))
mode = promote_mode (type, mode, &unsignedp, 1);
args[i].unsignedp = unsignedp;
--- 1119,1125 ----
mode = TYPE_MODE (type);
unsignedp = TYPE_UNSIGNED (type);
! if (targetm.calls.promote_function_args (fndecl ? TREE_TYPE (fndecl) : fntype))
mode = promote_mode (type, mode, &unsignedp, 1);
args[i].unsignedp = unsignedp;
*************** expand_call (tree exp, rtx target, int i
*** 2088,2094 ****
/* Set up a place to return a structure. */
/* Cater to broken compilers. */
! if (aggregate_value_p (exp, fndecl))
{
/* This call returns a big structure. */
flags &= ~(ECF_CONST | ECF_PURE | ECF_LOOPING_CONST_OR_PURE);
--- 2088,2094 ----
/* Set up a place to return a structure. */
/* Cater to broken compilers. */
! if (aggregate_value_p (exp, (!fndecl ? fntype : fndecl)))
{
/* This call returns a big structure. */
flags &= ~(ECF_CONST | ECF_PURE | ECF_LOOPING_CONST_OR_PURE);
*************** expand_call (tree exp, rtx target, int i
*** 2245,2251 ****
arguments into ARGS_SIZE, etc. */
initialize_argument_information (num_actuals, args, &args_size,
n_named_args, exp,
! structure_value_addr_value, fndecl,
&args_so_far, reg_parm_stack_space,
&old_stack_level, &old_pending_adj,
&must_preallocate, &flags,
--- 2245,2251 ----
arguments into ARGS_SIZE, etc. */
initialize_argument_information (num_actuals, args, &args_size,
n_named_args, exp,
! structure_value_addr_value, fndecl, fntype,
&args_so_far, reg_parm_stack_space,
&old_stack_level, &old_pending_adj,
&must_preallocate, &flags,
*************** expand_call (tree exp, rtx target, int i
*** 2296,2301 ****
--- 2296,2304 ----
It does not seem worth the effort since few optimizable
sibling calls will return a structure. */
|| structure_value_addr != NULL_RTX
+ /* If outgoing reg parm stack space changes, we can not do sibcall. */
+ || (OUTGOING_REG_PARM_STACK_SPACE (fntype)
+ != OUTGOING_REG_PARM_STACK_SPACE (TREE_TYPE (current_function_decl)))
/* Check whether the target is able to optimize the call
into a sibcall. */
|| !targetm.function_ok_for_sibcall (fndecl, exp)
Index: gcc/config/i386/i386.h
===================================================================
*** gcc/config/i386/i386.h (revision 142536)
--- gcc/config/i386/i386.h (working copy)
*************** do { \
*** 964,970 ****
for (i = FIRST_REX_SSE_REG; i <= LAST_REX_SSE_REG; i++) \
reg_names[i] = ""; \
} \
! if (TARGET_64BIT && DEFAULT_ABI == MS_ABI) \
{ \
call_used_regs[4 /*RSI*/] = 0; \
call_used_regs[5 /*RDI*/] = 0; \
--- 964,972 ----
for (i = FIRST_REX_SSE_REG; i <= LAST_REX_SSE_REG; i++) \
reg_names[i] = ""; \
} \
! if (TARGET_64BIT \
! && ((cfun && cfun->machine->call_abi == MS_ABI) \
! || (!cfun && DEFAULT_ABI == MS_ABI))) \
{ \
call_used_regs[4 /*RSI*/] = 0; \
call_used_regs[5 /*RDI*/] = 0; \
Index: gcc/config/i386/i386.md
===================================================================
*** gcc/config/i386/i386.md (revision 142536)
--- gcc/config/i386/i386.md (working copy)
***************
*** 226,231 ****
--- 226,232 ----
(UNSPECV_CLD 15)
(UNSPECV_VZEROALL 16)
(UNSPECV_VZEROUPPER 17)
+ (UNSPECV_MS_TO_SYSV_CALL 18)
])
;; Constants to represent pcomtrue/pcomfalse variants
***************
*** 15039,15044 ****
--- 15040,15059 ----
}
[(set_attr "type" "call")])
+ (define_insn "call_1_rex64_ms_sysv"
+ [(call (mem:QI (match_operand:DI 0 "call_insn_operand" "rsm"))
+ (match_operand 1 "" ""))
+ (unspec_volatile [(const_int 0)] UNSPECV_MS_TO_SYSV_CALL)
+ (clobber (reg:DI SI_REG))
+ (clobber (reg:DI DI_REG))]
+ "!SIBLING_CALL_P (insn) && TARGET_64BIT"
+ {
+ if (constant_call_address_operand (operands[0], Pmode))
+ return "call\t%P0";
+ return "call\t%A0";
+ }
+ [(set_attr "type" "call")])
+
(define_insn "*call_1_rex64_large"
[(call (mem:QI (match_operand:DI 0 "call_insn_operand" "rm"))
(match_operand 1 "" ""))]
***************
*** 21361,21366 ****
--- 21376,21397 ----
}
[(set_attr "type" "callv")])
+ (define_insn "*call_value_0_rex64_ms_sysv"
+ [(set (match_operand 0 "" "")
+ (call (mem:QI (match_operand:DI 1 "constant_call_address_operand" ""))
+ (match_operand:DI 2 "const_int_operand" "")))
+ (unspec_volatile [(const_int 0)] UNSPECV_MS_TO_SYSV_CALL)
+ (clobber (reg:DI SI_REG))
+ (clobber (reg:DI DI_REG))]
+ "TARGET_64BIT"
+ {
+ if (SIBLING_CALL_P (insn))
+ return "jmp\t%P1";
+ else
+ return "call\t%P1";
+ }
+ [(set_attr "type" "callv")])
+
(define_insn "*call_value_1"
[(set (match_operand 0 "" "")
(call (mem:QI (match_operand:SI 1 "call_insn_operand" "rsm"))
***************
*** 21398,21403 ****
--- 21429,21449 ----
}
[(set_attr "type" "callv")])
+ (define_insn "*call_value_1_rex64_sysv_ms"
+ [(set (match_operand 0 "" "")
+ (call (mem:QI (match_operand:DI 1 "call_insn_operand" "rsm"))
+ (match_operand:DI 2 "" "")))
+ (unspec_volatile [(const_int 0)] UNSPECV_MS_TO_SYSV_CALL)
+ (clobber (reg:DI SI_REG))
+ (clobber (reg:DI DI_REG))]
+ "!SIBLING_CALL_P (insn) && TARGET_64BIT"
+ {
+ if (constant_call_address_operand (operands[1], Pmode))
+ return "call\t%P1";
+ return "call\t%A1";
+ }
+ [(set_attr "type" "callv")])
+
(define_insn "*call_value_1_rex64_large"
[(set (match_operand 0 "" "")
(call (mem:QI (match_operand:DI 1 "call_insn_operand" "rm"))
Index: gcc/config/i386/i386.c
===================================================================
*** gcc/config/i386/i386.c (revision 142536)
--- gcc/config/i386/i386.c (working copy)
*************** tree (*ix86_veclib_handler)(enum built_i
*** 1926,1931 ****
--- 1926,1936 ----
static tree ix86_veclibabi_svml (enum built_in_function, tree, tree);
static tree ix86_veclibabi_acml (enum built_in_function, tree, tree);
+ /* Ugly hack. We don't have any way to communicate ABI to expand_call
+ expander. Set it while processing arguments that is always done
+ just before expanding the call. */
+ static enum calling_abi last_function_call_abi;
+
/* Processor target table, indexed by processor number */
struct ptt
{
*************** extern void init_regs (void);
*** 4603,4611 ****
/* Implementation of call abi switching target hook. Specific to FNDECL
the specific call register sets are set. See also CONDITIONAL_REGISTER_USAGE
! for more details.
! To prevent redudant calls of costy function init_regs (), it checks not to
! reset register usage for default abi. */
void
ix86_call_abi_override (const_tree fndecl)
{
--- 4608,4614 ----
/* Implementation of call abi switching target hook. Specific to FNDECL
the specific call register sets are set. See also CONDITIONAL_REGISTER_USAGE
! for more details. */
void
ix86_call_abi_override (const_tree fndecl)
{
*************** ix86_call_abi_override (const_tree fndec
*** 4613,4636 ****
cfun->machine->call_abi = DEFAULT_ABI;
else
cfun->machine->call_abi = ix86_function_type_abi (TREE_TYPE (fndecl));
! if (TARGET_64BIT && cfun->machine->call_abi == MS_ABI)
! {
! if (call_used_regs[4 /*RSI*/] != 0 || call_used_regs[5 /*RDI*/] != 0)
! {
! call_used_regs[4 /*RSI*/] = 0;
! call_used_regs[5 /*RDI*/] = 0;
! init_regs ();
! }
! }
! else if (TARGET_64BIT)
! {
! if (call_used_regs[4 /*RSI*/] != 1 || call_used_regs[5 /*RDI*/] != 1)
! {
! call_used_regs[4 /*RSI*/] = 1;
! call_used_regs[5 /*RDI*/] = 1;
! init_regs ();
! }
! }
}
/* Initialize a variable CUM of type CUMULATIVE_ARGS
--- 4616,4632 ----
cfun->machine->call_abi = DEFAULT_ABI;
else
cfun->machine->call_abi = ix86_function_type_abi (TREE_TYPE (fndecl));
! }
!
! /* MS and SYSV ABI have different set of call used registers. Avoid expensive
! re-initialization of init_regs each time we switch function context since
! this is needed only during RTL expansion. */
! static void
! ix86_maybe_switch_abi (void)
! {
! if (TARGET_64BIT &&
! call_used_regs[4 /*RSI*/] == (cfun->machine->call_abi == MS_ABI))
! init_regs ();
}
/* Initialize a variable CUM of type CUMULATIVE_ARGS
*************** init_cumulative_args (CUMULATIVE_ARGS *c
*** 4646,4652 ****
struct cgraph_local_info *i = fndecl ? cgraph_local_info (fndecl) : NULL;
memset (cum, 0, sizeof (*cum));
! cum->call_abi = ix86_function_type_abi (fntype);
/* Set up the number of registers to use for passing arguments. */
cum->nregs = ix86_regparm;
if (TARGET_64BIT)
--- 4642,4648 ----
struct cgraph_local_info *i = fndecl ? cgraph_local_info (fndecl) : NULL;
memset (cum, 0, sizeof (*cum));
! last_function_call_abi = cum->call_abi = ix86_function_type_abi (fntype);
/* Set up the number of registers to use for passing arguments. */
cum->nregs = ix86_regparm;
if (TARGET_64BIT)
*************** ix86_expand_call (rtx retval, rtx fnaddr
*** 18164,18169 ****
--- 18160,18177 ----
pop = gen_rtx_PLUS (Pmode, stack_pointer_rtx, pop);
pop = gen_rtx_SET (VOIDmode, stack_pointer_rtx, pop);
call = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, call, pop));
+ gcc_assert (ix86_cfun_abi () != MS_ABI || last_function_call_abi != SYSV_ABI);
+ }
+ /* We need to represent that SI and DI registers are clobbered by SYSV calls.
+ */
+ if (ix86_cfun_abi () == MS_ABI && last_function_call_abi == SYSV_ABI)
+ {
+ rtx clobber1 = gen_rtx_CLOBBER (DImode, gen_rtx_REG (DImode, SI_REG));
+ rtx clobber2 = gen_rtx_CLOBBER (DImode, gen_rtx_REG (DImode, DI_REG));
+ rtx unspec = gen_rtx_UNSPEC_VOLATILE (VOIDmode, gen_rtvec (1, const0_rtx),
+ UNSPECV_MS_TO_SYSV_CALL);
+ call = gen_rtx_PARALLEL (VOIDmode,
+ gen_rtvec (4, call, unspec, clobber1, clobber2));
}
call = emit_call_insn (call);
*************** ix86_enum_va_list (int idx, const char *
*** 29243,29248 ****
--- 29251,29259 ----
#undef TARGET_OPTION_CAN_INLINE_P
#define TARGET_OPTION_CAN_INLINE_P ix86_can_inline_p
+ #undef TARGET_EXPAND_TO_RTL_HOOK
+ #define TARGET_EXPAND_TO_RTL_HOOK ix86_maybe_switch_abi
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-i386.h"