Question about how to re-initialize call_used registers via init_regs()

Jan Hubicka hubicka@ucw.cz
Sun Dec 7 16:35:00 GMT 2008


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"



More information about the Gcc-patches mailing list