xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/config/epiphany/resolve-sw-modes.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
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