This patch is for an AIX problem, but the only robust solution is in common code: calls.c:precompute_register_parameters().
AIX, like other platforms, needs to call a function to obtain the pointer to thread-local storage. If the thread local variable is referenced as a parameter to a function call, the TLS resolution call may clobber parameters to the primary function call. GCC calls.c has special provisions for this situation in precompute_register_parameters, which tests each parameters with the legitimate_constant_p target hook. Most targets define that hook to return False for a TLS symbol. >From the very initial implementation of the rs6000 port, Richard Kenner utilized the GCC constant pool for the TOC managed by the compiler -- the table of position independent pointers to global symbols (like GOT). TLS symbols must be referenced by the TOC like all global symbols and must be considered constants valid for the constant pool. Currently targetm.legitimate_constant_p() returns True for TLS symbols on AIX, which inhibits the pre-legitimization of the TLS symbol in calls.c and registers can be overridden. If the AIX port defines TLS symbols as non-constant, emit_move_insn() prematurely calls force_const_mem() and prevents the correct TLS and TOC code generation. I have experimented extensively with attempts to have it both ways and teach cannot_force_const_mem hook to reject TLS symbols during the appropriate phases. This has proven too fragile a solution that causes additional testsuite failures. targetm.legitimate_constant_p has too many meanings and too many uses. I'm forced to fall back to a targeted patch in calls.c:precompute_register_parameters() that tests exactly for TLS symbols on AIX instead of using the legitimate_constant_p hook to test for TLS symbols. I could create a new target hook for this specific use in calls.c and define it as an alias to legitimate_constant_p for all other targets, but that solution seems overkill for a very narrow and target-specific issue. No other target will override this hook. Because GCC prefers compile-time tests instead of build-time #ifdef's, I use an inline test for an AIX macro and provide a definition of the macro for all other targets. Bootstrapped on powerpc-ibm-aix7.2.0.0. Okay for trunk? Thanks, David * calls.c (precompute_register_parameters): Precompute AIX TLS parameters also. diff --git a/gcc/calls.c b/gcc/calls.c index 4c3a8f3c215..b53a8916462 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -994,9 +994,15 @@ precompute_register_parameters (int num_actuals, struct arg _data *args, args[i].value, args[i].unsignedp); /* If the value is a non-legitimate constant, force it into a - pseudo now. TLS symbols sometimes need a call to resolve. */ + pseudo now. TLS symbols sometimes need a call to resolve. + AIX uses constant pool for the TOC so it must test explicitly. */ +#ifndef TARGET_AIX_OS +#define TARGET_AIX_OS 0 +#endif if (CONSTANT_P (args[i].value) - && !targetm.legitimate_constant_p (args[i].mode, args[i].value)) + && (!targetm.legitimate_constant_p (args[i].mode, args[i].value) + || (TARGET_AIX_OS && SYMBOL_REF_P (args[i].value) + && SYMBOL_REF_TLS_MODEL (args[i].value)))) args[i].value = force_reg (args[i].mode, args[i].value); /* If we're going to have to load the value by parts, pull the