xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/config/epiphany/resolve-sw-modes.c (revision 6cd39ddb8550f6fa1bff3fed32053d7f19fd0453)
1 /* Mode switching cleanup pass for the EPIPHANY cpu.
2    Copyright (C) 2000-2013 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 "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"
40 
41 /* Clean-up after mode switching:
42    Check for mode setting insns that have FP_MODE_ROUND_UNKNOWN.
43    If only one rounding mode is required, select that one.
44    Else we have to choose one to use in this mode setting insn and
45    insert new mode setting insns on the edges where the other mode
46    becomes unambigous.  */
47 
48 static bool
49 gate_resolve_sw_modes (void)
50 {
51   return optimize;
52 }
53 
54 static unsigned
55 resolve_sw_modes (void)
56 {
57   basic_block bb;
58   rtx insn, src;
59   vec<basic_block> todo;
60   sbitmap pushed;
61   bool need_commit = false;
62   bool finalize_fp_sets = (MACHINE_FUNCTION (cfun)->unknown_mode_sets == 0);
63 
64   todo.create (last_basic_block);
65   pushed = sbitmap_alloc (last_basic_block);
66   bitmap_clear (pushed);
67   if (!finalize_fp_sets)
68     {
69       df_note_add_problem ();
70       df_analyze ();
71     }
72   FOR_EACH_BB (bb)
73     FOR_BB_INSNS (bb, insn)
74       {
75 	enum attr_fp_mode selected_mode;
76 
77 	if (!NONJUMP_INSN_P (insn)
78 	    || recog_memoized (insn) != CODE_FOR_set_fp_mode)
79 	  continue;
80 	src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
81 	if (finalize_fp_sets)
82 	  {
83 	    SET_SRC (XVECEXP (PATTERN (insn), 0, 2)) = copy_rtx (src);
84 	    if (REG_P (src))
85 	      df_insn_rescan (insn);
86 	    continue;
87 	  }
88 	if (REG_P (src)
89 	    || XINT (XVECEXP (XEXP (src, 0), 0, 0), 0) != FP_MODE_ROUND_UNKNOWN)
90 	  continue;
91 	if (find_regno_note (insn, REG_UNUSED, FP_TRUNCATE_REGNUM))
92 	  selected_mode = FP_MODE_ROUND_NEAREST;
93 	else if (find_regno_note (insn, REG_UNUSED, FP_NEAREST_REGNUM))
94 	  selected_mode = FP_MODE_ROUND_TRUNC;
95 	else
96 	  {
97 	    /* We could get more fancy in the selection of the mode by
98 	       checking the total frequency of the affected edges.  */
99 	    selected_mode = (enum attr_fp_mode) epiphany_normal_fp_rounding;
100 
101 	    todo.quick_push (bb);
102 	    bitmap_set_bit (pushed, bb->index);
103 	  }
104 	XVECEXP (XEXP (src, 0), 0, 0) = GEN_INT (selected_mode);
105 	SET_SRC (XVECEXP (PATTERN (insn), 0, 1)) = copy_rtx (src);
106 	SET_SRC (XVECEXP (PATTERN (insn), 0, 2)) = copy_rtx (src);
107 	df_insn_rescan (insn);
108       }
109   while (todo.length ())
110     {
111       basic_block bb = todo.pop ();
112       int selected_reg, jilted_reg;
113       enum attr_fp_mode jilted_mode;
114       edge e;
115       edge_iterator ei;
116 
117       bitmap_set_bit (pushed, bb->index);
118       bitmap_set_bit (pushed, bb->index);
119 
120       if (epiphany_normal_fp_rounding == FP_MODE_ROUND_NEAREST)
121 	{
122 	  selected_reg = FP_NEAREST_REGNUM;
123 	  jilted_reg = FP_TRUNCATE_REGNUM;
124 	  jilted_mode = FP_MODE_ROUND_TRUNC;
125 	}
126       else
127 	{
128 	  selected_reg = FP_TRUNCATE_REGNUM;
129 	  jilted_reg = FP_NEAREST_REGNUM;
130 	  jilted_mode = FP_MODE_ROUND_NEAREST;
131 	}
132 
133       FOR_EACH_EDGE (e, ei, bb->succs)
134 	{
135 	  basic_block succ = e->dest;
136 	  rtx seq;
137 
138 	  if (!REGNO_REG_SET_P (DF_LIVE_IN (succ), jilted_reg))
139 	    continue;
140 	  if (REGNO_REG_SET_P (DF_LIVE_IN (succ), selected_reg))
141 	    {
142 	      if (bitmap_bit_p (pushed, succ->index))
143 		continue;
144 	      todo.quick_push (succ);
145 	      bitmap_set_bit (pushed, bb->index);
146 	      continue;
147 	    }
148 	  start_sequence ();
149 	  emit_set_fp_mode (EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN,
150 			    jilted_mode, NULL);
151 	  seq = get_insns ();
152 	  end_sequence ();
153 	  need_commit = true;
154 	  insert_insn_on_edge (seq, e);
155 	}
156     }
157   todo.release ();
158   sbitmap_free (pushed);
159   if (need_commit)
160     commit_edge_insertions ();
161   return 0;
162 }
163 
164 struct rtl_opt_pass pass_resolve_sw_modes =
165 {
166  {
167   RTL_PASS,
168   "resolve_sw_modes",			/* name */
169   OPTGROUP_NONE,			/* optinfo_flags */
170   gate_resolve_sw_modes,		/* gate */
171   resolve_sw_modes,			/* execute */
172   NULL,					/* sub */
173   NULL,					/* next */
174   0,					/* static_pass_number */
175   TV_MODE_SWITCH,			/* tv_id */
176   0,					/* properties_required */
177   0,					/* properties_provided */
178   0,					/* properties_destroyed */
179   0,					/* todo_flags_start */
180   TODO_df_finish | TODO_verify_rtl_sharing |
181   0					/* todo_flags_finish */
182  }
183 };
184