This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

reworked long_call heuristic patch.



Hello Nick,

I'm sending the reworked patch.  This time base sources were taken
from arm-thumb cvs branch.  I do not use SYMBOL_REF_FLAG anymore.
However now there are still at least two 'weak' points which I'm not
quite sure about.  First, in gcc/tree.c and gcc/cp/tree.c when new
function or method types are being built, hash table is checked for
existence of the same type and if found the tree_type pointer of the
function declaration is set to point to the found tree node.  Thus
there can be many function declaration tree nodes that share the same
tree_type nodes.  It is a problem when type attributes need to be set.
Assigning attributes to such shared type breaks the long-call
heuristic.  For now I parenthesized all the hash table checks in #if
0/#endif, thus making every fundecl tree node have its own copy of
corresponding tree_type node.  I don't think this is a correct
solution. But I don't think that decls should share type nodes either.
Second I'm assigning short_call attributes to functions declared
static from ENCODE_SECTION_INFO.  I'm not sure whether this is the
correct place to do this.  Otherwise there's very little different
from original patch, while I also tried to minimize the changes in all
three arm.[hc]/md files.  One more thing -- arm_comp_type_attributes
doesn't work at all.  With current arm_comp_type_attributes compiler
rejects all __attribute__ syntax, therefore for the testing purposes I
just return 1 from arm_comp_type_attributes all the time.  I don't
know what it is needed for at all, so I didn't do anything with it.
Finally, I noticed last time you applied the patch without updating
*.texi files.  If this is intentional and the changes should be
reworked, please let me know.  In any case I assume the long-call
support in ARM should be documented.

I guess no new ChangeLog entry is needed with this patch...

Regards,
Dmitri.

Here's the patch.

Index: gcc/extend.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/extend.texi,v
retrieving revision 1.38.2.1
diff -c -3 -p -r1.38.2.1 extend.texi
*** extend.texi	2000/01/13 16:09:55	1.38.2.1
--- extend.texi	2000/02/19 02:20:33
*************** compiler to always call the function via
*** 1613,1618 ****
--- 1613,1627 ----
  which reside further than 64 megabytes (67,108,864 bytes) from the
  current location can be called.
  
