I made this patch by chopping up my overall patch set, so it's possible some of the line numbers may be a bit flakey. If there are any failures applying the patch, use the --fuzz option of the patch command. Note that this patch is only valid for the Vxworks target, specifically the SysV/EABI calling convention. It may well break other targets such as AIX or NT, may not be valid with pic code, and may fail to emit long calls to virtual functions that it may falsely believe to exist in the current module. As long as they are within 32 Mb it will still work; alternatively the longcall attribute could be added to these functions. diff -c3prN /gcc.orig/gcc/gcc/config/rs6000/rs6000.c /gcc.dev/gcc/gcc/config/rs6000/rs6000.c *** /gcc.orig/gcc/gcc/config/rs6000/rs6000.c Mon Jan 15 05:28:54 2001 --- /gcc.dev/gcc/gcc/config/rs6000/rs6000.c Sat Jan 27 21:11:50 2001 *************** current_file_function_operand (op, mode) *** 1201,1212 **** register rtx op; enum machine_mode mode ATTRIBUTE_UNUSED; { ! return (GET_CODE (op) == SYMBOL_REF ! && (SYMBOL_REF_FLAG (op) ! || (op == XEXP (DECL_RTL (current_function_decl), 0) ! && !DECL_WEAK (current_function_decl)))); ! } /* Return 1 if this operand is a valid input for a move insn. */ --- 1201,1218 ---- register rtx op; enum machine_mode mode ATTRIBUTE_UNUSED; { ! if (GET_CODE(op) != SYMBOL_REF) ! return 0; ! ! if (op == XEXP (DECL_RTL (current_function_decl), 0) ! && !DECL_WEAK (current_function_decl)) ! { ! SYMBOL_REF_FLAG(op) = 1; ! return 1; ! } + return SYMBOL_REF_FLAG (op) != 0; + } /* Return 1 if this operand is a valid input for a move insn. */ *************** init_cumulative_args (cum, fntype, libna *** 1380,1385 **** --- 1386,1394 ---- if (cum->call_cookie & CALL_LONG) fprintf (stderr, " longcall,"); + if (cum->call_cookie & CALL_SHORT) + fprintf (stderr, " shortcall,"); + fprintf (stderr, " proto = %d, nargs = %d\n", cum->prototype, cum->nargs_prototype); } *************** rs6000_valid_type_attribute_p (type, att *** 5675,5680 **** --- 5684,5693 ---- if (is_attribute_p ("longcall", identifier)) return (args == NULL_TREE); + /* Shortcall overrides implicit longcalls */ + if (is_attribute_p ("shortcall", identifier)) + return (args == NULL_TREE); + if (DEFAULT_ABI == ABI_NT) { /* Stdcall attribute says callee is responsible for popping arguments *************** rs6000_dll_import_ref (call_ref) *** 5774,5779 **** --- 5787,5814 ---- return reg2; } + /* A C expression whose value is nonzero if a 32 bit "longcall" should be + generated for this call. We generate a longcall if the function + is not declared __attribute__ ((shortcall), AND: + (i) the function is declared __attribute__ ((longcall)), or + (ii) -mlongcall is enabled and we don't know for sure that the target + function is declared 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. + */ + + int + rs6000_is_longcall_p (call_ref, call_cookie) + rtx call_ref; + int call_cookie; + { + return !(call_cookie & CALL_SHORT) && + ((call_cookie & CALL_LONG) || + (TARGET_LONGCALL && + !current_file_function_operand (call_ref, VOIDmode))); + } + /* Return a reference suitable for calling a function with the longcall attribute. */ struct rtx_def * rs6000_longcall_ref (call_ref) *************** rs6000_encode_section_info (decl) *** 5889,5897 **** if (TREE_CODE (decl) == FUNCTION_DECL) { rtx sym_ref = XEXP (DECL_RTL (decl), 0); ! if ((TREE_ASM_WRITTEN (decl) || ! TREE_PUBLIC (decl)) ! && !DECL_WEAK (decl)) ! SYMBOL_REF_FLAG (sym_ref) = 1; if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT) { --- 5924,5933 ---- if (TREE_CODE (decl) == FUNCTION_DECL) { rtx sym_ref = XEXP (DECL_RTL (decl), 0); ! ! if (!TREE_PUBLIC (decl) && !DECL_WEAK (decl)) ! SYMBOL_REF_FLAG (sym_ref) = 1; if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT) { diff -c3prN /gcc.orig/gcc/gcc/config/rs6000/rs6000.h /gcc.dev/gcc/gcc/config/rs6000/rs6000.h *** /gcc.orig/gcc/gcc/config/rs6000/rs6000.h Fri Dec 22 20:39:59 2000 --- /gcc.dev/gcc/gcc/config/rs6000/rs6000.h Sat Jan 13 03:39:12 2001 *************** extern int target_flags; *** 279,284 **** --- 279,294 ---- /* Disable fused multiply/add operations */ #define MASK_NO_FUSED_MADD 0x00020000 + /* Use a conservative heuristic to determine whether to + make a direct (26 bit) call or an indirect (32 bit) call: + We make a longcall unless the target function is declared + static, or its definition has already been seen, or + it is declared with the attribute "shortcall" . + An underlying assumption is that individual translation + units span less than 32MB so that it is always safe + to make direct calls to functions in the same module. */ + #define MASK_LONGCALL 0x00080000 + #define TARGET_POWER (target_flags & MASK_POWER) #define TARGET_POWER2 (target_flags & MASK_POWER2) #define TARGET_POWERPC (target_flags & MASK_POWERPC) *************** extern int target_flags; *** 302,307 **** --- 312,318 ---- #define TARGET_HARD_FLOAT (! TARGET_SOFT_FLOAT) #define TARGET_UPDATE (! TARGET_NO_UPDATE) #define TARGET_FUSED_MADD (! TARGET_NO_FUSED_MADD) + #define TARGET_LONGCALL (target_flags & MASK_LONGCALL) /* Pseudo target to indicate whether the object format is ELF (to get around not having conditional compilation in the md file) */ *************** extern int target_flags; *** 390,395 **** --- 401,408 ---- {"no-update", MASK_NO_UPDATE}, \ {"fused-madd", - MASK_NO_FUSED_MADD}, \ {"no-fused-madd", MASK_NO_FUSED_MADD}, \ + {"longcall", MASK_LONGCALL}, \ + {"no-longcall", - MASK_LONGCALL}, \ SUBTARGET_SWITCHES \ {"", TARGET_DEFAULT}} *************** extern int rs6000_sysv_varargs_p; *** 1407,1412 **** --- 1420,1426 ---- #define CALL_V4_CLEAR_FP_ARGS 0x00000002 /* V.4, no FP args passed */ #define CALL_V4_SET_FP_ARGS 0x00000004 /* V.4, FP args were passed */ #define CALL_LONG 0x00000008 /* always call indirect */ + #define CALL_SHORT 0x00000010 /* always call direct */ /* Define cutoff for using external functions to save floating point */ #define FP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) == 62 || (FIRST_REG) == 63) *************** extern int rs6000_trunc_used; *** 2538,2544 **** #define ENCODE_SECTION_INFO(DECL) \ if (TREE_CODE (DECL) == FUNCTION_DECL \ ! && (TREE_ASM_WRITTEN (DECL) || ! TREE_PUBLIC (DECL)) \ && !DECL_WEAK (DECL)) \ SYMBOL_REF_FLAG (XEXP (DECL_RTL (DECL), 0)) = 1; --- 2552,2558 ---- #define ENCODE_SECTION_INFO(DECL) \ if (TREE_CODE (DECL) == FUNCTION_DECL \ ! && !TREE_PUBLIC (DECL) \ && !DECL_WEAK (DECL)) \ SYMBOL_REF_FLAG (XEXP (DECL_RTL (DECL), 0)) = 1; *************** extern int toc_initialized; *** 2620,2631 **** The csect for the function will have already been created by the `text_section' call previously done. We do have to go back to that ! csect, however. */ /* ??? What do the 16 and 044 in the .function line really mean? */ #define ASM_DECLARE_FUNCTION_NAME(FILE,NAME,DECL) \ ! { if (TREE_PUBLIC (DECL)) \ { \ fputs ("\t.globl .", FILE); \ RS6000_OUTPUT_BASENAME (FILE, NAME); \ --- 2634,2653 ---- The csect for the function will have already been created by the `text_section' call previously done. We do have to go back to that ! csect, however. ! ! We also record the fact that the function exists in the current ! compilation unit and so can be reached by a short branch by ! setting SYMBOL_REF_FLAG. */ /* ??? What do the 16 and 044 in the .function line really mean? */ #define ASM_DECLARE_FUNCTION_NAME(FILE,NAME,DECL) \ ! { \ ! rtx sym_ref = XEXP (DECL_RTL (DECL), 0); \ ! if (!DECL_WEAK (DECL)) \ ! SYMBOL_REF_FLAG (sym_ref) = 1; \ ! if (TREE_PUBLIC (DECL)) \ { \ fputs ("\t.globl .", FILE); \ RS6000_OUTPUT_BASENAME (FILE, NAME); \ *************** extern int rs6000_valid_decl_attribute_p *** 3326,3331 **** --- 3348,3354 ---- extern int rs6000_valid_type_attribute_p (); extern void rs6000_set_default_type_attributes (); extern struct rtx_def *rs6000_dll_import_ref (); + extern int rs6000_is_longcall_p (); extern struct rtx_def *rs6000_longcall_ref (); extern int function_arg_padding (); extern void toc_section (); diff -c3prN /gcc.orig/gcc/gcc/config/rs6000/rs6000.md /gcc.dev/gcc/gcc/config/rs6000/rs6000.md *** /gcc.orig/gcc/gcc/config/rs6000/rs6000.md Wed Jan 3 15:52:43 2001 --- /gcc.dev/gcc/gcc/config/rs6000/rs6000.md Sat Jan 27 21:11:44 2001 *************** *** 1,5 **** ;; Machine description for IBM RISC System 6000 (POWER) for GNU C compiler ! ;; Copyright (C) 1990, 91-98, 1999 Free Software Foundation, Inc. ;; Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu) ;; This file is part of GNU CC. --- 1,6 ---- ;; Machine description for IBM RISC System 6000 (POWER) for GNU C compiler ! ;; Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, ! ;; 2000, 2001 Free Software Foundation, Inc. ;; Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu) ;; This file is part of GNU CC. *************** *** 8047,8052 **** --- 8048,8055 ---- "" " { + int is_longcall; + if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != CONST_INT) abort (); *************** *** 8060,8069 **** operands[2] = GEN_INT ((int)CALL_NORMAL); } ! if (GET_CODE (operands[0]) != SYMBOL_REF ! || (INTVAL (operands[2]) & CALL_LONG) != 0) { ! if (INTVAL (operands[2]) & CALL_LONG) operands[0] = rs6000_longcall_ref (operands[0]); if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_SOLARIS) --- 8063,8073 ---- operands[2] = GEN_INT ((int)CALL_NORMAL); } ! is_longcall = rs6000_is_longcall_p(operands[0], INTVAL(operands[2])); ! ! if (GET_CODE (operands[0]) != SYMBOL_REF || is_longcall) { ! if (is_longcall) operands[0] = rs6000_longcall_ref (operands[0]); if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_SOLARIS) *************** *** 8109,8114 **** --- 8113,8120 ---- "" " { + int is_longcall; + if (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != CONST_INT) abort (); *************** *** 8122,8136 **** operands[3] = GEN_INT ((int)CALL_NORMAL); } ! if (GET_CODE (operands[1]) != SYMBOL_REF ! || (INTVAL (operands[3]) & CALL_LONG) != 0) { ! if (INTVAL (operands[3]) & CALL_LONG) operands[1] = rs6000_longcall_ref (operands[1]); if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_SOLARIS) emit_call_insn (gen_call_value_indirect_sysv (operands[0], operands[1], ! operands[2], operands[3])); else { rtx toc_reg = gen_rtx_REG (Pmode, 2); --- 8128,8143 ---- operands[3] = GEN_INT ((int)CALL_NORMAL); } ! is_longcall = rs6000_is_longcall_p(operands[1], INTVAL(operands[3])); ! ! if (GET_CODE (operands[1]) != SYMBOL_REF || is_longcall) { ! if (is_longcall) operands[1] = rs6000_longcall_ref (operands[1]); if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_SOLARIS) emit_call_insn (gen_call_value_indirect_sysv (operands[0], operands[1], ! operands[2], operands[3])); else { rtx toc_reg = gen_rtx_REG (Pmode, 2); *************** *** 8176,8182 **** (match_operand 1 "" "g,g")) (use (match_operand:SI 2 "immediate_operand" "O,n")) (clobber (match_scratch:SI 3 "=l,l"))] ! "(INTVAL (operands[2]) & CALL_LONG) == 0" "* { if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS) --- 8183,8189 ---- (match_operand 1 "" "g,g")) (use (match_operand:SI 2 "immediate_operand" "O,n")) (clobber (match_scratch:SI 3 "=l,l"))] ! "!rs6000_is_longcall_p(operands[0], INTVAL (operands[2]))" "* { if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS) *************** *** 8195,8201 **** (match_operand 1 "" "g,g")) (use (match_operand:SI 2 "immediate_operand" "O,n")) (clobber (match_scratch:SI 3 "=l,l"))] ! "TARGET_64BIT && (INTVAL (operands[2]) & CALL_LONG) == 0" "* { if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS) --- 8202,8208 ---- (match_operand 1 "" "g,g")) (use (match_operand:SI 2 "immediate_operand" "O,n")) (clobber (match_scratch:SI 3 "=l,l"))] ! "TARGET_64BIT && !rs6000_is_longcall_p(operands[0], INTVAL (operands[2]))" "* { if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS) *************** *** 8215,8221 **** (match_operand 2 "" "g,g"))) (use (match_operand:SI 3 "immediate_operand" "O,n")) (clobber (match_scratch:SI 4 "=l,l"))] ! "(INTVAL (operands[3]) & CALL_LONG) == 0" "* { if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS) --- 8222,8228 ---- (match_operand 2 "" "g,g"))) (use (match_operand:SI 3 "immediate_operand" "O,n")) (clobber (match_scratch:SI 4 "=l,l"))] ! "!rs6000_is_longcall_p(operands[1], INTVAL (operands[3]))" "* { if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS) *************** *** 8236,8242 **** (match_operand 2 "" "g,g"))) (use (match_operand:SI 3 "immediate_operand" "O,n")) (clobber (match_scratch:SI 4 "=l,l"))] ! "TARGET_64BIT && (INTVAL (operands[3]) & CALL_LONG) == 0" "* { if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS) --- 8243,8249 ---- (match_operand 2 "" "g,g"))) (use (match_operand:SI 3 "immediate_operand" "O,n")) (clobber (match_scratch:SI 4 "=l,l"))] ! "TARGET_64BIT && !rs6000_is_longcall_p(operands[1], INTVAL (operands[3]))" "* { if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS) *************** *** 8311,8317 **** (use (match_operand:SI 2 "immediate_operand" "O,n")) (clobber (match_scratch:SI 3 "=l,l"))] "(DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) ! && (INTVAL (operands[2]) & CALL_LONG) == 0" "* { /* Indirect calls should go through call_indirect */ --- 8318,8324 ---- (use (match_operand:SI 2 "immediate_operand" "O,n")) (clobber (match_scratch:SI 3 "=l,l"))] "(DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) ! && !rs6000_is_longcall_p(operands[0], INTVAL (operands[2]))" "* { /* Indirect calls should go through call_indirect */ *************** *** 8386,8392 **** (use (match_operand:SI 3 "immediate_operand" "O,n")) (clobber (match_scratch:SI 4 "=l,l"))] "(DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) ! && (INTVAL (operands[3]) & CALL_LONG) == 0" "* { /* This should be handled by call_value_indirect */ --- 8393,8399 ---- (use (match_operand:SI 3 "immediate_operand" "O,n")) (clobber (match_scratch:SI 4 "=l,l"))] "(DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) ! && !rs6000_is_longcall_p(operands[1], INTVAL (operands[3]))" "* { /* This should be handled by call_value_indirect */