| /* This file is part of GCC. |
| |
| GCC 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 3, or (at your option) |
| any later version. |
| |
| GCC 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 GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| /* This file contains code aimed at optimizing function generated with the |
| use of '-msave-restore. The goal is to identify cases where the call |
| out to the save/restore routines are sub-optimal, and remove the calls |
| in this case. |
| |
| As GCC currently makes the choice between using or not using |
| save/restore early on (during the gimple expand pass) once we have |
| selected to use save/restore we are stuck with it. */ |
| |
| #define IN_TARGET_CODE 1 |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "tm.h" |
| #include "rtl.h" |
| #include "function.h" |
| #include "memmodel.h" |
| #include "emit-rtl.h" |
| #include "target.h" |
| #include "basic-block.h" |
| #include "bitmap.h" |
| #include "df.h" |
| #include "tree.h" |
| #include "expr.h" |
| #include "cfg.h" |
| |
| /* This file should be included last. */ |
| #include "hard-reg-set.h" |
| |
| /* Look in the function prologue for a call to the save stub. Ensure that |
| the instruction is as we expect (see detail below) and if the |
| instruction matches return a pointer to it. Otherwise, return NULL. |
| |
| We expect the function prologue to look like this: |
| |
| (note NOTE_INSN_BASIC_BLOCK) |
| (insn (parallel [ |
| (unspec_volatile [ |
| (const_int 2 [0x2]) |
| ] UNSPECV_GPR_SAVE) |
| (clobber (reg:SI 5 t0)) |
| (clobber (reg:SI 6 t1))]) |
| (note NOTE_INSN_PROLOGUE_END) |
| |
| Between the NOTE_INSN_BASIC_BLOCK and the GPR_SAVE insn we might find |
| other notes of type NOTE_INSN_DELETED and/or NOTE_INSN_FUNCTION_BEG. |
| |
| The parameter BODY is updated to point to the first instruction after |
| the NOTE_INSN_PROLOGUE_END or will be updated to NULL if the prologue |
| end note was not found. */ |
| |
| static rtx_insn * |
| riscv_sr_match_prologue (rtx_insn **body) |
| { |
| rtx_insn *insn, *bb_note; |
| *body = NULL; |
| |
| /* Find the prologue end note. */ |
| for (insn = get_insns (); insn != NULL; insn = NEXT_INSN (insn)) |
| if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_PROLOGUE_END) |
| { |
| *body = NEXT_INSN (insn); |
| break; |
| } |
| |
| /* If we don't have the prologue end note and at least one instruction |
| before it, then this function doesn't have the structure we expect. */ |
| if (insn == NULL |
| || PREV_INSN (insn) == NULL) |
| return NULL; |
| |
| /* The INSN is the end of prologue note, before this we expect to find |
| one real instruction which makes the prologue, and before that we |
| expect to find some number of notes for deleted instructions, the |
| beginning of the function, and finally a basicblock beginning. The |
| following loop checks that this assumption is true. */ |
| for (bb_note = PREV_INSN (PREV_INSN (insn)); |
| bb_note != NULL; |
| bb_note = PREV_INSN (bb_note)) |
| { |
| if (!NOTE_P (bb_note)) |
| return NULL; |
| if (NOTE_KIND (bb_note) == NOTE_INSN_BASIC_BLOCK) |
| break; |
| if (NOTE_KIND (bb_note) != NOTE_INSN_DELETED |
| && NOTE_KIND (bb_note) != NOTE_INSN_FUNCTION_BEG) |
| return NULL; |
| } |
| if (bb_note == NULL) |
| return NULL; |
| |
| /* Set INSN to point to the actual interesting prologue instruction. */ |
| insn = PREV_INSN (insn); |
| if (INSN_P (insn) |
| && INSN_CODE (insn) == CODE_FOR_gpr_save |
| /* Check this is a call to _riscv_save_0. */ |
| && GET_CODE (PATTERN (insn)) == PARALLEL |
| && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == UNSPEC_VOLATILE |
| && (GET_CODE (XVECEXP (XVECEXP (PATTERN (insn), 0, 0), 0, 0)) |
| == CONST_INT) |
| && INTVAL (XVECEXP (XVECEXP (PATTERN (insn), 0, 0), 0, 0)) == 0) |
| return insn; |
| |
| return NULL; |
| } |
| |
| /* Find the first instruction in the epilogue of the current function, and |
| return a pointer to that instruction if, and only if, the epilogue has |
| the correct structure that would allow us to optimize out the call to |
| _riscv_restore_0. */ |
| |
| static rtx_insn * |
| riscv_sr_match_epilogue (void) |
| { |
| /* Find the first instruction in the epilogue. */ |
| rtx_insn *insn, *start; |
| for (insn = get_insns (); insn != NULL; insn = NEXT_INSN (insn)) |
| if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_EPILOGUE_BEG) |
| { |
| insn = NEXT_INSN (insn); |
| break; |
| } |
| if (insn == NULL) |
| return NULL; |
| |
| /* At this point INSN is the first instruction in the epilogue. A |
| standard epilogue (of the form we expect to handle) consists of the |
| following instructions: |
| |
| 1. A stack_tiesi or stack_tiedi (for RV32 and RV64 respectively), |
| |
| 2. An optional use instruction for the register holding the return |
| value. This will be missing in functions with no return value, |
| |
| 3. A gpr_restore instruction, and |
| |
| 4. A jump instruction of type gpr_restore_return. */ |
| start = insn; |
| if (INSN_CODE (insn) != CODE_FOR_stack_tiesi |
| && INSN_CODE (insn) != CODE_FOR_stack_tiedi) |
| return NULL; |
| |
| insn = NEXT_INSN (insn); |
| if (INSN_P (insn) && GET_CODE (PATTERN (insn)) == USE) |
| insn = NEXT_INSN (insn); |
| |
| if (!INSN_P (insn) || INSN_CODE (insn) != CODE_FOR_gpr_restore) |
| return NULL; |
| |
| insn = NEXT_INSN (insn); |
| if (!INSN_P (insn) || INSN_CODE (insn) != CODE_FOR_gpr_restore_return) |
| return NULL; |
| |
| return start; |
| } |
| |
| /* Helper for riscv_remove_unneeded_save_restore_calls. If we match the |
| prologue instructions but not the epilogue then we might have the case |
| where the epilogue has been optimized out due to a call to a no-return |
| function. In this case we might be able to remove the prologue too - |
| that's what this function does. PROLOGUE is the matched prolgoue |
| instruction, by the time this function returns the progloue instruction |
| may have been removed. */ |
| |
| static void |
| check_for_no_return_call (rtx_insn *prologue) |
| { |
| /* Check to see if we have the following pattern: |
| |
| PROLOGUE instruction |
| NOTE_INSN_PROLOGUE_END |
| A no-return call instruction |
| |
| If we do, then we can remove the prologue instruction safely. Remember |
| that we've already confirmed by this point that the prologue is a call |
| to riscv_save_0. */ |
| |
| if (dump_file) |
| fprintf (dump_file, |
| "Prologue matched, checking for no-return epilogue.\n"); |
| |
| rtx_insn *tmp = NEXT_INSN (prologue); |
| if (!NOTE_P (tmp) || NOTE_KIND (tmp) != NOTE_INSN_PROLOGUE_END) |
| return; |
| |
| /* Skip any extra notes in here, they're most likely just debug. */ |
| do |
| { |
| tmp = NEXT_INSN (tmp); |
| } |
| while (tmp != NULL && NOTE_P (tmp)); |
| |
| if (tmp == NULL || !INSN_P (tmp)) |
| return; |
| |
| bool noreturn_p = find_reg_note (tmp, REG_NORETURN, NULL_RTX) != NULL_RTX; |
| if (!CALL_P (tmp) || !noreturn_p) |
| return; |
| |
| if (dump_file) |
| fprintf (dump_file, |
| "Prologue call to riscv_save_0 followed by noreturn call, " |
| "removing prologue.\n"); |
| remove_insn (prologue); |
| } |
| |
| /* Entry point called from riscv_reorg to remove some unneeded calls to |
| the save and restore stubs. This should only be called when |
| -msave-restore is in use. |
| |
| We identify some simple cases where the function looks like this: |
| |
| call t0,__riscv_save_0 |
| <other-code> |
| call foo |
| tail __riscv_restore_0 |
| |
| And transform it into something like this: |
| |
| <other-code> |
| tail foo |
| |
| In the above examples, what can appear in <other-code> is pretty |
| restricted; only caller saved registers can be touched, this prevents |
| any additional calls (as they would write to 'ra'). */ |
| |
| void |
| riscv_remove_unneeded_save_restore_calls (void) |
| { |
| /* We'll adjust stack size after this optimization, that require update every |
| sp use site, which could be unsafe, so we decide to turn off this |
| optimization if there are any arguments put on stack. */ |
| if (crtl->args.size != 0) |
| return; |
| |
| /* Will point to the first instruction of the function body, after the |
| prologue end note. */ |
| rtx_insn *body = NULL; |
| |
| /* Should only be called with -msave-restore is in use. */ |
| gcc_assert (TARGET_SAVE_RESTORE); |
| |
| /* Match the expected prologue and epilogue patterns. If either of these |
| fail to match then we abandon our attempt to optimize this function. */ |
| rtx_insn *prologue_matched = riscv_sr_match_prologue (&body); |
| if (prologue_matched == NULL || body == NULL) |
| return; |
| |
| rtx_insn *epilogue_matched = riscv_sr_match_epilogue (); |
| if (epilogue_matched == NULL) |
| { |
| check_for_no_return_call (prologue_matched); |
| return; |
| } |
| |
| if (dump_file) |
| fprintf (dump_file, |
| "Could be a candidate for save/restore removal\n"); |
| |
| /* We want to check which registers this function uses. */ |
| df_analyze (); |
| |
| int call_count = 0; |
| bool good_use = true; |
| int epilogue_count = 0; |
| |
| /* Now examine all of the instructions that make up this function, we're |
| looking for call instructions and also double checking register usage |
| while we're at it (see comments below). */ |
| basic_block bb; |
| FOR_EACH_BB_FN (bb, cfun) |
| { |
| rtx_insn *insn; |
| |
| FOR_BB_INSNS (bb, insn) |
| { |
| if (dump_file) |
| fprintf (dump_file, |
| "Block %d, Insn %d\n", bb->index, INSN_UID (insn)); |
| |
| /* If we scan the epilogue we will fall foul of our register |
| usage check below (due to it's use of the return address), so |
| once we spot we're at the epilogue, just skip the rest of this |
| block. Scanning the prologue instructions again (if they |
| match the expected pattern) is harmless. */ |
| if (NOTE_P (insn) |
| && NOTE_KIND (insn) == NOTE_INSN_EPILOGUE_BEG) |
| { |
| ++epilogue_count; |
| break; |
| } |
| |
| if (!INSN_P (insn)) |
| continue; |
| |
| if (CALL_P (insn)) |
| ++call_count; |
| /* Ignore any USEs in the gpr_save pattern. They don't prevent us |
| from optimizing away the save call. */ |
| else if (insn == prologue_matched) |
| ; |
| else |
| { |
| df_ref use; |
| |
| FOR_EACH_INSN_USE (use, insn) |
| { |
| /* If the function makes use of any registers that are |
| callee saved then we should be saving them in this |
| function, which would suggest that a call to the save |
| and restore functions is required. This would seem to |
| indicate that something has gone wrong above, as we |
| should only get here if we are saving zero registers. |
| |
| The one exception to this rule is the return address |
| register used within a call instruction. We can |
| optimize a single call within a function (by making it |
| a tail call), so we skip call instructions here. */ |
| if (!call_used_regs[DF_REF_REGNO (use)]) |
| { |
| if (dump_file) |
| fprintf (dump_file, |
| "Found unsupported use of callee saved " |
| "register in instruction %d\n", |
| INSN_UID (insn)); |
| good_use = false; |
| break; |
| } |
| } |
| if (!good_use) |
| break; |
| } |
| } |
| } |
| |
| /* If we used any registers that would indicate a need for a call to a |
| save/restore stub then don't optimize. */ |
| if (!good_use) |
| return; |
| |
| /* If this function has multiple epilogues, then for now we don't try to |
| optimize it. */ |
| if (epilogue_count != 1) |
| return; |
| |
| /* We can only optimize functions containing a single call, any more |
| would require us to add instructions to store the return address on |
| the stack (and restore it before we return). We could do this in the |
| future, but for now we don't. A single call can be transformed into |
| a tail call reasonably easily. */ |
| if (call_count > 1) |
| { |
| if (dump_file) |
| fprintf (dump_file, |
| "Found too many call instructions\n"); |
| return; |
| } |
| |
| rtx_insn *epilogue_begin_note = PREV_INSN (epilogue_matched); |
| gcc_assert (NOTE_P (epilogue_begin_note) |
| && NOTE_KIND (epilogue_begin_note) == NOTE_INSN_EPILOGUE_BEG); |
| |
| df_finish_pass (false); |
| |
| /* Find the first instruction before the function epilogue. */ |
| rtx_insn *insn_before_epilogue; |
| for (insn_before_epilogue = PREV_INSN (epilogue_begin_note); |
| NOTE_P (insn_before_epilogue); |
| insn_before_epilogue = PREV_INSN (insn_before_epilogue)) |
| ; |
| |
| /* Leaf functions will not generate calls to the save/restore stubs, so |
| there's no need for this optimization there. We know this function |
| has no more than 1 call (checked above). To convert this single call |
| into a tail call we rely on the call being the last thing before the |
| epilogue. */ |
| if (GET_CODE (insn_before_epilogue) != CALL_INSN) |
| return; |
| |
| /* The last instruction in this block, just before the epilogue is a |
| call. We can potentially change this call into a tail call. */ |
| rtx_insn *call = insn_before_epilogue; |
| |
| /* Transform call in insn to a sibcall, this will only be done if the |
| last thing in the function is a call. */ |
| rtx callpat = PATTERN (call); |
| gcc_assert (GET_CODE (callpat) == PARALLEL); |
| |
| /* Extract from CALLPAT the information we need to build the sibcall. */ |
| rtx target_call = NULL; |
| rtx tmp_rtx = XVECEXP (callpat, 0, 0); |
| rtx set_target = NULL; |
| switch (GET_CODE (tmp_rtx)) |
| { |
| case CALL: |
| target_call = tmp_rtx; |
| break; |
| |
| case SET: |
| { |
| set_target = XEXP (tmp_rtx, 0); |
| tmp_rtx = XEXP (tmp_rtx, 1); |
| if (GET_CODE (tmp_rtx) != CALL) |
| return; |
| target_call = tmp_rtx; |
| break; |
| } |
| |
| default: |
| return; |
| } |
| |
| rtx target_mem = XEXP (target_call, 0); |
| if (GET_CODE (target_mem) != MEM) |
| return; |
| |
| rtx target = XEXP (target_mem, 0); |
| if (GET_CODE (target) != SYMBOL_REF && GET_CODE (target) != REG) |
| return; |
| |
| /* The sibcall instructions can only use a specific subset of |
| registers, we're about to (possibly) move a call through a |
| register from the function body and make it a sibcall. If we're |
| not using an appropriate register then we can't make this change. |
| |
| Maybe in some future iteration we could actually scan the |
| function, find a suitable sibcall register, and switch over the |
| registers. But we don't do that yet. */ |
| if (GET_CODE (target) == REG |
| && !SIBCALL_REG_P (REGNO (target))) |
| return; |
| |
| rtx sibcall = NULL; |
| if (set_target != NULL) |
| sibcall |
| = gen_sibcall_value_internal (set_target, target, const0_rtx); |
| else |
| sibcall = gen_sibcall_internal (target, const0_rtx); |
| |
| rtx_insn *before_call = PREV_INSN (call); |
| remove_insn (call); |
| rtx_insn *insn = emit_call_insn_after_setloc (sibcall, before_call, |
| INSN_LOCATION (call)); |
| REG_NOTES (insn) = REG_NOTES (call); |
| SIBLING_CALL_P (insn) = 1; |
| |
| /* Now update the prologue and epilogue to take account of the |
| changes within the function body. */ |
| remove_insn (prologue_matched); |
| remove_insn (NEXT_INSN (NEXT_INSN (NEXT_INSN (epilogue_matched)))); |
| remove_insn (NEXT_INSN (NEXT_INSN (epilogue_matched))); |
| remove_insn (NEXT_INSN (epilogue_matched)); |
| remove_insn (epilogue_matched); |
| |
| if (dump_file) |
| fprintf (dump_file, |
| "Save/restore successfully removed\n"); |
| } |