Index: gcc/config/nios2/nios2-protos.h =================================================================== --- gcc/config/nios2/nios2-protos.h (revision 446123) +++ gcc/config/nios2/nios2-protos.h (working copy) @@ -32,7 +32,7 @@ extern void nios2_function_profiler (FILE *, int); #ifdef RTX_CODE extern bool nios2_emit_move_sequence (rtx *, enum machine_mode); extern void nios2_emit_expensive_div (rtx *, enum machine_mode); -extern void nios2_adjust_call_address (rtx *); +extern void nios2_adjust_call_address (rtx *, rtx); extern rtx nios2_get_return_address (int); extern void nios2_set_return_address (rtx, rtx); Index: gcc/config/nios2/nios2.c =================================================================== --- gcc/config/nios2/nios2.c (revision 446123) +++ gcc/config/nios2/nios2.c (working copy) @@ -1511,12 +1511,12 @@ nios2_unspec_offset (rtx loc, int unspec) /* Generate GOT pointer based address with large offset. */ static rtx -nios2_large_got_address (rtx offset) +nios2_large_got_address (rtx offset, rtx tmp) { - rtx addr = gen_reg_rtx (Pmode); - emit_insn (gen_add3_insn (addr, pic_offset_table_rtx, - force_reg (Pmode, offset))); - return addr; + if (!tmp) + tmp = gen_reg_rtx (Pmode); + emit_move_insn (tmp, offset); + return gen_rtx_PLUS (Pmode, tmp, pic_offset_table_rtx); } /* Generate a GOT pointer based address. */ @@ -1527,7 +1527,7 @@ nios2_got_address (rtx loc, int unspec) crtl->uses_pic_offset_table = 1; if (nios2_large_offset_p (unspec)) - return nios2_large_got_address (offset); + return force_reg (Pmode, nios2_large_got_address (offset, NULL_RTX)); return gen_rtx_PLUS (Pmode, pic_offset_table_rtx, offset); } @@ -2080,13 +2080,17 @@ nios2_load_pic_register (void) /* Generate a PIC address as a MEM rtx. */ static rtx -nios2_load_pic_address (rtx sym, int unspec) +nios2_load_pic_address (rtx sym, int unspec, rtx tmp) { if (flag_pic == 2 && GET_CODE (sym) == SYMBOL_REF && nios2_symbol_binds_local_p (sym)) /* Under -fPIC, generate a GOTOFF address for local symbols. */ - return nios2_got_address (sym, UNSPEC_PIC_GOTOFF_SYM); + { + rtx offset = nios2_unspec_offset (sym, UNSPEC_PIC_GOTOFF_SYM); + crtl->uses_pic_offset_table = 1; + return nios2_large_got_address (offset, tmp); + } return gen_const_mem (Pmode, nios2_got_address (sym, unspec)); } @@ -2122,7 +2126,7 @@ nios2_legitimize_constant_address (rtx addr) if (nios2_tls_symbol_p (base)) base = nios2_legitimize_tls_address (base); else if (flag_pic) - base = nios2_load_pic_address (base, UNSPEC_PIC_SYM); + base = nios2_load_pic_address (base, UNSPEC_PIC_SYM, NULL_RTX); else return addr; @@ -2266,18 +2270,24 @@ nios2_emit_move_sequence (rtx *operands, enum mach /* The function with address *ADDR is being called. If the address needs to be loaded from the GOT, emit the instruction to do so and - update *ADDR to point to the rtx for the loaded value. */ + update *ADDR to point to the rtx for the loaded value. + If REG != NULL_RTX, it is used as the target/scratch register in the + GOT address calculation. */ void -nios2_adjust_call_address (rtx *call_op) +nios2_adjust_call_address (rtx *call_op, rtx reg) { - rtx addr; - gcc_assert (MEM_P (*call_op)); - addr = XEXP (*call_op, 0); + if (MEM_P (*call_op)) + call_op = &XEXP (*call_op, 0); + + rtx addr = *call_op; if (flag_pic && CONSTANT_P (addr)) { - rtx reg = gen_reg_rtx (Pmode); - emit_move_insn (reg, nios2_load_pic_address (addr, UNSPEC_PIC_CALL_SYM)); - XEXP (*call_op, 0) = reg; + rtx tmp = reg ? reg : NULL_RTX; + if (!reg) + reg = gen_reg_rtx (Pmode); + addr = nios2_load_pic_address (addr, UNSPEC_PIC_CALL_SYM, tmp); + emit_insn (gen_rtx_SET (VOIDmode, reg, addr)); + *call_op = reg; } } @@ -4980,8 +4990,10 @@ nios2_asm_output_mi_thunk (FILE *file, tree thunk_ TREE_USED (function) = 1; } funexp = XEXP (DECL_RTL (function), 0); - funexp = gen_rtx_MEM (FUNCTION_MODE, funexp); - insn = emit_call_insn (gen_sibcall (funexp, const0_rtx)); + /* Function address needs to be constructed under PIC, + provide r2 to use here. */ + nios2_adjust_call_address (&funexp, gen_rtx_REG (Pmode, 2)); + insn = emit_call_insn (gen_sibcall_internal (funexp, const0_rtx)); SIBLING_CALL_P (insn) = 1; /* Run just enough of rest_of_compilation to get the insns emitted. Index: gcc/config/nios2/nios2.md =================================================================== --- gcc/config/nios2/nios2.md (revision 446123) +++ gcc/config/nios2/nios2.md (working copy) @@ -818,7 +818,7 @@ (match_operand 1 "" "")) (clobber (reg:SI RA_REGNO))])] "" - "nios2_adjust_call_address (&operands[0]);") + "nios2_adjust_call_address (&operands[0], NULL_RTX);") (define_expand "call_value" [(parallel [(set (match_operand 0 "" "") @@ -826,7 +826,7 @@ (match_operand 2 "" ""))) (clobber (reg:SI RA_REGNO))])] "" - "nios2_adjust_call_address (&operands[1]);") + "nios2_adjust_call_address (&operands[1], NULL_RTX);") (define_insn "*call" [(call (mem:QI (match_operand:SI 0 "call_operand" "i,r")) @@ -854,7 +854,7 @@ (match_operand 1 "" "")) (return)])] "" - "nios2_adjust_call_address (&operands[0]);") + "nios2_adjust_call_address (&operands[0], NULL_RTX);") (define_expand "sibcall_value" [(parallel [(set (match_operand 0 "" "") @@ -862,9 +862,9 @@ (match_operand 2 "" ""))) (return)])] "" - "nios2_adjust_call_address (&operands[1]);") + "nios2_adjust_call_address (&operands[1], NULL_RTX);") -(define_insn "*sibcall" +(define_insn "sibcall_internal" [(call (mem:QI (match_operand:SI 0 "call_operand" "i,j")) (match_operand 1 "" "")) (return)] @@ -874,7 +874,7 @@ jmp.r\\t%0" [(set_attr "type" "control")]) -(define_insn "*sibcall_value" +(define_insn "sibcall_value_internal" [(set (match_operand 0 "register_operand" "") (call (mem:QI (match_operand:SI 1 "call_operand" "i,j")) (match_operand 2 "" "")))