+ @item long_call/short_call
+ @cindex indirect calls on ARM
+ This attribute allows to specify how to call a particular function on
+ ARM.  Both attribute override @code{-mlong-calls} (@pxref{ARM Options})
+ command line switch and @code{#pragma long_calls} settings.  The
+ @code{long_call} attribute causes the compiler to always call the
+ function via a pointer and the @code{short_call} attribute to always
+ call the function via @samp{BL} instruction.
+ 
  @item dllimport
  @cindex functions which are imported from a dll on PowerPC Windows NT
  On the PowerPC running Windows NT, the @code{dllimport} attribute causes
Index: gcc/invoke.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/invoke.texi,v
retrieving revision 1.147.2.2
diff -c -3 -p -r1.147.2.2 invoke.texi
*** invoke.texi	2000/01/13 16:10:02	1.147.2.2
--- invoke.texi	2000/02/19 02:20:38
*************** in the following sections.
*** 269,274 ****
--- 269,275 ----
  -mstructure-size-boundary=
  -mbsd -mxopen -mno-symrename
  -mabort-on-noreturn
+ -mlong-calls -mno-long-calls
  -mnop-fun-dllimport -mno-nop-fun-dllimport
  -msingle-pic-base -mno-single-pic-base
  -mpic-register=
*************** value as future versions of the toolchai
*** 4577,4582 ****
--- 4578,4593 ----
  @kindex -mnoabort-on-noreturn
  Generate a call to the function abort at the end of a noreturn function.
  It will be executed if the function tries to return.
+ 
+ @item -mlong-calls
+ @itemx -mno-long-calls
+ Do calls indirect with loading of 32-bit address of the callee into
+ @samp{PC} register.  You need to use this switch, if you call outside of
+ the current 64 megabyte segment to functions that are not through
+ pointers.  Not all calls made indirect when this option is used.  The
+ heuristic is that functions declared static and also the functions which
+ definitions have been seen in the same source file, before the call in
+ question being parsed, are close enough and need not be called indirectly.
  
  @item -mnop-fun-dllimport
  @kindex -mnop-fun-dllimport
Index: gcc/tree.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/tree.c,v
retrieving revision 1.98.2.1
diff -c -3 -p -r1.98.2.1 tree.c
*** tree.c	2000/01/13 16:10:08	1.98.2.1
--- tree.c	2000/02/19 02:20:40
*************** build_function_type (value_type, arg_typ
*** 4464,4472 ****
    TREE_TYPE (t) = value_type;
    TYPE_ARG_TYPES (t) = arg_types;
  
!   /* If we already have such a type, use the old one and free this one.  */
    hashcode = TYPE_HASH (value_type) + type_hash_list (arg_types);
    t = type_hash_canon (hashcode, t);
  
    if (TYPE_SIZE (t) == 0)
      layout_type (t);
--- 4464,4478 ----
    TREE_TYPE (t) = value_type;
    TYPE_ARG_TYPES (t) = arg_types;
  
! #if 0
!   /* to support long-call heuristic each function decl node must have
!      its own copy of funtype node, because otherwise changing
!      attributes of a funtype affects all decls having the same funtype 
!   */
!   /* If we already have such a type, use the old one and free this one. */
    hashcode = TYPE_HASH (value_type) + type_hash_list (arg_types);
    t = type_hash_canon (hashcode, t);
+ #endif
  
    if (TYPE_SIZE (t) == 0)
      layout_type (t);
*************** build_method_type (basetype, type)
*** 4501,4509 ****
--- 4507,4521 ----
      = tree_cons (NULL_TREE,
  		 build_pointer_type (basetype), TYPE_ARG_TYPES (type));
  
+ #if 0
+   /* to support long-call heuristic each function decl node must have
+      its own copy of funtype node, because otherwise changing
+      attributes of a funtype affects all decls having the same funtype 
+   */
    /* If we already have such a type, use the old one and free this one.  */
    hashcode = TYPE_HASH (basetype) + TYPE_HASH (type);
    t = type_hash_canon (hashcode, t);
+ #endif
  
    if (TYPE_SIZE (t) == 0)
      layout_type (t);
Index: gcc/config/arm/arm-protos.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/arm/arm-protos.h,v
retrieving revision 1.1.2.5
diff -c -3 -p -r1.1.2.5 arm-protos.h
*** arm-protos.h	2000/02/09 21:48:11	1.1.2.5
--- arm-protos.h	2000/02/19 02:20:42
*************** extern void   output_func_epilogue	PARAM
*** 35,44 ****
  extern void   arm_expand_prologue	PARAMS ((void));
  
  #ifdef TREE_CODE
! extern int    arm_return_in_memory	PARAMS ((tree));
  extern int    arm_valid_machine_decl_attribute	PARAMS ((tree, tree, tree));
! extern int    arm_comp_type_attributes	PARAMS ((tree, tree));
! extern int    arm_valid_type_attribute_p PARAMS ((tree, tree, tree, tree));
  #endif
  #ifdef RTX_CODE
  extern int    const_ok_for_arm		PARAMS ((HOST_WIDE_INT));
--- 35,46 ----
  extern void   arm_expand_prologue	PARAMS ((void));
  
  #ifdef TREE_CODE
! extern int    arm_return_in_memory		PARAMS ((tree));
  extern int    arm_valid_machine_decl_attribute	PARAMS ((tree, tree, tree));
! extern int    arm_comp_type_attributes		PARAMS ((tree, tree));
! extern int    arm_valid_type_attribute_p	PARAMS ((tree, tree, tree, tree));
! extern void   arm_set_default_type_attributes	PARAMS ((tree));
! extern void   arm_set_short_call_attribute	PARAMS ((tree));
  #endif
  #ifdef RTX_CODE
  extern int    const_ok_for_arm		PARAMS ((HOST_WIDE_INT));
*************** extern void   arm_print_operand		PARAMS 
*** 126,132 ****
  extern void   arm_final_prescan_insn	PARAMS ((rtx));
  extern int    arm_go_if_legitimate_address PARAMS ((enum machine_mode, rtx));
  extern int    arm_debugger_arg_offset	PARAMS ((int, rtx));
! 
  #if defined TREE_CODE
  extern rtx    arm_function_arg		PARAMS ((CUMULATIVE_ARGS *,
  						enum machine_mode, tree, int));
--- 128,134 ----
  extern void   arm_final_prescan_insn	PARAMS ((rtx));
  extern int    arm_go_if_legitimate_address PARAMS ((enum machine_mode, rtx));
  extern int    arm_debugger_arg_offset	PARAMS ((int, rtx));
! extern int    arm_is_long_call_p 	PARAMS ((rtx, int, int));
  #if defined TREE_CODE
  extern rtx    arm_function_arg		PARAMS ((CUMULATIVE_ARGS *,
  						enum machine_mode, tree, int));
Index: gcc/config/arm/arm.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/arm/arm.c,v
retrieving revision 1.68.2.20
diff -c -3 -p -r1.68.2.20 arm.c
*** arm.c	2000/02/10 13:59:01	1.68.2.20
--- arm.c	2000/02/19 02:20:45
*************** arm_override_options ()
*** 421,427 ****
  	}
        else if (! TARGET_APCS_32)
  	sought |= FL_MODE26;
!       
        if (sought != 0 && ((sought & insn_flags) != sought))
  	{
  	  /* Try to locate a CPU type that supports all of the abilities
--- 421,427 ----
  	}
        else if (! TARGET_APCS_32)
  	sought |= FL_MODE26;
! 
        if (sought != 0 && ((sought & insn_flags) != sought))
  	{
  	  /* Try to locate a CPU type that supports all of the abilities
*************** use_return_insn (iscond)
*** 684,690 ****
       if they aren't taken and registers have been stacked.  */
    if (iscond && arm_is_strong && frame_pointer_needed)
      return 0;
!   
    if ((iscond && arm_is_strong)
        || TARGET_INTERWORK)
      {
--- 684,690 ----
       if they aren't taken and registers have been stacked.  */
    if (iscond && arm_is_strong && frame_pointer_needed)
      return 0;
! 
    if ((iscond && arm_is_strong)
        || TARGET_INTERWORK)
      {
*************** arm_return_in_memory (type)
*** 1543,1560 ****
     For a library call, FNTYPE is 0.  */
  void
  arm_init_cumulative_args (pcum, fntype, libname, indirect)
!      CUMULATIVE_ARGS * pcum;
!      tree fntype;
!      rtx libname  ATTRIBUTE_UNUSED;
!      int indirect ATTRIBUTE_UNUSED;
  {
    /* On the ARM, the offset starts at 0.  */
!   pcum->nregs = ((fntype && aggregate_value_p (TREE_TYPE (fntype)))
! 		 ? 1 : 0);
!   pcum->long_call = (TARGET_LONG_CALLS
! 		     || (fntype
! 			 && lookup_attribute ("long_call",
! 					      TYPE_ATTRIBUTES (fntype))));
  }
  
  /* Determine where to put an argument to a function.
--- 1543,1568 ----
     For a library call, FNTYPE is 0.  */
  void
  arm_init_cumulative_args (pcum, fntype, libname, indirect)
!   CUMULATIVE_ARGS * pcum;
!   tree fntype;
!   rtx libname  ATTRIBUTE_UNUSED;
!   int indirect ATTRIBUTE_UNUSED;
  {
    /* On the ARM, the offset starts at 0.  */
!   pcum->nregs = ((fntype && aggregate_value_p (TREE_TYPE (fntype))) ? 1 : 0);
! 
!   pcum->long_call = CALL_NORMAL;
! 
!   /* check for long_call/short_call attribute  */
!   if (fntype && lookup_attribute ("long_call", TYPE_ATTRIBUTES (fntype)))
!     pcum->long_call = CALL_LONG;
! 
!   /* It is possible that a func declaration has both long_call and
!      short_call attributes.  For example if #pragma long_calls and
!      subsequent __attribute__ (short_call) present.  In this case
!      short_call overrides long_call. */
!   if (fntype && lookup_attribute ("short_call", TYPE_ATTRIBUTES (fntype)))
!     pcum->long_call = CALL_SHORT;
  }
  
  /* Determine where to put an argument to a function.
*************** arm_function_arg (pcum, mode, type, name
*** 1578,1592 ****
       int named;
  {
    if (mode == VOIDmode)
!     /* Compute operand 2 of the call insn.  */
!     return GEN_INT (pcum->long_call);
!   
    if (! named || pcum->nregs >= NUM_ARG_REGS)
      return 0;
    
    return gen_rtx_REG (mode, pcum->nregs);
  }
  
  /* Handle pragmas for compatibility with Intel's compilers.  */
  
  /* ??? This is incomplete, since it does not handle all pragmas that the
--- 1586,1607 ----
       int named;
  {
    if (mode == VOIDmode)
!     {
!       /* Compute operand 2 of the call insn.  */
!       return GEN_INT (pcum->long_call);
!     }
! 
    if (! named || pcum->nregs >= NUM_ARG_REGS)
      return 0;
    
    return gen_rtx_REG (mode, pcum->nregs);
  }
  
+ /* Non-zero iff #pragma long_calls is currently on.  The initial value
+    must be set to -1, because this is a three state flag, where 0
+    means short_calls and positive int means long_calls. */
+ int arm_pragma_long_calls = -1;
+ 
  /* Handle pragmas for compatibility with Intel's compilers.  */
  
  /* ??? This is incomplete, since it does not handle all pragmas that the
*************** arm_process_pragma (p_getc, p_ungetc, pn
*** 1600,1611 ****
  {
    /* Should be pragma 'far' or equivalent for callx/balx here.  */
    if (strcmp (pname, "long_calls") == 0)
!     target_flags |= ARM_FLAG_LONG_CALLS;
    else if (strcmp (pname, "no_long_calls") == 0)
!     target_flags &= ~ARM_FLAG_LONG_CALLS;
    else
      return 0;
!   
    return 1;
  }
  
