]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/epiphany/resolve-sw-modes.c
gen-mul-tables.cc: Adjust include files.
[thirdparty/gcc.git] / gcc / config / epiphany / resolve-sw-modes.c
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 "backend.h"
25 #include "rtl.h"
26 #include "df.h"
27 #include "tm_p.h"
28 #include "insn-config.h"
29 #include "emit-rtl.h"
30 #include "recog.h"
31 #include "cfgrtl.h"
32 #include "insn-attr-common.h"
33 #include "tree-pass.h"
34
35 namespace {
36
37 const pass_data pass_data_resolve_sw_modes =
38 {
39 RTL_PASS, /* type */
40 "resolve_sw_modes", /* name */
41 OPTGROUP_NONE, /* optinfo_flags */
42 TV_MODE_SWITCH, /* tv_id */
43 0, /* properties_required */
44 0, /* properties_provided */
45 0, /* properties_destroyed */
46 0, /* todo_flags_start */
47 TODO_df_finish, /* todo_flags_finish */
48 };
49
50 class pass_resolve_sw_modes : public rtl_opt_pass
51 {
52 public:
53 pass_resolve_sw_modes(gcc::context *ctxt)
54 : rtl_opt_pass(pass_data_resolve_sw_modes, ctxt)
55 {}
56
57 /* opt_pass methods: */
58 virtual bool gate (function *) { return optimize; }
59 virtual unsigned int execute (function *);
60
61 }; // class pass_resolve_sw_modes
62
63 /* Clean-up after mode switching:
64 Check for mode setting insns that have FP_MODE_ROUND_UNKNOWN.
65 If only one rounding mode is required, select that one.
66 Else we have to choose one to use in this mode setting insn and
67 insert new mode setting insns on the edges where the other mode
68 becomes unambigous. */
69
70 unsigned
71 pass_resolve_sw_modes::execute (function *fun)
72 {
73 basic_block bb;
74 rtx_insn *insn;
75 rtx src;
76 vec<basic_block> todo;
77 sbitmap pushed;
78 bool need_commit = false;
79 bool finalize_fp_sets = (MACHINE_FUNCTION (cfun)->unknown_mode_sets == 0);
80
81 todo.create (last_basic_block_for_fn (fun));
82 pushed = sbitmap_alloc (last_basic_block_for_fn (fun));
83 bitmap_clear (pushed);
84 if (!finalize_fp_sets)
85 {
86 df_note_add_problem ();
87 df_analyze ();
88 }
89 FOR_EACH_BB_FN (bb, fun)
90 FOR_BB_INSNS (bb, insn)
91 {
92 enum attr_fp_mode selected_mode;
93
94 if (!NONJUMP_INSN_P (insn)
95 || recog_memoized (insn) != CODE_FOR_set_fp_mode)
96 continue;
97 src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
98 if (finalize_fp_sets)
99 {
100 SET_SRC (XVECEXP (PATTERN (insn), 0, 2)) = copy_rtx (src);
101 if (REG_P (src))
102 df_insn_rescan (insn);
103 continue;
104 }
105 if (REG_P (src)
106 || XINT (XVECEXP (XEXP (src, 0), 0, 0), 0) != FP_MODE_ROUND_UNKNOWN)
107 continue;
108 if (find_regno_note (insn, REG_UNUSED, FP_TRUNCATE_REGNUM))
109 selected_mode = FP_MODE_ROUND_NEAREST;
110 else if (find_regno_note (insn, REG_UNUSED, FP_NEAREST_REGNUM))
111 selected_mode = FP_MODE_ROUND_TRUNC;
112 else
113 {
114 /* We could get more fancy in the selection of the mode by
115 checking the total frequency of the affected edges. */
116 selected_mode = (enum attr_fp_mode) epiphany_normal_fp_rounding;
117
118 todo.quick_push (bb);
119 bitmap_set_bit (pushed, bb->index);
120 }
121 XVECEXP (XEXP (src, 0), 0, 0) = GEN_INT (selected_mode);
122 SET_SRC (XVECEXP (PATTERN (insn), 0, 1)) = copy_rtx (src);
123 SET_SRC (XVECEXP (PATTERN (insn), 0, 2)) = copy_rtx (src);
124 df_insn_rescan (insn);
125 }
126 while (todo.length ())
127 {
128 basic_block bb = todo.pop ();
129 int selected_reg, jilted_reg;
130 enum attr_fp_mode jilted_mode;
131 edge e;
132 edge_iterator ei;
133
134 bitmap_set_bit (pushed, bb->index);
135 bitmap_set_bit (pushed, bb->index);
136
137 if (epiphany_normal_fp_rounding == FP_MODE_ROUND_NEAREST)
138 {
139 selected_reg = FP_NEAREST_REGNUM;
140 jilted_reg = FP_TRUNCATE_REGNUM;
141 jilted_mode = FP_MODE_ROUND_TRUNC;
142 }
143 else
144 {
145 selected_reg = FP_TRUNCATE_REGNUM;
146 jilted_reg = FP_NEAREST_REGNUM;
147 jilted_mode = FP_MODE_ROUND_NEAREST;
148 }
149
150 FOR_EACH_EDGE (e, ei, bb->succs)
151 {
152 basic_block succ = e->dest;
153 rtx_insn *seq;
154
155 if (!REGNO_REG_SET_P (DF_LIVE_IN (succ), jilted_reg))
156 continue;
157 if (REGNO_REG_SET_P (DF_LIVE_IN (succ), selected_reg))
158 {
159 if (bitmap_bit_p (pushed, succ->index))
160 continue;
161 todo.quick_push (succ);
162 bitmap_set_bit (pushed, bb->index);
163 continue;
164 }
165 start_sequence ();
166 emit_set_fp_mode (EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN,
167 jilted_mode, FP_MODE_NONE, NULL);
168 seq = get_insns ();
169 end_sequence ();
170 need_commit = true;
171 insert_insn_on_edge (seq, e);
172 }
173 }
174 todo.release ();
175 sbitmap_free (pushed);
176 if (need_commit)
177 commit_edge_insertions ();
178 return 0;
179 }
180
181 } // anon namespace
182
183 rtl_opt_pass *
184 make_pass_resolve_sw_modes (gcc::context *ctxt)
185 {
186 return new pass_resolve_sw_modes (ctxt);
187 }