xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/config/epiphany/resolve-sw-modes.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
11debfc3dSmrg /* Mode switching cleanup pass for the EPIPHANY cpu.
2*8feb0f0bSmrg    Copyright (C) 2000-2020 Free Software Foundation, Inc.
31debfc3dSmrg    Contributed by Embecosm on behalf of Adapteva, Inc.
41debfc3dSmrg 
51debfc3dSmrg This file is part of GCC.
61debfc3dSmrg 
71debfc3dSmrg GCC is free software; you can redistribute it and/or modify
81debfc3dSmrg it under the terms of the GNU General Public License as published by
91debfc3dSmrg the Free Software Foundation; either version 3, or (at your option)
101debfc3dSmrg any later version.
111debfc3dSmrg 
121debfc3dSmrg GCC is distributed in the hope that it will be useful,
131debfc3dSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
141debfc3dSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
151debfc3dSmrg GNU General Public License for more details.
161debfc3dSmrg 
171debfc3dSmrg You should have received a copy of the GNU General Public License
181debfc3dSmrg along with GCC; see the file COPYING3.  If not see
191debfc3dSmrg <http://www.gnu.org/licenses/>.  */
201debfc3dSmrg 
21a2dc1f3fSmrg #define IN_TARGET_CODE 1
22a2dc1f3fSmrg 
231debfc3dSmrg #include "config.h"
241debfc3dSmrg #include "system.h"
251debfc3dSmrg #include "coretypes.h"
261debfc3dSmrg #include "backend.h"
271debfc3dSmrg #include "rtl.h"
281debfc3dSmrg #include "df.h"
291debfc3dSmrg #include "memmodel.h"
301debfc3dSmrg #include "tm_p.h"
311debfc3dSmrg #include "insn-config.h"
321debfc3dSmrg #include "emit-rtl.h"
331debfc3dSmrg #include "recog.h"
341debfc3dSmrg #include "cfgrtl.h"
351debfc3dSmrg #include "insn-attr-common.h"
361debfc3dSmrg #include "tree-pass.h"
371debfc3dSmrg 
381debfc3dSmrg namespace {
391debfc3dSmrg 
401debfc3dSmrg const pass_data pass_data_resolve_sw_modes =
411debfc3dSmrg {
421debfc3dSmrg   RTL_PASS, /* type */
431debfc3dSmrg   "resolve_sw_modes", /* name */
441debfc3dSmrg   OPTGROUP_NONE, /* optinfo_flags */
451debfc3dSmrg   TV_MODE_SWITCH, /* tv_id */
461debfc3dSmrg   0, /* properties_required */
471debfc3dSmrg   0, /* properties_provided */
481debfc3dSmrg   0, /* properties_destroyed */
491debfc3dSmrg   0, /* todo_flags_start */
501debfc3dSmrg   TODO_df_finish, /* todo_flags_finish */
511debfc3dSmrg };
521debfc3dSmrg 
531debfc3dSmrg class pass_resolve_sw_modes : public rtl_opt_pass
541debfc3dSmrg {
551debfc3dSmrg public:
pass_resolve_sw_modes(gcc::context * ctxt)561debfc3dSmrg   pass_resolve_sw_modes(gcc::context *ctxt)
571debfc3dSmrg     : rtl_opt_pass(pass_data_resolve_sw_modes, ctxt)
581debfc3dSmrg   {}
591debfc3dSmrg 
601debfc3dSmrg   /* opt_pass methods: */
gate(function *)611debfc3dSmrg   virtual bool gate (function *) { return optimize; }
621debfc3dSmrg   virtual unsigned int execute (function *);
631debfc3dSmrg 
641debfc3dSmrg }; // class pass_resolve_sw_modes
651debfc3dSmrg 
661debfc3dSmrg /* Clean-up after mode switching:
671debfc3dSmrg    Check for mode setting insns that have FP_MODE_ROUND_UNKNOWN.
681debfc3dSmrg    If only one rounding mode is required, select that one.
691debfc3dSmrg    Else we have to choose one to use in this mode setting insn and
701debfc3dSmrg    insert new mode setting insns on the edges where the other mode
711debfc3dSmrg    becomes unambigous.  */
721debfc3dSmrg 
731debfc3dSmrg unsigned
execute(function * fun)741debfc3dSmrg pass_resolve_sw_modes::execute (function *fun)
751debfc3dSmrg {
761debfc3dSmrg   basic_block bb;
771debfc3dSmrg   rtx_insn *insn;
781debfc3dSmrg   rtx src;
791debfc3dSmrg   vec<basic_block> todo;
801debfc3dSmrg   sbitmap pushed;
811debfc3dSmrg   bool need_commit = false;
821debfc3dSmrg   bool finalize_fp_sets = (MACHINE_FUNCTION (cfun)->unknown_mode_sets == 0);
831debfc3dSmrg 
841debfc3dSmrg   todo.create (last_basic_block_for_fn (fun));
851debfc3dSmrg   pushed = sbitmap_alloc (last_basic_block_for_fn (fun));
861debfc3dSmrg   bitmap_clear (pushed);
871debfc3dSmrg   if (!finalize_fp_sets)
881debfc3dSmrg     {
891debfc3dSmrg       df_note_add_problem ();
901debfc3dSmrg       df_analyze ();
911debfc3dSmrg     }
921debfc3dSmrg   FOR_EACH_BB_FN (bb, fun)
931debfc3dSmrg     FOR_BB_INSNS (bb, insn)
941debfc3dSmrg       {
951debfc3dSmrg 	enum attr_fp_mode selected_mode;
961debfc3dSmrg 
971debfc3dSmrg 	if (!NONJUMP_INSN_P (insn)
981debfc3dSmrg 	    || recog_memoized (insn) != CODE_FOR_set_fp_mode)
991debfc3dSmrg 	  continue;
1001debfc3dSmrg 	src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
1011debfc3dSmrg 	if (finalize_fp_sets)
1021debfc3dSmrg 	  {
1031debfc3dSmrg 	    SET_SRC (XVECEXP (PATTERN (insn), 0, 2)) = copy_rtx (src);
1041debfc3dSmrg 	    if (REG_P (src))
1051debfc3dSmrg 	      df_insn_rescan (insn);
1061debfc3dSmrg 	    continue;
1071debfc3dSmrg 	  }
1081debfc3dSmrg 	if (REG_P (src)
1091debfc3dSmrg 	    || XINT (XVECEXP (XEXP (src, 0), 0, 0), 0) != FP_MODE_ROUND_UNKNOWN)
1101debfc3dSmrg 	  continue;
1111debfc3dSmrg 	if (find_regno_note (insn, REG_UNUSED, FP_TRUNCATE_REGNUM))
1121debfc3dSmrg 	  selected_mode = FP_MODE_ROUND_NEAREST;
1131debfc3dSmrg 	else if (find_regno_note (insn, REG_UNUSED, FP_NEAREST_REGNUM))
1141debfc3dSmrg 	  selected_mode = FP_MODE_ROUND_TRUNC;
1151debfc3dSmrg 	else
1161debfc3dSmrg 	  {
1171debfc3dSmrg 	    /* We could get more fancy in the selection of the mode by
1181debfc3dSmrg 	       checking the total frequency of the affected edges.  */
1191debfc3dSmrg 	    selected_mode = (enum attr_fp_mode) epiphany_normal_fp_rounding;
1201debfc3dSmrg 
1211debfc3dSmrg 	    todo.quick_push (bb);
1221debfc3dSmrg 	    bitmap_set_bit (pushed, bb->index);
1231debfc3dSmrg 	  }
1241debfc3dSmrg 	XVECEXP (XEXP (src, 0), 0, 0) = GEN_INT (selected_mode);
1251debfc3dSmrg 	SET_SRC (XVECEXP (PATTERN (insn), 0, 1)) = copy_rtx (src);
1261debfc3dSmrg 	SET_SRC (XVECEXP (PATTERN (insn), 0, 2)) = copy_rtx (src);
1271debfc3dSmrg 	df_insn_rescan (insn);
1281debfc3dSmrg       }
1291debfc3dSmrg   while (todo.length ())
1301debfc3dSmrg     {
1311debfc3dSmrg       basic_block bb = todo.pop ();
1321debfc3dSmrg       int selected_reg, jilted_reg;
1331debfc3dSmrg       enum attr_fp_mode jilted_mode;
1341debfc3dSmrg       edge e;
1351debfc3dSmrg       edge_iterator ei;
1361debfc3dSmrg 
1371debfc3dSmrg       bitmap_set_bit (pushed, bb->index);
1381debfc3dSmrg       bitmap_set_bit (pushed, bb->index);
1391debfc3dSmrg 
1401debfc3dSmrg       if (epiphany_normal_fp_rounding == FP_MODE_ROUND_NEAREST)
1411debfc3dSmrg 	{
1421debfc3dSmrg 	  selected_reg = FP_NEAREST_REGNUM;
1431debfc3dSmrg 	  jilted_reg = FP_TRUNCATE_REGNUM;
1441debfc3dSmrg 	  jilted_mode = FP_MODE_ROUND_TRUNC;
1451debfc3dSmrg 	}
1461debfc3dSmrg       else
1471debfc3dSmrg 	{
1481debfc3dSmrg 	  selected_reg = FP_TRUNCATE_REGNUM;
1491debfc3dSmrg 	  jilted_reg = FP_NEAREST_REGNUM;
1501debfc3dSmrg 	  jilted_mode = FP_MODE_ROUND_NEAREST;
1511debfc3dSmrg 	}
1521debfc3dSmrg 
1531debfc3dSmrg       FOR_EACH_EDGE (e, ei, bb->succs)
1541debfc3dSmrg 	{
1551debfc3dSmrg 	  basic_block succ = e->dest;
1561debfc3dSmrg 	  rtx_insn *seq;
1571debfc3dSmrg 
1581debfc3dSmrg 	  if (!REGNO_REG_SET_P (DF_LIVE_IN (succ), jilted_reg))
1591debfc3dSmrg 	    continue;
1601debfc3dSmrg 	  if (REGNO_REG_SET_P (DF_LIVE_IN (succ), selected_reg))
1611debfc3dSmrg 	    {
1621debfc3dSmrg 	      if (bitmap_bit_p (pushed, succ->index))
1631debfc3dSmrg 		continue;
1641debfc3dSmrg 	      todo.quick_push (succ);
1651debfc3dSmrg 	      bitmap_set_bit (pushed, bb->index);
1661debfc3dSmrg 	      continue;
1671debfc3dSmrg 	    }
1681debfc3dSmrg 	  start_sequence ();
1691debfc3dSmrg 	  emit_set_fp_mode (EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN,
170*8feb0f0bSmrg 			    jilted_mode, FP_MODE_NONE,
171*8feb0f0bSmrg 			    reg_class_contents[NO_REGS]);
1721debfc3dSmrg 	  seq = get_insns ();
1731debfc3dSmrg 	  end_sequence ();
1741debfc3dSmrg 	  need_commit = true;
1751debfc3dSmrg 	  insert_insn_on_edge (seq, e);
1761debfc3dSmrg 	}
1771debfc3dSmrg     }
1781debfc3dSmrg   todo.release ();
1791debfc3dSmrg   sbitmap_free (pushed);
1801debfc3dSmrg   if (need_commit)
1811debfc3dSmrg     commit_edge_insertions ();
1821debfc3dSmrg   return 0;
1831debfc3dSmrg }
1841debfc3dSmrg 
1851debfc3dSmrg } // anon namespace
1861debfc3dSmrg 
1871debfc3dSmrg rtl_opt_pass *
make_pass_resolve_sw_modes(gcc::context * ctxt)1881debfc3dSmrg make_pass_resolve_sw_modes (gcc::context *ctxt)
1891debfc3dSmrg {
1901debfc3dSmrg   return new pass_resolve_sw_modes (ctxt);
1911debfc3dSmrg }
192