This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
reworked long_call heuristic patch.
- To: nickc at cygnus dot com
- Subject: reworked long_call heuristic patch.
- From: Dmitri Makarov <dim at windriver dot com>
- Date: Fri, 18 Feb 2000 19:01:44 -0800 (PST)
- Cc: gcc-patches at gcc dot gnu dot org
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);