--- 1615,1626 ----
  {
    /* Should be pragma 'far' or equivalent for callx/balx here.  */
    if (strcmp (pname, "long_calls") == 0)
!     arm_pragma_long_calls = 1;
    else if (strcmp (pname, "no_long_calls") == 0)
!     arm_pragma_long_calls = 0;
    else
      return 0;
! 
    return 1;
  }
  
*************** arm_valid_type_attribute_p (type, attrib
*** 1619,1624 ****
--- 1634,1640 ----
       tree identifier;
       tree args;
  {
+ 
    if (   TREE_CODE (type) != FUNCTION_TYPE
        && TREE_CODE (type) != METHOD_TYPE
        && TREE_CODE (type) != FIELD_DECL
*************** arm_valid_type_attribute_p (type, attrib
*** 1628,1636 ****
    /* Function calls made to this symbol must be done indirectly, because
       it may lie outside of the 26 bit addressing range of a normal function
       call.  */
    if (is_attribute_p ("long_call", identifier))
      return (args == NULL_TREE);
!   
    return 0;
  }
  
--- 1644,1659 ----
    /* Function calls made to this symbol must be done indirectly, because
       it may lie outside of the 26 bit addressing range of a normal function
       call.  */
+ 
    if (is_attribute_p ("long_call", identifier))
      return (args == NULL_TREE);
! 
!   /* Shortcall attribute overrides both command line switch
!      -mlong-calls and #pragma long_call. */
! 
!   if (is_attribute_p ("short_call", identifier))
!     return (args == NULL_TREE);
! 
    return 0;
  }
  
*************** arm_comp_type_attributes (type1, type2)
*** 1642,1660 ****
       tree type1;
       tree type2;
  {
    /* Check for mismatch of non-default calling convention. */
    if (TREE_CODE (type1) != FUNCTION_TYPE)
      return 1;
  
    /* Check for mismatched long_calls attribute.
       ??? Not sure this is necessary.  */
!   if (   ! lookup_attribute ("long_call", TYPE_ATTRIBUTES (type1))
!       != ! lookup_attribute ("long_call", TYPE_ATTRIBUTES (type2)))
!     return 0;
!   
!   return 1;
  }
  
  int
  legitimate_pic_operand_p (x)
       rtx x;
--- 1665,1810 ----
       tree type1;
       tree type2;
  {
+   int l1, l2, s1, s2;
+ 
+   return 1;
+ 
    /* Check for mismatch of non-default calling convention. */
    if (TREE_CODE (type1) != FUNCTION_TYPE)
      return 1;
  
    /* Check for mismatched long_calls attribute.
       ??? Not sure this is necessary.  */
! 
!   l1 = !! lookup_attribute ("long_call", TYPE_ATTRIBUTES (type1));
!   l2 = !! lookup_attribute ("long_call", TYPE_ATTRIBUTES (type2));
!   s1 = !! lookup_attribute ("short_call", TYPE_ATTRIBUTES (type1));
!   s2 = !! lookup_attribute ("short_call", TYPE_ATTRIBUTES (type2));
! 
!   return ! ((l1 ^ l2) || (s1 ^ s2) || (l1 & s2) || (s1 & l2));
  }
  
+ /*  Assigns default attributes to newly defined type.  This is used to
+     set short_call/long_call attributes for function types of
+     functions defined inside corresponding #pragma scopes. */
+ void
+ arm_set_default_type_attributes (type)
+   tree type;
+ {
+   /* add __attribute__ ((long_call)) to all functions, when
+      inside #pragma long_calls or __attribute__ ((short_call)),
+      when inside #pragma no_long_calls. */
+ 
+   if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE)
+     {
+       tree type_attr_list, attr_name;
+       type_attr_list = TYPE_ATTRIBUTES (type);
+ 
+       if (arm_pragma_long_calls > 0)
+ 	attr_name = get_identifier ("long_call");
+       else if (arm_pragma_long_calls == 0)
+ 	attr_name = get_identifier ("short_call");
+       else
+ 	return;
+ 
+       type_attr_list = tree_cons (attr_name, NULL_TREE, type_attr_list);
+       TYPE_ATTRIBUTES (type) = type_attr_list;
+     }
+ } /* arm_set_default_type_attributes */
+ 
+ /*  Assignes short_call attribute to the function type associated with 
+     DECL function declaration.  Normally the function is either
+     declared static or defined in the file being compiled.  For static 
+     function declarations this called from ENCODE_SECTION_INFO macro.
+     For functions just defined it is called from
+     ARM_DECLARE_FUNCTION_SIZE macro. */
+ void
+ arm_set_short_call_attribute (decl)
+   tree decl;
+ {
+   tree type;
+ 
+   if (TREE_CODE (decl) != FUNCTION_DECL)
+     return;
+   type = TREE_TYPE (decl);
+   if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE)
+     {
+       tree type_attr_list, attr_name;
+       type_attr_list = TYPE_ATTRIBUTES (type);
+       attr_name = get_identifier ("short_call");
+       type_attr_list = tree_cons (attr_name, NULL_TREE, type_attr_list);
+       TYPE_ATTRIBUTES (type) = type_attr_list;
+     }
+ } /* arm_declare_function_size */
+ 
+ /* Return non-zero if a 32 bit "long_call" should be generated for
+    this call. We generate a long_call if the function is not declared
+    __attribute__ ((shortcall),
+ 
+    AND:
+    
+    (1)  the function is declared __attribute__ ((long_call))
+         (either explicitly in the source code or implicitly
+ 	when the declaration is within a #pragma long_calls),
+ 
+    OR
+ 
+    (2) -mlong-calls is enabled and we don't know whether the target
+         function is defined in this file.
+ 	 
+    This function will typically be called by C fragments in the
+    machine description file. CALL_REF and CALL_COOKIE will correspond
+    to matched rtl operands. CALL_SYMBOL is used to distinguish between
+    two different callers of the function.  It is set to 1 in
+    define_insn "call_symbol" or "call_symbol_value" patterns in arm.md
+    and to 0 in define_expand "call" and "call_value".  This is because
+    of the difference of SYM_REFs passed from "call_symbol" and "call"
+    patterns.  */
+ 
+ int
+ arm_is_long_call_p (sym_ref, call_cookie, call_symbol)
+   rtx sym_ref;
+   int call_cookie;
+   int call_symbol;
+ {
+   if (GET_CODE (sym_ref) != MEM && ! call_symbol)
+     {
+       return 0;
+     }
+ 
+   if (! call_symbol)
+     {
+       sym_ref = XEXP (sym_ref, 0);
+     }
+ 
+   if (GET_CODE (sym_ref) != SYMBOL_REF)
+     {
+       return 0;
+     }
+ 
+   if (TARGET_LONG_CALLS && flag_function_sections)
+     {
+       return 1;
+     }
+ 
+   if (call_cookie & CALL_SHORT)
+     {
+       return 0;
+     }
+ 
+   if (sym_ref == XEXP (DECL_RTL (current_function_decl), 0))
+     {
+       return 0;
+     }
+ 
+   if ((call_cookie & CALL_LONG) || TARGET_LONG_CALLS)
+     {
+       return 1;
+     }
+ 
+   return 0;
+ } /* arm_is_long_call_p */
+ 
  int
  legitimate_pic_operand_p (x)
       rtx x;
