This fixes a large number of Go testsuite failures on powerpc64 ELFv1, caused by loading r11 from a function descriptor and thus trashing the value set up from CALL_EXPR_STATIC_CHAIN. So don't load r11 if it already contains a useful value. Whether r11 has been set is found directly by examining rtl. Conveniently, looking at the previous sequence on the rtl sequence stack lets us skip over anything already emitted for GEN_CALL, and the static chain assignment, if present, happens to be the last insn of that sequence (calls.c emit_call_1 stuff).
Alternative approaches considered: 1) Turn off TARGET_POINTERS_TO_NESTED_FUNCTIONS for Go in rs6000_option_override_internal, similar to the hack posted in the PR. That fixes Go, but leaves __builtin_call_with_static_chain broken. 2) Turn off TARGET_POINTERS_TO_NESTED_FUNCTIONS everywhere. This means rewriting rs6000_trampoline_init to not put the static chain value into the trampoline function descriptor, and possibly other code. Might also affect user code. 3) Arrange to have a new flag set in the third arg of rs6000_call_aix. This isn't simple due to none of INIT_CUMULATIVE_ARGS or various targetm.calls hooks having access to the call expression. We don't have a function decl either, since this is an indirect call. Bootstrapped and regression tested powerpc64-linux. OK to apply? PR target/64876 * config/rs6000/rs6000.c (chain_already_loaded): New function. (rs6000_call_aix): Use it. Index: gcc/config/rs6000/rs6000.c =================================================================== --- gcc/config/rs6000/rs6000.c (revision 220358) +++ gcc/config/rs6000/rs6000.c (working copy) @@ -32919,7 +32987,29 @@ rs6000_legitimate_constant_p (machine_mode mode, r } +/* Return TRUE iff the sequence ending in LAST sets the static chain. */ +static bool +chain_already_loaded (rtx_insn *last) +{ + if (last != NULL) + { + rtx patt = PATTERN (last); + + if (GET_CODE (patt) == SET) + { + rtx lhs = XEXP (patt, 0); + + if (REG_P (lhs) && REGNO (lhs) == STATIC_CHAIN_REGNUM) + return true; + } + } + /* This function is only called when we are about to emit a call, + and we know that the static chain is set just before a call, so + there is no need to look at previous insns. */ + return false; +} + /* Expand code to perform a call under the AIX or ELFv2 ABI. */ void @@ -33002,7 +33092,9 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx fla originally direct, the 3rd word has not been written since no trampoline has been built, so we ought not to load it, lest we override a static chain value. */ - if (!direct_call_p && TARGET_POINTERS_TO_NESTED_FUNCTIONS) + if (!direct_call_p + && TARGET_POINTERS_TO_NESTED_FUNCTIONS + && !chain_already_loaded (crtl->emit.sequence_stack->last)) { rtx sc_reg = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM); rtx func_sc_offset = GEN_INT (2 * GET_MODE_SIZE (Pmode)); -- Alan Modra Australia Development Lab, IBM