1 /* Mode switching cleanup pass for the EPIPHANY cpu. 2 Copyright (C) 2000-2015 Free Software Foundation, Inc. 3 Contributed by Embecosm on behalf of Adapteva, Inc. 4 5 This file is part of GCC. 6 7 GCC is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3, or (at your option) 10 any later version. 11 12 GCC is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with GCC; see the file COPYING3. If not see 19 <http://www.gnu.org/licenses/>. */ 20 21 #include "config.h" 22 #include "system.h" 23 #include "coretypes.h" 24 #include "machmode.h" 25 #include "tm.h" 26 #include "hard-reg-set.h" 27 #include "tm_p.h" 28 #include "vec.h" 29 #include "sbitmap.h" 30 #include "predict.h" 31 #include "hashtab.h" 32 #include "hash-set.h" 33 #include "input.h" 34 #include "function.h" 35 #include "dominance.h" 36 #include "cfg.h" 37 #include "cfgrtl.h" 38 #include "cfganal.h" 39 #include "lcm.h" 40 #include "cfgbuild.h" 41 #include "cfgcleanup.h" 42 #include "basic-block.h" 43 #include "df.h" 44 #include "rtl.h" 45 #include "insn-config.h" 46 #include "insn-codes.h" 47 #include "emit-rtl.h" 48 #include "recog.h" 49 #include "insn-attr-common.h" 50 #include "tree-pass.h" 51 52 namespace { 53 54 const pass_data pass_data_resolve_sw_modes = 55 { 56 RTL_PASS, /* type */ 57 "resolve_sw_modes", /* name */ 58 OPTGROUP_NONE, /* optinfo_flags */ 59 TV_MODE_SWITCH, /* tv_id */ 60 0, /* properties_required */ 61 0, /* properties_provided */ 62 0, /* properties_destroyed */ 63 0, /* todo_flags_start */ 64 TODO_df_finish, /* todo_flags_finish */ 65 }; 66 67 class pass_resolve_sw_modes : public rtl_opt_pass 68 { 69 public: 70 pass_resolve_sw_modes(gcc::context *ctxt) 71 : rtl_opt_pass(pass_data_resolve_sw_modes, ctxt) 72 {} 73 74 /* opt_pass methods: */ 75 virtual bool gate (function *) { return optimize; } 76 virtual unsigned int execute (function *); 77 78 }; // class pass_resolve_sw_modes 79 80 /* Clean-up after mode switching: 81 Check for mode setting insns that have FP_MODE_ROUND_UNKNOWN. 82 If only one rounding mode is required, select that one. 83 Else we have to choose one to use in this mode setting insn and 84 insert new mode setting insns on the edges where the other mode 85 becomes unambigous. */ 86 87 unsigned 88 pass_resolve_sw_modes::execute (function *fun) 89 { 90 basic_block bb; 91 rtx_insn *insn; 92 rtx src; 93 vec<basic_block> todo; 94 sbitmap pushed; 95 bool need_commit = false; 96 bool finalize_fp_sets = (MACHINE_FUNCTION (cfun)->unknown_mode_sets == 0); 97 98 todo.create (last_basic_block_for_fn (fun)); 99 pushed = sbitmap_alloc (last_basic_block_for_fn (fun)); 100 bitmap_clear (pushed); 101 if (!finalize_fp_sets) 102 { 103 df_note_add_problem (); 104 df_analyze (); 105 } 106 FOR_EACH_BB_FN (bb, fun) 107 FOR_BB_INSNS (bb, insn) 108 { 109 enum attr_fp_mode selected_mode; 110 111 if (!NONJUMP_INSN_P (insn) 112 || recog_memoized (insn) != CODE_FOR_set_fp_mode) 113 continue; 114 src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); 115 if (finalize_fp_sets) 116 { 117 SET_SRC (XVECEXP (PATTERN (insn), 0, 2)) = copy_rtx (src); 118 if (REG_P (src)) 119 df_insn_rescan (insn); 120 continue; 121 } 122 if (REG_P (src) 123 || XINT (XVECEXP (XEXP (src, 0), 0, 0), 0) != FP_MODE_ROUND_UNKNOWN) 124 continue; 125 if (find_regno_note (insn, REG_UNUSED, FP_TRUNCATE_REGNUM)) 126 selected_mode = FP_MODE_ROUND_NEAREST; 127 else if (find_regno_note (insn, REG_UNUSED, FP_NEAREST_REGNUM)) 128 selected_mode = FP_MODE_ROUND_TRUNC; 129 else 130 { 131 /* We could get more fancy in the selection of the mode by 132 checking the total frequency of the affected edges. */ 133 selected_mode = (enum attr_fp_mode) epiphany_normal_fp_rounding; 134 135 todo.quick_push (bb); 136 bitmap_set_bit (pushed, bb->index); 137 } 138 XVECEXP (XEXP (src, 0), 0, 0) = GEN_INT (selected_mode); 139 SET_SRC (XVECEXP (PATTERN (insn), 0, 1)) = copy_rtx (src); 140 SET_SRC (XVECEXP (PATTERN (insn), 0, 2)) = copy_rtx (src); 141 df_insn_rescan (insn); 142 } 143 while (todo.length ()) 144 { 145 basic_block bb = todo.pop (); 146 int selected_reg, jilted_reg; 147 enum attr_fp_mode jilted_mode; 148 edge e; 149 edge_iterator ei; 150 151 bitmap_set_bit (pushed, bb->index); 152 bitmap_set_bit (pushed, bb->index); 153 154 if (epiphany_normal_fp_rounding == FP_MODE_ROUND_NEAREST) 155 { 156 selected_reg = FP_NEAREST_REGNUM; 157 jilted_reg = FP_TRUNCATE_REGNUM; 158 jilted_mode = FP_MODE_ROUND_TRUNC; 159 } 160 else 161 { 162 selected_reg = FP_TRUNCATE_REGNUM; 163 jilted_reg = FP_NEAREST_REGNUM; 164 jilted_mode = FP_MODE_ROUND_NEAREST; 165 } 166 167 FOR_EACH_EDGE (e, ei, bb->succs) 168 { 169 basic_block succ = e->dest; 170 rtx_insn *seq; 171 172 if (!REGNO_REG_SET_P (DF_LIVE_IN (succ), jilted_reg)) 173 continue; 174 if (REGNO_REG_SET_P (DF_LIVE_IN (succ), selected_reg)) 175 { 176 if (bitmap_bit_p (pushed, succ->index)) 177 continue; 178 todo.quick_push (succ); 179 bitmap_set_bit (pushed, bb->index); 180 continue; 181 } 182 start_sequence (); 183 emit_set_fp_mode (EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN, 184 jilted_mode, FP_MODE_NONE, NULL); 185 seq = get_insns (); 186 end_sequence (); 187 need_commit = true; 188 insert_insn_on_edge (seq, e); 189 } 190 } 191 todo.release (); 192 sbitmap_free (pushed); 193 if (need_commit) 194 commit_edge_insertions (); 195 return 0; 196 } 197 198 } // anon namespace 199 200 rtl_opt_pass * 201 make_pass_resolve_sw_modes (gcc::context *ctxt) 202 { 203 return new pass_resolve_sw_modes (ctxt); 204 } 205