1af526226Smrg /* Mode switching cleanup pass for the EPIPHANY cpu.
2*dd083157Smrg    Copyright (C) 2000-2020 Free Software Foundation, Inc.
3af526226Smrg    Contributed by Embecosm on behalf of Adapteva, Inc.
4af526226Smrg 
5af526226Smrg This file is part of GCC.
6af526226Smrg 
7af526226Smrg GCC is free software; you can redistribute it and/or modify
8af526226Smrg it under the terms of the GNU General Public License as published by
9af526226Smrg the Free Software Foundation; either version 3, or (at your option)
10af526226Smrg any later version.
11af526226Smrg 
12af526226Smrg GCC is distributed in the hope that it will be useful,
13af526226Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
14af526226Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15af526226Smrg GNU General Public License for more details.
16af526226Smrg 
17af526226Smrg You should have received a copy of the GNU General Public License
18af526226Smrg along with GCC; see the file COPYING3.  If not see
19af526226Smrg <http://www.gnu.org/licenses/>.  */
20af526226Smrg 
213903d7f3Smrg #define IN_TARGET_CODE 1
223903d7f3Smrg 
23af526226Smrg #include "config.h"
24af526226Smrg #include "system.h"
25af526226Smrg #include "coretypes.h"
2663aace61Smrg #include "backend.h"
27af526226Smrg #include "rtl.h"
2863aace61Smrg #include "df.h"
296a5c9aabSmrg #include "memmodel.h"
3063aace61Smrg #include "tm_p.h"
31af526226Smrg #include "insn-config.h"
32af526226Smrg #include "emit-rtl.h"
33af526226Smrg #include "recog.h"
3463aace61Smrg #include "cfgrtl.h"
35af526226Smrg #include "insn-attr-common.h"
36af526226Smrg #include "tree-pass.h"
37af526226Smrg 
385ef59e75Smrg namespace {
395ef59e75Smrg 
405ef59e75Smrg const pass_data pass_data_resolve_sw_modes =
415ef59e75Smrg {
425ef59e75Smrg   RTL_PASS, /* type */
435ef59e75Smrg   "resolve_sw_modes", /* name */
445ef59e75Smrg   OPTGROUP_NONE, /* optinfo_flags */
455ef59e75Smrg   TV_MODE_SWITCH, /* tv_id */
465ef59e75Smrg   0, /* properties_required */
475ef59e75Smrg   0, /* properties_provided */
485ef59e75Smrg   0, /* properties_destroyed */
495ef59e75Smrg   0, /* todo_flags_start */
505ef59e75Smrg   TODO_df_finish, /* todo_flags_finish */
515ef59e75Smrg };
525ef59e75Smrg 
535ef59e75Smrg class pass_resolve_sw_modes : public rtl_opt_pass
545ef59e75Smrg {
555ef59e75Smrg public:
pass_resolve_sw_modes(gcc::context * ctxt)565ef59e75Smrg   pass_resolve_sw_modes(gcc::context *ctxt)
575ef59e75Smrg     : rtl_opt_pass(pass_data_resolve_sw_modes, ctxt)
585ef59e75Smrg   {}
595ef59e75Smrg 
605ef59e75Smrg   /* opt_pass methods: */
gate(function *)615ef59e75Smrg   virtual bool gate (function *) { return optimize; }
625ef59e75Smrg   virtual unsigned int execute (function *);
635ef59e75Smrg 
645ef59e75Smrg }; // class pass_resolve_sw_modes
655ef59e75Smrg 
66af526226Smrg /* Clean-up after mode switching:
67af526226Smrg    Check for mode setting insns that have FP_MODE_ROUND_UNKNOWN.
68af526226Smrg    If only one rounding mode is required, select that one.
69af526226Smrg    Else we have to choose one to use in this mode setting insn and
70af526226Smrg    insert new mode setting insns on the edges where the other mode
71af526226Smrg    becomes unambigous.  */
72af526226Smrg 
735ef59e75Smrg unsigned
execute(function * fun)745ef59e75Smrg pass_resolve_sw_modes::execute (function *fun)
75af526226Smrg {
76af526226Smrg   basic_block bb;
775ef59e75Smrg   rtx_insn *insn;
785ef59e75Smrg   rtx src;
79af526226Smrg   vec<basic_block> todo;
80af526226Smrg   sbitmap pushed;
81af526226Smrg   bool need_commit = false;
82af526226Smrg   bool finalize_fp_sets = (MACHINE_FUNCTION (cfun)->unknown_mode_sets == 0);
83af526226Smrg 
845ef59e75Smrg   todo.create (last_basic_block_for_fn (fun));
855ef59e75Smrg   pushed = sbitmap_alloc (last_basic_block_for_fn (fun));
86af526226Smrg   bitmap_clear (pushed);
87af526226Smrg   if (!finalize_fp_sets)
88af526226Smrg     {
89af526226Smrg       df_note_add_problem ();
90af526226Smrg       df_analyze ();
91af526226Smrg     }
925ef59e75Smrg   FOR_EACH_BB_FN (bb, fun)
93af526226Smrg     FOR_BB_INSNS (bb, insn)
94af526226Smrg       {
95af526226Smrg 	enum attr_fp_mode selected_mode;
96af526226Smrg 
97af526226Smrg 	if (!NONJUMP_INSN_P (insn)
98af526226Smrg 	    || recog_memoized (insn) != CODE_FOR_set_fp_mode)
99af526226Smrg 	  continue;
100af526226Smrg 	src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
101af526226Smrg 	if (finalize_fp_sets)
102af526226Smrg 	  {
103af526226Smrg 	    SET_SRC (XVECEXP (PATTERN (insn), 0, 2)) = copy_rtx (src);
104af526226Smrg 	    if (REG_P (src))
105af526226Smrg 	      df_insn_rescan (insn);
106af526226Smrg 	    continue;
107af526226Smrg 	  }
108af526226Smrg 	if (REG_P (src)
109af526226Smrg 	    || XINT (XVECEXP (XEXP (src, 0), 0, 0), 0) != FP_MODE_ROUND_UNKNOWN)
110af526226Smrg 	  continue;
111af526226Smrg 	if (find_regno_note (insn, REG_UNUSED, FP_TRUNCATE_REGNUM))
112af526226Smrg 	  selected_mode = FP_MODE_ROUND_NEAREST;
113af526226Smrg 	else if (find_regno_note (insn, REG_UNUSED, FP_NEAREST_REGNUM))
114af526226Smrg 	  selected_mode = FP_MODE_ROUND_TRUNC;
115af526226Smrg 	else
116af526226Smrg 	  {
117af526226Smrg 	    /* We could get more fancy in the selection of the mode by
118af526226Smrg 	       checking the total frequency of the affected edges.  */
119af526226Smrg 	    selected_mode = (enum attr_fp_mode) epiphany_normal_fp_rounding;
120af526226Smrg 
121af526226Smrg 	    todo.quick_push (bb);
122af526226Smrg 	    bitmap_set_bit (pushed, bb->index);
123af526226Smrg 	  }
124af526226Smrg 	XVECEXP (XEXP (src, 0), 0, 0) = GEN_INT (selected_mode);
125af526226Smrg 	SET_SRC (XVECEXP (PATTERN (insn), 0, 1)) = copy_rtx (src);
126af526226Smrg 	SET_SRC (XVECEXP (PATTERN (insn), 0, 2)) = copy_rtx (src);
127af526226Smrg 	df_insn_rescan (insn);
128af526226Smrg       }
129af526226Smrg   while (todo.length ())
130af526226Smrg     {
131af526226Smrg       basic_block bb = todo.pop ();
132af526226Smrg       int selected_reg, jilted_reg;
133af526226Smrg       enum attr_fp_mode jilted_mode;
134af526226Smrg       edge e;
135af526226Smrg       edge_iterator ei;
136af526226Smrg 
137af526226Smrg       bitmap_set_bit (pushed, bb->index);
138af526226Smrg       bitmap_set_bit (pushed, bb->index);
139af526226Smrg 
140af526226Smrg       if (epiphany_normal_fp_rounding == FP_MODE_ROUND_NEAREST)
141af526226Smrg 	{
142af526226Smrg 	  selected_reg = FP_NEAREST_REGNUM;
143af526226Smrg 	  jilted_reg = FP_TRUNCATE_REGNUM;
144af526226Smrg 	  jilted_mode = FP_MODE_ROUND_TRUNC;
145af526226Smrg 	}
146af526226Smrg       else
147af526226Smrg 	{
148af526226Smrg 	  selected_reg = FP_TRUNCATE_REGNUM;
149af526226Smrg 	  jilted_reg = FP_NEAREST_REGNUM;
150af526226Smrg 	  jilted_mode = FP_MODE_ROUND_NEAREST;
151af526226Smrg 	}
152af526226Smrg 
153af526226Smrg       FOR_EACH_EDGE (e, ei, bb->succs)
154af526226Smrg 	{
155af526226Smrg 	  basic_block succ = e->dest;
1565ef59e75Smrg 	  rtx_insn *seq;
157af526226Smrg 
158af526226Smrg 	  if (!REGNO_REG_SET_P (DF_LIVE_IN (succ), jilted_reg))
159af526226Smrg 	    continue;
160af526226Smrg 	  if (REGNO_REG_SET_P (DF_LIVE_IN (succ), selected_reg))
161af526226Smrg 	    {
162af526226Smrg 	      if (bitmap_bit_p (pushed, succ->index))
163af526226Smrg 		continue;
164af526226Smrg 	      todo.quick_push (succ);
165af526226Smrg 	      bitmap_set_bit (pushed, bb->index);
166af526226Smrg 	      continue;
167af526226Smrg 	    }
168af526226Smrg 	  start_sequence ();
169af526226Smrg 	  emit_set_fp_mode (EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN,
170*dd083157Smrg 			    jilted_mode, FP_MODE_NONE,
171*dd083157Smrg 			    reg_class_contents[NO_REGS]);
172af526226Smrg 	  seq = get_insns ();
173af526226Smrg 	  end_sequence ();
174af526226Smrg 	  need_commit = true;
175af526226Smrg 	  insert_insn_on_edge (seq, e);
176af526226Smrg 	}
177af526226Smrg     }
178af526226Smrg   todo.release ();
179af526226Smrg   sbitmap_free (pushed);
180af526226Smrg   if (need_commit)
181af526226Smrg     commit_edge_insertions ();
182af526226Smrg   return 0;
183af526226Smrg }
184af526226Smrg 
1855ef59e75Smrg } // anon namespace
1865ef59e75Smrg 
1875ef59e75Smrg rtl_opt_pass *
make_pass_resolve_sw_modes(gcc::context * ctxt)1885ef59e75Smrg make_pass_resolve_sw_modes (gcc::context *ctxt)
189af526226Smrg {
1905ef59e75Smrg   return new pass_resolve_sw_modes (ctxt);
191af526226Smrg }
192