2014-07-12 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / gcc / config / epiphany / resolve-sw-modes.c
blobf40cc8dbad52a239b9218d86ca55590ce0953d6b
1 /* Mode switching cleanup pass for the EPIPHANY cpu.
2 Copyright (C) 2000-2014 Free Software Foundation, Inc.
3 Contributed by Embecosm on behalf of Adapteva, Inc.
5 This file is part of GCC.
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.
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.
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/>. */
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 "basic-block.h"
31 #include "df.h"
32 #include "rtl.h"
33 #include "insn-config.h"
34 #include "insn-codes.h"
35 #include "emit-rtl.h"
36 #include "recog.h"
37 #include "function.h"
38 #include "insn-attr-common.h"
39 #include "tree-pass.h"
41 namespace {
43 const pass_data pass_data_resolve_sw_modes =
45 RTL_PASS, /* type */
46 "resolve_sw_modes", /* name */
47 OPTGROUP_NONE, /* optinfo_flags */
48 TV_MODE_SWITCH, /* tv_id */
49 0, /* properties_required */
50 0, /* properties_provided */
51 0, /* properties_destroyed */
52 0, /* todo_flags_start */
53 TODO_df_finish, /* todo_flags_finish */
56 class pass_resolve_sw_modes : public rtl_opt_pass
58 public:
59 pass_resolve_sw_modes(gcc::context *ctxt)
60 : rtl_opt_pass(pass_data_resolve_sw_modes, ctxt)
63 /* opt_pass methods: */
64 virtual bool gate (function *) { return optimize; }
65 virtual unsigned int execute (function *);
67 }; // class pass_resolve_sw_modes
69 /* Clean-up after mode switching:
70 Check for mode setting insns that have FP_MODE_ROUND_UNKNOWN.
71 If only one rounding mode is required, select that one.
72 Else we have to choose one to use in this mode setting insn and
73 insert new mode setting insns on the edges where the other mode
74 becomes unambigous. */
76 unsigned
77 pass_resolve_sw_modes::execute (function *fun)
79 basic_block bb;
80 rtx insn, src;
81 vec<basic_block> todo;
82 sbitmap pushed;
83 bool need_commit = false;
84 bool finalize_fp_sets = (MACHINE_FUNCTION (cfun)->unknown_mode_sets == 0);
86 todo.create (last_basic_block_for_fn (fun));
87 pushed = sbitmap_alloc (last_basic_block_for_fn (fun));
88 bitmap_clear (pushed);
89 if (!finalize_fp_sets)
91 df_note_add_problem ();
92 df_analyze ();
94 FOR_EACH_BB_FN (bb, fun)
95 FOR_BB_INSNS (bb, insn)
97 enum attr_fp_mode selected_mode;
99 if (!NONJUMP_INSN_P (insn)
100 || recog_memoized (insn) != CODE_FOR_set_fp_mode)
101 continue;
102 src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
103 if (finalize_fp_sets)
105 SET_SRC (XVECEXP (PATTERN (insn), 0, 2)) = copy_rtx (src);
106 if (REG_P (src))
107 df_insn_rescan (insn);
108 continue;
110 if (REG_P (src)
111 || XINT (XVECEXP (XEXP (src, 0), 0, 0), 0) != FP_MODE_ROUND_UNKNOWN)
112 continue;
113 if (find_regno_note (insn, REG_UNUSED, FP_TRUNCATE_REGNUM))
114 selected_mode = FP_MODE_ROUND_NEAREST;
115 else if (find_regno_note (insn, REG_UNUSED, FP_NEAREST_REGNUM))
116 selected_mode = FP_MODE_ROUND_TRUNC;
117 else
119 /* We could get more fancy in the selection of the mode by
120 checking the total frequency of the affected edges. */
121 selected_mode = (enum attr_fp_mode) epiphany_normal_fp_rounding;
123 todo.quick_push (bb);
124 bitmap_set_bit (pushed, bb->index);
126 XVECEXP (XEXP (src, 0), 0, 0) = GEN_INT (selected_mode);
127 SET_SRC (XVECEXP (PATTERN (insn), 0, 1)) = copy_rtx (src);
128 SET_SRC (XVECEXP (PATTERN (insn), 0, 2)) = copy_rtx (src);
129 df_insn_rescan (insn);
131 while (todo.length ())
133 basic_block bb = todo.pop ();
134 int selected_reg, jilted_reg;
135 enum attr_fp_mode jilted_mode;
136 edge e;
137 edge_iterator ei;
139 bitmap_set_bit (pushed, bb->index);
140 bitmap_set_bit (pushed, bb->index);
142 if (epiphany_normal_fp_rounding == FP_MODE_ROUND_NEAREST)
144 selected_reg = FP_NEAREST_REGNUM;
145 jilted_reg = FP_TRUNCATE_REGNUM;
146 jilted_mode = FP_MODE_ROUND_TRUNC;
148 else
150 selected_reg = FP_TRUNCATE_REGNUM;
151 jilted_reg = FP_NEAREST_REGNUM;
152 jilted_mode = FP_MODE_ROUND_NEAREST;
155 FOR_EACH_EDGE (e, ei, bb->succs)
157 basic_block succ = e->dest;
158 rtx seq;
160 if (!REGNO_REG_SET_P (DF_LIVE_IN (succ), jilted_reg))
161 continue;
162 if (REGNO_REG_SET_P (DF_LIVE_IN (succ), selected_reg))
164 if (bitmap_bit_p (pushed, succ->index))
165 continue;
166 todo.quick_push (succ);
167 bitmap_set_bit (pushed, bb->index);
168 continue;
170 start_sequence ();
171 emit_set_fp_mode (EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN,
172 jilted_mode, FP_MODE_NONE, NULL);
173 seq = get_insns ();
174 end_sequence ();
175 need_commit = true;
176 insert_insn_on_edge (seq, e);
179 todo.release ();
180 sbitmap_free (pushed);
181 if (need_commit)
182 commit_edge_insertions ();
183 return 0;
186 } // anon namespace
188 rtl_opt_pass *
189 make_pass_resolve_sw_modes (gcc::context *ctxt)
191 return new pass_resolve_sw_modes (ctxt);