*************** soft_df_operand (op, mode)
*** 2696,2702 ****
    
    if (GET_CODE (op) == SUBREG)
      op = SUBREG_REG (op);
!   
    switch (GET_CODE (op))
      {
      case CONST_DOUBLE:
--- 2846,2852 ----
    
    if (GET_CODE (op) == SUBREG)
      op = SUBREG_REG (op);
! 
    switch (GET_CODE (op))
      {
      case CONST_DOUBLE:
*************** cc_register (x, mode)
*** 2849,2855 ****
    if (mode == VOIDmode)
      {
        mode = GET_MODE (x);
!       
        if (GET_MODE_CLASS (mode) != MODE_CC)
  	return FALSE;
      }
--- 2999,3005 ----
    if (mode == VOIDmode)
      {
        mode = GET_MODE (x);
! 
        if (GET_MODE_CLASS (mode) != MODE_CC)
  	return FALSE;
      }
*************** dominant_cc_register (x, mode)
*** 2874,2880 ****
    if (mode == VOIDmode)
      {
        mode = GET_MODE (x);
!       
        if (GET_MODE_CLASS (mode) != MODE_CC)
  	return FALSE;
      }
--- 3024,3030 ----
    if (mode == VOIDmode)
      {
        mode = GET_MODE (x);
! 
        if (GET_MODE_CLASS (mode) != MODE_CC)
  	return FALSE;
      }
*************** symbol_mentioned_p (x)
*** 2901,2907 ****
      return 1;
  
    fmt = GET_RTX_FORMAT (GET_CODE (x));
!   
    for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
      {
        if (fmt[i] == 'E')
--- 3051,3057 ----
      return 1;
  
    fmt = GET_RTX_FORMAT (GET_CODE (x));
! 
    for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
      {
        if (fmt[i] == 'E')
*************** arm_gen_movstrqi (operands)
*** 3850,3856 ****
  	  MEM_IN_STRUCT_P (mem) = dst_in_struct_p;
  	  MEM_SCALAR_P (mem) = dst_scalar_p;
  	  emit_move_insn (mem, gen_rtx_SUBREG (QImode, part_bytes_reg, 0));
! 	  
  	  if (--last_bytes)
  	    {
  	      tmp = gen_reg_rtx (SImode);
--- 4000,4006 ----
  	  MEM_IN_STRUCT_P (mem) = dst_in_struct_p;
  	  MEM_SCALAR_P (mem) = dst_scalar_p;
  	  emit_move_insn (mem, gen_rtx_SUBREG (QImode, part_bytes_reg, 0));
! 
  	  if (--last_bytes)
  	    {
  	      tmp = gen_reg_rtx (SImode);
*************** output_call (operands)
*** 5283,5289 ****
        operands[0] = gen_rtx_REG (SImode, IP_REGNUM);
        output_asm_insn ("mov%?\t%0, %|lr", operands);
      }
!   
    output_asm_insn ("mov%?\t%|lr, %|pc", operands);
    
    if (TARGET_INTERWORK)
--- 5433,5439 ----
        operands[0] = gen_rtx_REG (SImode, IP_REGNUM);
        output_asm_insn ("mov%?\t%0, %|lr", operands);
      }
! 
    output_asm_insn ("mov%?\t%|lr, %|pc", operands);
    
    if (TARGET_INTERWORK)
*************** eliminate_lr2ip (x)
*** 5316,5329 ****
      default:
        /* Scan through the sub-elements and change any references there */
        fmt = GET_RTX_FORMAT (code);
!       
        for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
  	if (fmt[i] == 'e')
  	  something_changed |= eliminate_lr2ip (&XEXP (x0, i));
  	else if (fmt[i] == 'E')
  	  for (j = 0; j < XVECLEN (x0, i); j++)
  	    something_changed |= eliminate_lr2ip (&XVECEXP (x0, i, j));
!       
        return something_changed;
      }
  }
--- 5466,5479 ----
      default:
        /* Scan through the sub-elements and change any references there */
        fmt = GET_RTX_FORMAT (code);
! 
        for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
  	if (fmt[i] == 'e')
  	  something_changed |= eliminate_lr2ip (&XEXP (x0, i));
  	else if (fmt[i] == 'E')
  	  for (j = 0; j < XVECLEN (x0, i); j++)
  	    something_changed |= eliminate_lr2ip (&XVECEXP (x0, i, j));
! 
        return something_changed;
      }
  }
