Patch/RFC: -mlongcall and #pragma longcall for PowerPC
Zack Weinberg
zack@codesourcery.com
Mon May 6 12:56:00 GMT 2002
This patch implements coarser-grained control over long call
generation for the PowerPC and POWER architectures. We already had
__attribute__((longcall)) which could be applied to individual
function declarations, but some people want a broader brush.
There are three new features. The -m(no-)longcall switch can be used
to instruct the compiler to generate long calls for an entire
translation unit. #pragma longcall(1) ... #pragma longcall(0) enable
and disable it for a particular series of declarations. Finally,
__attribute__ ((shortcall)) will override either of the above for a
single declaration.
I implemented this to match a feature that a customer of CodeSourcery
added to their private copy of GCC. The syntax and semantics are
somewhat dubious, but there is a body of code out there that expects
them all to work just so. The key gotchas as I see them are: Both the
pragma and the switch work by applying attributes to function
declarations. This means that
#pragma longcall(1)
void foo() {
a();
b();
c();
}
#pragma longcall(0)
has no effect on the calls from foo to a, b, or c. If foo was not
previously declared, however, future calls to foo *will* use long
calls.
Also, there is no '#pragma longcall(pop)' -- if the above was compiled
with -mlongcall in effect, later code in the file gets compiled with
it turned off.
I had to split up the *call_nonlocal_sysv and
*call_value_nonlocal_sysv patterns so that combine did not nullify the
effects of longcall markers (however they got there). Note that the
length attribute on these patterns is inaccurate in the presence of
CALL_* flags other than CALL_V4_(SET|CLEAR)_FP_ARGS. That would be
best fixed, IMO, by putting the crxor/creqv in its own insn, but I
don't want to complicate this patch with that.
I added 'default: break;' clauses to
altivec_expand_{un,bin,tern}op_builtin so that they wouldn't flood my
screen with warnings. They do the same thing as they used to, of
course; I also believe that that's the correct thing for them to do.
I have tested that this patch compiles and the switches work as
advertised (by code inspection). I'm doing a powerpc-eabisim test
run, but this of course does not exercise the feature.
There doesn't seem to be an established place in the manual to
document target-specific #pragmas.
zw
* config/rs6000/rs6000.c (rs6000_default_long_calls,
rs6000_longcall_switch, rs6000_set_default_type_attributes): New.
(TARGET_SET_DEFAULT_TYPE_ATTRIBUTES): Set it.
(rs6000_override_options): Handle -m(no-)longcall.
(init_cumulative_args, output_mi_thunk): Check for both
longcall and shortcall attributes on the function.
(rs6000_attribute_table): Add "shortcall".
(altivec_expand_unop_builtin, altivec_expand_binop_builtin,
altivec_expand_ternop_builtin): Add default clauses to switches
to silence warnings.
* config/rs6000/rs6000.h: Declare rs6000_longcall_switch and
rs6000_default_long_calls. Define REGISTER_TARGET_PRAGMAS.
(TARGET_OPTIONS): Add longcall and no-longcall.
* config/rs6000/rs6000.md (call_nonlocal_sysv,
call_value_nonlocal_sysv): Split by alternatives. One pair
accepts only SYMBOL_REFs and rejects if CALL_LONG is set in
the call cookie. The other pair accepts only LR/CTR and has
no restriction.
* config.gcc (rs6000-*-* | powerpc*-*-* trailer stanza):
Set c_target_objs, cxx_target_objs; add t-rs6000-c-rule to
tmake_file.
* config/rs6000/rs6000-c.c: New file.
* config/rs6000/t-rs6000-c-rule: New file.
* config/rs6000/rs6000-protos.c: Add multiple-include guard.
Prototype rs6000_pragma_longcall.
* doc/extend.texi: Document shortcall attribute.
* doc/invoke.texi: Document -mlongcall, -mno-longcall.
===================================================================
Index: config.gcc
--- config.gcc 5 May 2002 22:23:40 -0000 1.192
+++ config.gcc 6 May 2002 19:54:13 -0000
@@ -3650,6 +3650,9 @@ powerpc*-*-* | rs6000-*-*)
fi
;;
esac
+ c_target_objs="rs6000-c.o"
+ cxx_target_objs="rs6000-c.o"
+ tmake_file="${tmake_file} rs6000/t-rs6000-c-rule"
;;
sparc*-*-*)
case ".$with_cpu" in
===================================================================
Index: config/rs6000/rs6000-c.c
--- config/rs6000/rs6000-c.c 1 Jan 1970 00:00:00 -0000
+++ config/rs6000/rs6000-c.c 6 May 2002 19:54:14 -0000
@@ -0,0 +1,71 @@
+/* Subroutines for the C front end on the POWER and PowerPC architectures.
+ Copyright (C) 2002
+ Free Software Foundation, Inc.
+
+ Contributed by Zack Weinberg <zack@codesourcery.com>
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "cpplib.h"
+#include "tree.h"
+#include "c-lex.h"
+#include "errors.h"
+#include "tm_p.h"
+
+/* Handle the machine specific pragma longcall. Its syntax is
+
+ # pragma longcall ( TOGGLE )
+
+ where TOGGLE is either 0 or 1.
+
+ rs6000_default_long_calls is set to the value of TOGGLE, changing
+ whether or not new function declarations receive a longcall
+ attribute by default. */
+
+#define BAD(msgid) do { \
+ warning (msgid); \
+ warning ("ignoring malformed #pragma longcall"); \
+ return; \
+} while (0)
+
+void
+rs6000_pragma_longcall (pfile)
+ cpp_reader *pfile ATTRIBUTE_UNUSED;
+{
+ tree x, n;
+
+ /* If we get here, generic code has already scanned the directive
+ leader and the word "longcall". */
+
+ if (c_lex (&x) != CPP_OPEN_PAREN)
+ BAD ("missing open paren");
+ if (c_lex (&n) != CPP_NUMBER)
+ BAD ("missing number");
+ if (c_lex (&x) != CPP_CLOSE_PAREN)
+ BAD ("missing close paren");
+
+ if (n != integer_zero_node && n != integer_one_node)
+ BAD ("number must be 0 or 1");
+
+ if (c_lex (&x) != CPP_EOF)
+ warning ("junk at end of #pragma longcall");
+
+ rs6000_default_long_calls = (n == integer_one_node);
+}
===================================================================
Index: config/rs6000/rs6000-protos.h
--- config/rs6000/rs6000-protos.h 3 Mar 2002 04:23:16 -0000 1.31
+++ config/rs6000/rs6000-protos.h 6 May 2002 19:54:14 -0000
@@ -19,6 +19,9 @@ along with GNU CC; see the file COPYING.
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+#ifndef GCC_RS6000_PROTOS_H
+#define GCC_RS6000_PROTOS_H
+
/* Declare functions in rs6000.c */
#ifdef RTX_CODE
@@ -186,3 +189,9 @@ extern void rs6000_emit_epilogue PARAMS
extern void debug_stack_info PARAMS ((rs6000_stack_t *));
extern void machopic_output_stub PARAMS ((FILE *, const char *, const char *));
+
+#ifdef GCC_CPPLIB_H
+extern void rs6000_pragma_longcall PARAMS ((cpp_reader *));
+#endif
+
+#endif /* rs6000-protos.h */
===================================================================
Index: config/rs6000/rs6000.c
--- config/rs6000/rs6000.c 4 May 2002 00:33:48 -0000 1.314
+++ config/rs6000/rs6000.c 6 May 2002 19:54:16 -0000
@@ -124,6 +124,13 @@ char toc_label_name[10];
/* Alias set for saves and restores from the rs6000 stack. */
static int rs6000_sr_alias_set;
+/* Call distance, overridden by -mlongcall and #pragma longcall(1).
+ The only place that looks at this is rs6000_set_default_type_attributes;
+ everywhere else should rely on the presence or absence of a longcall
+ attribute on the function declaration. */
+int rs6000_default_long_calls;
+const char *rs6000_longcall_switch;
+
static void rs6000_add_gc_roots PARAMS ((void));
static int num_insns_constant_wide PARAMS ((HOST_WIDE_INT));
static rtx expand_block_move_mem PARAMS ((enum machine_mode, rtx, rtx));
@@ -146,6 +153,7 @@ static bool rs6000_assemble_integer PARA
static int rs6000_ra_ever_killed PARAMS ((void));
static tree rs6000_handle_longcall_attribute PARAMS ((tree *, tree, tree, int, bool *));
const struct attribute_spec rs6000_attribute_table[];
+static void rs6000_set_default_type_attributes PARAMS ((tree));
static void rs6000_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
static void rs6000_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
static rtx rs6000_emit_set_long_const PARAMS ((rtx,
@@ -235,6 +243,8 @@ static const char alt_reg_names[][8] =
/* Initialize the GCC target structure. */
#undef TARGET_ATTRIBUTE_TABLE
#define TARGET_ATTRIBUTE_TABLE rs6000_attribute_table
+#undef TARGET_SET_DEFAULT_TYPE_ATTRIBUTES
+#define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES rs6000_set_default_type_attributes
#undef TARGET_ASM_ALIGNED_DI_OP
#define TARGET_ASM_ALIGNED_DI_OP DOUBLE_INT_ASM_OP
@@ -546,6 +556,22 @@ rs6000_override_options (default_cpu)
/* Handle -mvrsave= option. */
rs6000_parse_vrsave_option ();
+ /* Handle -m(no-)longcall option. This is a bit of a cheap hack,
+ using TARGET_OPTIONS to handle a toggle switch, but we're out of
+ bits in target_flags so TARGET_SWITCHES cannot be used.
+ Assumption here is that rs6000_longcall_switch points into the
+ text of the complete option, rather than being a copy, so we can
+ scan back for the presence or absence of the no- modifier. */
+ if (rs6000_longcall_switch)
+ {
+ const char *base = rs6000_longcall_switch;
+ while (base[-1] != 'm') base--;
+
+ if (*rs6000_longcall_switch != '\0')
+ error ("invalid option `%s'", base);
+ rs6000_default_long_calls = (base[0] != 'n');
+ }
+
#ifdef TARGET_REGNAMES
/* If the user desires alternate register names, copy in the
alternate names now. */
@@ -2541,8 +2567,10 @@ init_cumulative_args (cum, fntype, libna
cum->orig_nargs = cum->nargs_prototype;
- /* Check for longcall's */
- if (fntype && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)))
+ /* Check for a longcall attribute. */
+ if (fntype
+ && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
+ && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))
cum->call_cookie = CALL_LONG;
if (TARGET_DEBUG_ARG)
@@ -3565,6 +3593,8 @@ altivec_expand_unop_builtin (icode, argl
return NULL_RTX;
}
break;
+ default:
+ break;
}
if (target == 0
@@ -3654,6 +3684,8 @@ altivec_expand_binop_builtin (icode, arg
return NULL_RTX;
}
break;
+ default:
+ break;
}
if (target == 0
@@ -3828,6 +3860,8 @@ altivec_expand_ternop_builtin (icode, ar
return NULL_RTX;
}
break;
+ default:
+ break;
}
if (target == 0
@@ -9871,8 +9905,11 @@ output_mi_thunk (file, thunk_fndecl, del
fname = XSTR (XEXP (DECL_RTL (function), 0), 0);
if (current_file_function_operand (XEXP (DECL_RTL (function), 0), VOIDmode)
- && ! lookup_attribute ("longcall",
- TYPE_ATTRIBUTES (TREE_TYPE (function))))
+ && (! lookup_attribute ("longcall",
+ TYPE_ATTRIBUTES (TREE_TYPE (function)))
+ || lookup_attribute ("shortcall",
+ TYPE_ATTRIBUTES (TREE_TYPE (function)))))
+
{
fprintf (file, "\tb %s", prefix);
assemble_name (file, fname);
@@ -10852,12 +10889,13 @@ rs6000_initialize_trampoline (addr, fnad
const struct attribute_spec rs6000_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
- { "longcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute },
- { NULL, 0, 0, false, false, false, NULL }
+ { "longcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute },
+ { "shortcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
};
-/* Handle a "longcall" attribute; arguments as in struct
- attribute_spec.handler. */
+/* Handle a "longcall" or "shortcall" attribute; arguments as in
+ struct attribute_spec.handler. */
static tree
rs6000_handle_longcall_attribute (node, name, args, flags, no_add_attrs)
@@ -10877,6 +10915,20 @@ rs6000_handle_longcall_attribute (node,
}
return NULL_TREE;
+}
+
+/* Set longcall attributes on all functions declared when
+ rs6000_default_long_calls is true. */
+static void
+rs6000_set_default_type_attributes (type)
+ tree type;
+{
+ if (rs6000_default_long_calls
+ && (TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == METHOD_TYPE))
+ TYPE_ATTRIBUTES (type) = tree_cons (get_identifier ("longcall"),
+ NULL_TREE,
+ TYPE_ATTRIBUTES (type));
}
/* Return a reference suitable for calling a function with the
===================================================================
Index: config/rs6000/rs6000.h
--- config/rs6000/rs6000.h 1 May 2002 01:50:24 -0000 1.200
+++ config/rs6000/rs6000.h 6 May 2002 19:54:17 -0000
@@ -432,6 +432,9 @@ extern enum processor_type rs6000_cpu;
N_("Specify size of long double (64 or 128 bits)") }, \
{"vrsave=", &rs6000_altivec_vrsave_string, \
N_("Specify yes/no if VRSAVE instructions should be generated for AltiVec") }, \
+ {"longcall", &rs6000_longcall_switch, \
+ N_("Avoid all range limits on call instructions") }, \
+ {"no-longcall", &rs6000_longcall_switch, "" }, \
SUBTARGET_OPTIONS \
}
@@ -462,6 +465,8 @@ extern int rs6000_long_double_type_size;
extern int rs6000_altivec_abi;
extern const char *rs6000_altivec_vrsave_string;
extern int rs6000_altivec_vrsave;
+extern const char *rs6000_longcall_switch;
+extern int rs6000_default_long_calls;
#define TARGET_LONG_DOUBLE_128 (rs6000_long_double_type_size == 128)
#define TARGET_ALTIVEC_ABI rs6000_altivec_abi
@@ -482,6 +487,11 @@ extern int rs6000_altivec_vrsave;
/* Define this to change the optimizations performed by default. */
#define OPTIMIZATION_OPTIONS(LEVEL,SIZE) optimization_options(LEVEL,SIZE)
+
+/* Target pragma. */
+#define REGISTER_TARGET_PRAGMAS(PFILE) do { \
+ cpp_register_pragma (PFILE, 0, "longcall", rs6000_pragma_longcall); \
+} while (0)
/* Show we can debug even without a frame pointer. */
#define CAN_DEBUG_WITHOUT_FP
===================================================================
Index: config/rs6000/rs6000.md
--- config/rs6000/rs6000.md 4 May 2002 14:32:31 -0000 1.184
+++ config/rs6000/rs6000.md 6 May 2002 19:54:19 -0000
@@ -10037,67 +10037,88 @@
;; which indicates how to set cr1
(define_insn "*call_nonlocal_sysv"
- [(call (mem:SI (match_operand:SI 0 "call_operand" "cl,cl,s,s"))
- (match_operand 1 "" "g,g,g,g"))
- (use (match_operand:SI 2 "immediate_operand" "O,n,O,n"))
- (clobber (match_scratch:SI 3 "=l,l,l,l"))]
+ [(call (mem:SI (match_operand:SI 0 "call_operand" "s,s"))
+ (match_operand 1 "" "g,g"))
+ (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_DARWIN)
+ && (INTVAL (operands[2]) && CALL_LONG) == 0"
+{
+ if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn ("crxor 6,6,6", operands);
+
+ else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn ("creqv 6,6,6", operands);
+
+ return (DEFAULT_ABI == ABI_V4 && flag_pic) ? "bl %z0@plt" : "bl %z0";
+}
+ [(set_attr "type" "branch,branch")
+ (set_attr "length" "4,8")])
+
+(define_insn "*call_indirect_nonlocal_sysv"
+ [(call (mem:SI (match_operand:SI 0 "call_operand" "cl,cl"))
+ (match_operand 1 "" "g,g"))
+ (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_DARWIN"
- "*
{
if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
- output_asm_insn (\"crxor 6,6,6\", operands);
+ output_asm_insn ("crxor 6,6,6", operands);
else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
- output_asm_insn (\"creqv 6,6,6\", operands);
+ output_asm_insn ("creqv 6,6,6", operands);
- switch (which_alternative)
- {
- default:
- abort ();
- case 0:
- case 1:
- return \"b%T0l\";
- case 2:
- case 3:
- return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"bl %z0@plt\" : \"bl %z0\";
- }
-}"
- [(set_attr "type" "jmpreg,jmpreg,branch,branch")
- (set_attr "length" "4,8,4,8")])
+ return "b%T0l";
+}
+ [(set_attr "type" "jmpreg,jmpreg")
+ (set_attr "length" "4,8")])
(define_insn "*call_value_nonlocal_sysv"
[(set (match_operand 0 "" "")
- (call (mem:SI (match_operand:SI 1 "call_operand" "cl,cl,s,s"))
- (match_operand 2 "" "g,g,g,g")))
- (use (match_operand:SI 3 "immediate_operand" "O,n,O,n"))
- (clobber (match_scratch:SI 4 "=l,l,l,l"))]
+ (call (mem:SI (match_operand:SI 1 "call_operand" "s,s"))
+ (match_operand 2 "" "g,g")))
+ (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_DARWIN)
+ && (INTVAL (operands[3]) && CALL_LONG) == 0"
+{
+ if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn ("crxor 6,6,6", operands);
+
+ else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn ("creqv 6,6,6", operands);
+
+ return (DEFAULT_ABI == ABI_V4 && flag_pic) ? "bl %z1@plt" : "bl %z1";
+}
+ [(set_attr "type" "branch,branch")
+ (set_attr "length" "4,8")])
+
+(define_insn "*call_value_indirect_nonlocal_sysv"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand:SI 1 "call_operand" "cl,cl"))
+ (match_operand 2 "" "g,g")))
+ (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_DARWIN"
- "*
{
if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
- output_asm_insn (\"crxor 6,6,6\", operands);
+ output_asm_insn ("crxor 6,6,6", operands);
else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
- output_asm_insn (\"creqv 6,6,6\", operands);
+ output_asm_insn ("creqv 6,6,6", operands);
- switch (which_alternative)
- {
- default:
- abort ();
- case 0:
- case 1:
- return \"b%T1l\";
- case 2:
- case 3:
- return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"bl %z1@plt\" : \"bl %z1\";
- }
-}"
- [(set_attr "type" "jmpreg,jmpreg,branch,branch")
- (set_attr "length" "4,8,4,8")])
+ return "b%T1l";
+}
+ [(set_attr "type" "jmpreg,jmpreg")
+ (set_attr "length" "4,8")])
;; Call subroutine returning any type.
(define_expand "untyped_call"
===================================================================
Index: config/rs6000/t-rs6000-c-rule
--- config/rs6000/t-rs6000-c-rule 1 Jan 1970 00:00:00 -0000
+++ config/rs6000/t-rs6000-c-rule 6 May 2002 19:54:19 -0000
@@ -0,0 +1,4 @@
+rs6000-c.o: $(srcdir)/config/rs6000/rs6000-c.c \
+ $(srcdir)/config/rs6000/rs6000-protos.h \
+ $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(CPPLIB_H) $(TM_P_H) c-lex.h errors.h
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
===================================================================
Index: doc/extend.texi
--- doc/extend.texi 11 Apr 2002 21:33:31 -0000 1.69
+++ doc/extend.texi 6 May 2002 19:54:21 -0000
@@ -2273,12 +2273,15 @@ useful to override the effects of the @o
The PowerPC compiler for Windows NT currently ignores the @code{cdecl}
attribute.
-@item longcall
+@item longcall/shortcall
@cindex functions called via pointer on the RS/6000 and PowerPC
On the RS/6000 and PowerPC, the @code{longcall} attribute causes the
compiler to always call the function via a pointer, so that functions
which reside further than 64 megabytes (67,108,864 bytes) from the
-current location can be called.
+current location can be called. The @code{shortcall} attribute causes
+the compiler not to do this. Both attributes override the
+@option{-mlongcall} switch (@pxref{RS/6000 and PowerPC Options}) and the
+@code{#pragma longcall} setting.
@item long_call/short_call
@cindex indirect calls on ARM
===================================================================
Index: doc/invoke.texi
--- doc/invoke.texi 30 Apr 2002 16:47:41 -0000 1.141
+++ doc/invoke.texi 6 May 2002 19:54:24 -0000
@@ -6813,6 +6813,16 @@ All modules should be compiled with the
On System V.4 and embedded PowerPC systems do (do not) emit register
names in the assembly language output using symbolic forms.
+@item -mlongcall
+@itemx -mno-longcall
+@opindex mlongcall
+@opindex mno-longcall
+Default to making all function calls via pointers, so that there is no
+danger of a called function being out of the range of the @code{bl}
+instruction. This setting can be overridden by the @code{shortcall}
+attribute or by @code{#pragma longcall(0)}.
+
+
@item -pthread
@opindex pthread
Adds support for multithreading with the @dfn{pthreads} library.
More information about the Gcc-patches
mailing list