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