*************** output_mov_long_double_fpu_from_arm (ope
*** 5376,5382 ****
    
    output_asm_insn ("stm%?fd\t%|sp!, {%0, %1, %2}", ops);
    output_asm_insn ("ldf%?e\t%0, [%|sp], #12", operands);
!   
    return "";
  }
  
--- 5526,5532 ----
    
    output_asm_insn ("stm%?fd\t%|sp!, {%0, %1, %2}", ops);
    output_asm_insn ("ldf%?e\t%0, [%|sp], #12", operands);
! 
    return "";
  }
  
*************** output_move_double (operands)
*** 5538,5544 ****
  	      otherops[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
  	      operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
  	    }
! 	  
  	  output_mov_immediate (operands);
  	  output_mov_immediate (otherops);
  	}
--- 5688,5694 ----
  	      otherops[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
  	      operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
  	    }
! 
  	  output_mov_immediate (operands);
  	  output_mov_immediate (otherops);
  	}
*************** output_return_instruction (operand, real
*** 6204,6210 ****
      return "";
    
    return_used_this_function = 1;
!   
    if (TARGET_ABORT_NORETURN && volatile_func)
      {
        /* If this function was declared non-returning, and we have found a tail 
--- 6354,6360 ----
      return "";
    
    return_used_this_function = 1;
! 
    if (TARGET_ABORT_NORETURN && volatile_func)
      {
        /* If this function was declared non-returning, and we have found a tail 
*************** output_return_instruction (operand, real
*** 6226,6232 ****
        
    if (current_function_calls_alloca && ! really_return)
      abort ();
!   
    for (reg = 0; reg <= 10; reg++)
      if (regs_ever_live[reg] && ! call_used_regs[reg])
        live_regs++;
--- 6376,6382 ----
        
    if (current_function_calls_alloca && ! really_return)
      abort ();
! 
    for (reg = 0; reg <= 10; reg++)
      if (regs_ever_live[reg] && ! call_used_regs[reg])
        live_regs++;
*************** output_return_instruction (operand, real
*** 6307,6319 ****
  	    }
  	  
  	  strcat (instr, "%|");
! 	  
  	  if (TARGET_INTERWORK && really_return)
  	    strcat (instr, reg_names[IP_REGNUM]);
  	  else
  	    strcat (instr, really_return ? reg_names[PC_REGNUM] : reg_names[LR_REGNUM]);
  	}
!       
        strcat (instr, (TARGET_APCS_32 || !really_return) ? "}" : "}^");
        output_asm_insn (instr, &operand);
  
--- 6457,6469 ----
  	    }
  	  
  	  strcat (instr, "%|");
! 
  	  if (TARGET_INTERWORK && really_return)
  	    strcat (instr, reg_names[IP_REGNUM]);
  	  else
  	    strcat (instr, really_return ? reg_names[PC_REGNUM] : reg_names[LR_REGNUM]);
  	}
! 
        strcat (instr, (TARGET_APCS_32 || !really_return) ? "}" : "}^");
        output_asm_insn (instr, &operand);
  
*************** arm_output_epilogue ()
*** 6565,6571 ****
  	      if (regs_ever_live[reg] && ! call_used_regs[reg])
  		{
  		  floats_offset += 12;
! 		  
  		  /* We can't unstack more than four registers at once */
  		  if (start_reg - reg == 3)
  		    {
--- 6715,6721 ----
  	      if (regs_ever_live[reg] && ! call_used_regs[reg])
  		{
  		  floats_offset += 12;
! 
  		  /* We can't unstack more than four registers at once */
  		  if (start_reg - reg == 3)
  		    {
*************** arm_output_epilogue ()
*** 6694,6700 ****
  	      operands[2] = GEN_INT (current_function_pretend_args_size);
  	      output_add_immediate (operands);
  	    }
! 	  
  	  /* And finally, go home */
  	  if (TARGET_INTERWORK)
  	    asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
--- 6844,6850 ----
  	      operands[2] = GEN_INT (current_function_pretend_args_size);
  	      output_add_immediate (operands);
  	    }
! 
  	  /* And finally, go home */
  	  if (TARGET_INTERWORK)
  	    asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
*************** arm_final_prescan_insn (insn)
*** 7592,7598 ****
  	  if (reverse || then_not_else)
  	    arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
  	}
!       
        /* Restore recog_data (getting the attributes of other insns can
  	 destroy this array, but final.c assumes that it remains intact
  	 across this call; since the insn has been recognized already we
--- 7742,7748 ----
  	  if (reverse || then_not_else)
  	    arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
  	}
! 
        /* Restore recog_data (getting the attributes of other insns can
  	 destroy this array, but final.c assumes that it remains intact
  	 across this call; since the insn has been recognized already we
Index: gcc/config/arm/arm.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/arm/arm.h,v
retrieving revision 1.49.2.10
diff -c -3 -p -r1.49.2.10 arm.h
*** arm.h	2000/02/09 19:57:43	1.49.2.10
--- arm.h	2000/02/19 02:20:46
*************** Unrecognized value in TARGET_CPU_DEFAULT
*** 441,447 ****
       "Do not load the PIC register in function prologues" },	\
    {"no-single-pic-base",       -ARM_FLAG_SINGLE_PIC_BASE, "" },	\
    {"long-calls",		ARM_FLAG_LONG_CALLS,		\
!      "Generate all call instructions as indirect calls"},	\
    {"no-long-calls",	       -ARM_FLAG_LONG_CALLS, ""},	\
    {"thumb",                     ARM_FLAG_THUMB,			\
       "Compile for the Thumb not the ARM" },			\
--- 441,447 ----
       "Do not load the PIC register in function prologues" },	\
    {"no-single-pic-base",       -ARM_FLAG_SINGLE_PIC_BASE, "" },	\
    {"long-calls",		ARM_FLAG_LONG_CALLS,		\
!    "Generate call insns as indirect calls, if necessary" },	\
    {"no-long-calls",	       -ARM_FLAG_LONG_CALLS, ""},	\
    {"thumb",                     ARM_FLAG_THUMB,			\
       "Compile for the Thumb not the ARM" },			\
*************** enum reg_class
*** 1354,1359 ****
--- 1354,1364 ----
     than a word, or if they contain elements offset from zero in the struct. */
  #define DEFAULT_PCC_STRUCT_RETURN 0
  
+ /* Flags for the call/call_value rtl operations set up by function_arg */
+ #define CALL_NORMAL		0x00000000	/* no special processing */
+ #define CALL_LONG		0x00000001	/* always call indirect */
+ #define CALL_SHORT		0x00000002	/* never call indirect */
+ 
  /* A C type for declaring a variable that is used as the first argument of
     `FUNCTION_ARG' and other related values.  For some target machines, the
     type `int' suffices and can hold the number of bytes of argument so far.  */
*************** typedef struct
*** 1361,1367 ****
  {
    /* This is the number of registers of arguments scanned so far.  */
    int nregs;
!   /* Nonzero if this should be a long call.  */
    int long_call;
  } CUMULATIVE_ARGS;
  
--- 1366,1372 ----
  {
    /* This is the number of registers of arguments scanned so far.  */
    int nregs;
!   /* One of CALL_NORMAL, CALL_LONG, CALL_SHORT  */
    int long_call;
  } CUMULATIVE_ARGS;
  
*************** typedef struct
*** 1807,1813 ****
--- 1812,1830 ----
                   ? TREE_CST_RTL (decl) : DECL_RTL (decl));		\
        SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;				\
      }									\
