Mercurial > hg > CbC > CbC_gcc
diff gcc/config/nds32/nds32-fp-as-gp.c @ 131:84e7813d76e9
gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 07:37:49 +0900 |
parents | 04ced10e8804 |
children | 1830386684a0 |
line wrap: on
line diff
--- a/gcc/config/nds32/nds32-fp-as-gp.c Fri Oct 27 22:46:09 2017 +0900 +++ b/gcc/config/nds32/nds32-fp-as-gp.c Thu Oct 25 07:37:49 2018 +0900 @@ -1,5 +1,5 @@ /* The fp-as-gp pass of Andes NDS32 cpu for GNU compiler - Copyright (C) 2012-2017 Free Software Foundation, Inc. + Copyright (C) 2012-2018 Free Software Foundation, Inc. Contributed by Andes Technology Corporation. This file is part of GCC. @@ -20,23 +20,262 @@ /* ------------------------------------------------------------------------ */ +#define IN_TARGET_CODE 1 + #include "config.h" #include "system.h" #include "coretypes.h" #include "backend.h" +#include "hard-reg-set.h" +#include "tm_p.h" +#include "rtl.h" +#include "memmodel.h" +#include "emit-rtl.h" +#include "insn-config.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "ira.h" +#include "ira-int.h" +#include "df.h" +#include "tree-core.h" +#include "tree-pass.h" +#include "nds32-protos.h" /* ------------------------------------------------------------------------ */ +/* A helper function to check if this function should contain prologue. */ +static bool +nds32_have_prologue_p (void) +{ + int i; + + for (i = 0; i < 28; i++) + if (NDS32_REQUIRED_CALLEE_SAVED_P (i)) + return true; + + return (flag_pic + || NDS32_REQUIRED_CALLEE_SAVED_P (FP_REGNUM) + || NDS32_REQUIRED_CALLEE_SAVED_P (LP_REGNUM)); +} + +static int +nds32_get_symbol_count (void) +{ + int symbol_count = 0; + rtx_insn *insn; + basic_block bb; + + FOR_EACH_BB_FN (bb, cfun) + { + FOR_BB_INSNS (bb, insn) + { + /* Counting the insn number which the addressing mode is symbol. */ + if (single_set (insn) && nds32_symbol_load_store_p (insn)) + { + rtx pattern = PATTERN (insn); + rtx mem; + gcc_assert (GET_CODE (pattern) == SET); + if (GET_CODE (SET_SRC (pattern)) == REG ) + mem = SET_DEST (pattern); + else + mem = SET_SRC (pattern); + + /* We have only lwi37 and swi37 for fp-as-gp optimization, + so don't count any other than SImode. + MEM for QImode and HImode will wrap by ZERO_EXTEND + or SIGN_EXTEND */ + if (GET_CODE (mem) == MEM) + symbol_count++; + } + } + } + + return symbol_count; +} + /* Function to determine whether it is worth to do fp_as_gp optimization. - Return 0: It is NOT worth to do fp_as_gp optimization. - Return 1: It is APPROXIMATELY worth to do fp_as_gp optimization. + Return false: It is NOT worth to do fp_as_gp optimization. + Return true: It is APPROXIMATELY worth to do fp_as_gp optimization. Note that if it is worth to do fp_as_gp optimization, we MUST set FP_REGNUM ever live in this function. */ -int +static bool nds32_fp_as_gp_check_available (void) { - /* By default we return 0. */ - return 0; + basic_block bb; + basic_block exit_bb; + edge_iterator ei; + edge e; + bool first_exit_blocks_p; + + /* If there exists ANY of following conditions, + we DO NOT perform fp_as_gp optimization: + 1. TARGET_FORBID_FP_AS_GP is set + regardless of the TARGET_FORCE_FP_AS_GP. + 2. User explicitly uses 'naked'/'no_prologue' attribute. + We use nds32_naked_function_p() to help such checking. + 3. Not optimize for size. + 4. Need frame pointer. + 5. If $fp is already required to be saved, + it means $fp is already choosen by register allocator. + Thus we better not to use it for fp_as_gp optimization. + 6. This function is a vararg function. + DO NOT apply fp_as_gp optimization on this function + because it may change and break stack frame. + 7. The epilogue is empty. + This happens when the function uses exit() + or its attribute is no_return. + In that case, compiler will not expand epilogue + so that we have no chance to output .omit_fp_end directive. */ + if (TARGET_FORBID_FP_AS_GP + || nds32_naked_function_p (current_function_decl) + || !optimize_size + || frame_pointer_needed + || NDS32_REQUIRED_CALLEE_SAVED_P (FP_REGNUM) + || (cfun->stdarg == 1) + || (find_fallthru_edge (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds) == NULL)) + return false; + + /* Disable fp_as_gp if there is any infinite loop since the fp may + reuse in infinite loops by register rename. + For check infinite loops we should make sure exit_bb is post dominate + all other basic blocks if there is no infinite loops. */ + first_exit_blocks_p = true; + exit_bb = NULL; + + FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds) + { + /* More than one exit block also do not perform fp_as_gp optimization. */ + if (!first_exit_blocks_p) + return false; + + exit_bb = e->src; + first_exit_blocks_p = false; + } + + /* Not found exit_bb? just abort fp_as_gp! */ + if (!exit_bb) + return false; + + /* Each bb should post dominate by exit_bb if there is no infinite loop! */ + FOR_EACH_BB_FN (bb, cfun) + { + if (!dominated_by_p (CDI_POST_DOMINATORS, + bb, + exit_bb)) + return false; + } + + /* Now we can check the possibility of using fp_as_gp optimization. */ + if (TARGET_FORCE_FP_AS_GP) + { + /* User explicitly issues -mforce-fp-as-gp option. */ + return true; + } + else + { + /* In the following we are going to evaluate whether + it is worth to do fp_as_gp optimization. */ + bool good_gain = false; + int symbol_count; + + int threshold; + + /* We check if there already requires prologue. + Note that $gp will be saved in prologue for PIC code generation. + After that, we can set threshold by the existence of prologue. + Each fp-implied instruction will gain 2-byte code size + from gp-aware instruction, so we have following heuristics. */ + if (flag_pic + || nds32_have_prologue_p ()) + { + /* Have-prologue: + Compiler already intends to generate prologue content, + so the fp_as_gp optimization will only insert + 'la $fp,_FP_BASE_' instruction, which will be + converted into 4-byte instruction at link time. + The threshold is "3" symbol accesses, 2 + 2 + 2 > 4. */ + threshold = 3; + } + else + { + /* None-prologue: + Compiler originally does not generate prologue content, + so the fp_as_gp optimization will NOT ONLY insert + 'la $fp,_FP_BASE' instruction, but also causes + push/pop instructions. + If we are using v3push (push25/pop25), + the threshold is "5" symbol accesses, 5*2 > 4 + 2 + 2; + If we are using normal push (smw/lmw), + the threshold is "5+2" symbol accesses 7*2 > 4 + 4 + 4. */ + threshold = 5 + (TARGET_V3PUSH ? 0 : 2); + } + + symbol_count = nds32_get_symbol_count (); + + if (symbol_count >= threshold) + good_gain = true; + + /* Enable fp_as_gp optimization when potential gain is good enough. */ + return good_gain; + } +} + +static unsigned int +nds32_fp_as_gp (void) +{ + bool fp_as_gp_p; + calculate_dominance_info (CDI_POST_DOMINATORS); + fp_as_gp_p = nds32_fp_as_gp_check_available (); + + /* Here is a hack to IRA for enable/disable a hard register per function. + We *MUST* review this way after migrate gcc 4.9! */ + if (fp_as_gp_p) { + SET_HARD_REG_BIT(this_target_ira_int->x_no_unit_alloc_regs, FP_REGNUM); + df_set_regs_ever_live (FP_REGNUM, 1); + } else { + CLEAR_HARD_REG_BIT(this_target_ira_int->x_no_unit_alloc_regs, FP_REGNUM); + } + + cfun->machine->fp_as_gp_p = fp_as_gp_p; + + free_dominance_info (CDI_POST_DOMINATORS); + return 1; +} + +const pass_data pass_data_nds32_fp_as_gp = +{ + RTL_PASS, /* type */ + "fp_as_gp", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_MACH_DEP, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ +}; + +class pass_nds32_fp_as_gp : public rtl_opt_pass +{ +public: + pass_nds32_fp_as_gp (gcc::context *ctxt) + : rtl_opt_pass (pass_data_nds32_fp_as_gp, ctxt) + {} + + /* opt_pass methods: */ + bool gate (function *) + { + return !TARGET_LINUX_ABI + && TARGET_16_BIT + && optimize_size; + } + unsigned int execute (function *) { return nds32_fp_as_gp (); } +}; + +rtl_opt_pass * +make_pass_nds32_fp_as_gp (gcc::context *ctxt) +{ + return new pass_nds32_fp_as_gp (ctxt); } /* ------------------------------------------------------------------------ */