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