+   if (TREE_CODE (decl) == FUNCTION_DECL	&& ! TREE_PUBLIC (decl))	\
+     arm_set_short_call_attribute (decl);				\
  }
+ #else
+ /* If we are referencing a function that is static or is known to be 
+    in this file attach short_call attribute to the type associated
+    with this declaration.  The same is for #ifndef AOF_ASSEMBLER
+    above. */
+ #define ENCODE_SECTION_INFO(decl)					\
+ {									\
+   if (TREE_CODE (decl) == FUNCTION_DECL	&& ! TREE_PUBLIC (decl))        \
+     arm_set_short_call_attribute (decl);				\
+ }
  #endif
  
  /* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
*************** extern int making_const_table;
*** 2372,2377 ****
--- 2389,2399 ----
  #define COMP_TYPE_ATTRIBUTES(TYPE1, TYPE2) \
    (arm_comp_type_attributes (TYPE1, TYPE2))
  
+ /* If defined, a C statement that assigns default attributes to newly
+    defined TYPE.  */
+ #define SET_DEFAULT_TYPE_ATTRIBUTES(TYPE) \
+   (arm_set_default_type_attributes (TYPE))
+ 
  /* Handle pragmas for compatibility with Intel's compilers.  */
  #define HANDLE_PRAGMA(GET, UNGET, NAME) arm_process_pragma (GET, UNGET, NAME)
  
*************** extern int making_const_table;
*** 2494,2499 ****
--- 2516,2524 ----
          arm_poke_function_name (STREAM, NAME);		\
      }							\
    while (0)
+ 
+ #define ARM_DECLARE_FUNCTION_SIZE(STREAM, NAME, DECL)	\
+   (arm_set_short_call_attribute (DECL))
  
  /* Target characters.  */
  #define TARGET_BELL	007
Index: gcc/config/arm/arm.md
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/arm/arm.md,v
retrieving revision 1.34.2.12
diff -c -3 -p -r1.34.2.12 arm.md
*** arm.md	2000/02/09 20:51:40	1.34.2.12
--- arm.md	2000/02/19 02:20:49
***************
*** 5821,5834 ****
    "TARGET_EITHER"
    "
    {
!     /* Operand 2 is either const0_rtx or const1_rtx; depending on whether or
!        not this is supposed to be a long call.  If it's not const0_rtx, force
!        the call address into a register.  */
!     /* In an untyped call, we can get NULL for operand 2.  */
!     if (operands[2] == 0)
!       operands[2] = const0_rtx;
!     if (operands[2] != const0_rtx
! 	&& GET_CODE (XEXP (operands[0], 0)) != REG)
        XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0));
    }"
  )
--- 5821,5838 ----
    "TARGET_EITHER"
    "
    {
!     /* This is to generate indirect calls by loading the 32 bit address
!        of the callee directly into pc.  SYMBOL_REF, which is a part of
!        operand[1] is forced into a register and then mem:SI of the
!        register is loaded into pc.  operand[2] is used to pass the
!        long_call/short_call attribute to arm_is_long_call_p().  This attribute
!        is set/reset whenever __attribute__ or pargma longcall () is
!        used, short_call is also set if function declared static or
!        if it was defined.  See arm.c and arm.h for info about it.  The third
!        parameter to arm_is_long_call_p is used to tell when the predicat is
!        called.  The function defined in arm.c, there's more info there. */
! 
!     if (arm_is_long_call_p (operands[0], INTVAL (operands[2]), 0))
        XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0));
    }"
  )
***************
*** 5902,5915 ****
    "TARGET_EITHER"
    "
    {
!     /* Operand 2 is either const0_rtx or const1_rtx; depending on whether or
!        not this is supposed to be a long call.  If it's not const0_rtx, force
!        the call address into a register.  */
!     /* In an untyped call, we can get NULL for operand 2.  */
!     if (operands[3] == 0)
!       operands[3] = const0_rtx;
!     if (operands[3] != const0_rtx && GET_CODE (XEXP (operands[1], 0)) != REG)
!       XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0));
    }"
  )
  
--- 5906,5914 ----
    "TARGET_EITHER"
    "
    {
!      /* See the comment in define_expand \"call\" */
!      if (arm_is_long_call_p (operands[1], INTVAL (operands[3]), 0))
!        XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0));
    }"
  )
  
***************
*** 5950,5956 ****
     (use (match_operand 2 "" ""))
     (clobber (reg:SI 14))]
    "TARGET_ARM
!    && operands[2] == const0_rtx
     && (GET_CODE (operands[0]) == SYMBOL_REF)"
    "*
    {
--- 5949,5955 ----
     (use (match_operand 2 "" ""))
     (clobber (reg:SI 14))]
    "TARGET_ARM
!    && ! arm_is_long_call_p (operands[0], INTVAL (operands[2]), 1)
     && (GET_CODE (operands[0]) == SYMBOL_REF)"
    "*
    {
***************
*** 5965,5971 ****
  	(match_operand:SI 2 "general_operand" "g")))
     (use (match_operand 3 "" ""))
     (clobber (reg:SI 14))]
!   "TARGET_ARM && operands[3] == const0_rtx && (GET_CODE(operands[1]) == SYMBOL_REF)"
    "*
    {
      return NEED_PLT_RELOC ? \"bl%?\\t%a1(PLT)\" : \"bl%?\\t%a1\";
--- 5964,5972 ----
  	(match_operand:SI 2 "general_operand" "g")))
     (use (match_operand 3 "" ""))
     (clobber (reg:SI 14))]
!   "TARGET_ARM
!    && ! arm_is_long_call_p (operands[1], INTVAL (operands[3]), 1)
!    && (GET_CODE(operands[1]) == SYMBOL_REF)"
    "*
    {
      return NEED_PLT_RELOC ? \"bl%?\\t%a1(PLT)\" : \"bl%?\\t%a1\";
Index: gcc/config/arm/elf.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/arm/elf.h,v
retrieving revision 1.13.2.4
diff -c -3 -p -r1.13.2.4 elf.h
*** elf.h	2000/02/18 18:24:29	1.13.2.4
--- elf.h	2000/02/19 02:20:50
*************** Boston, MA 02111-1307, USA.  */
*** 127,132 ****
--- 127,133 ----
  #define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL)		\
    do								\
      {								\
+       ARM_DECLARE_FUNCTION_SIZE (FILE, FNAME, DECL);		\
        if (!flag_inhibit_size_directive)				\
          {							\
            char label[256];					\
Index: gcc/cp/tree.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/tree.c,v
retrieving revision 1.157.2.1
diff -c -3 -p -r1.157.2.1 tree.c
*** tree.c	2000/01/13 16:10:36	1.157.2.1
--- tree.c	2000/02/19 02:20:58
*************** build_cplus_method_type (basetype, retty
*** 449,455 ****
--- 449,457 ----
  {
    register tree t;
    tree ptype;
+ #if 0
    int hashcode;
+ #endif
  
    /* Make a node of the sort we want.  */
    t = make_node (METHOD_TYPE);
*************** build_cplus_method_type (basetype, retty
*** 466,477 ****
    TYPE_ARG_TYPES (t) = argtypes;
    TREE_SIDE_EFFECTS (argtypes) = 1;  /* Mark first argtype as "artificial".  */
  
!   /* If we already have such a type, use the old one and free this one.
       Note that it also frees up the above cons cell if found.  */
    hashcode = TYPE_HASH (basetype) + TYPE_HASH (rettype) +
      type_hash_list (argtypes);
  
    t = type_hash_canon (hashcode, t);
  
    if (TYPE_SIZE (t) == 0)
      layout_type (t);
--- 468,485 ----
    TYPE_ARG_TYPES (t) = argtypes;
    TREE_SIDE_EFFECTS (argtypes) = 1;  /* Mark first argtype as "artificial".  */
  
! #if 0
!   /* to support long-call heuristic each function decl node must have
!      its own copy of funtype node, because otherwise changing
!      attributes of a funtype affects all decls having the same funtype 
!   */
! /* If we already have such a type, use the old one and free this one.
       Note that it also frees up the above cons cell if found.  */
    hashcode = TYPE_HASH (basetype) + TYPE_HASH (rettype) +
      type_hash_list (argtypes);
  
    t = type_hash_canon (hashcode, t);
+ #endif
  
    if (TYPE_SIZE (t) == 0)
      layout_type (t);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]