1*b1e83836Smrg // RTL SSA utility functions for changing instructions -*- C++ -*-
2*b1e83836Smrg // Copyright (C) 2020-2022 Free Software Foundation, Inc.
3*b1e83836Smrg //
4*b1e83836Smrg // This file is part of GCC.
5*b1e83836Smrg //
6*b1e83836Smrg // GCC is free software; you can redistribute it and/or modify it under
7*b1e83836Smrg // the terms of the GNU General Public License as published by the Free
8*b1e83836Smrg // Software Foundation; either version 3, or (at your option) any later
9*b1e83836Smrg // version.
10*b1e83836Smrg //
11*b1e83836Smrg // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12*b1e83836Smrg // WARRANTY; without even the implied warranty of MERCHANTABILITY or
13*b1e83836Smrg // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14*b1e83836Smrg // for more details.
15*b1e83836Smrg //
16*b1e83836Smrg // You should have received a copy of the GNU General Public License
17*b1e83836Smrg // along with GCC; see the file COPYING3. If not see
18*b1e83836Smrg // <http://www.gnu.org/licenses/>.
19*b1e83836Smrg
20*b1e83836Smrg namespace rtl_ssa {
21*b1e83836Smrg
22*b1e83836Smrg // Return true if INSN is one of the instructions being changed by CHANGES.
23*b1e83836Smrg inline bool
insn_is_changing(array_slice<insn_change * const> changes,const insn_info * insn)24*b1e83836Smrg insn_is_changing (array_slice<insn_change *const> changes,
25*b1e83836Smrg const insn_info *insn)
26*b1e83836Smrg {
27*b1e83836Smrg for (const insn_change *change : changes)
28*b1e83836Smrg if (change->insn () == insn)
29*b1e83836Smrg return true;
30*b1e83836Smrg return false;
31*b1e83836Smrg }
32*b1e83836Smrg
33*b1e83836Smrg // Return a closure of insn_is_changing, for use as a predicate.
34*b1e83836Smrg // This could be done using local lambdas instead, but the predicate is
35*b1e83836Smrg // used often enough that having a class should be more convenient and allow
36*b1e83836Smrg // reuse of template instantiations.
37*b1e83836Smrg //
38*b1e83836Smrg // We don't use std::bind because it would involve an indirect function call,
39*b1e83836Smrg // whereas this function is used in relatively performance-critical code.
40*b1e83836Smrg inline insn_is_changing_closure
insn_is_changing(array_slice<insn_change * const> changes)41*b1e83836Smrg insn_is_changing (array_slice<insn_change *const> changes)
42*b1e83836Smrg {
43*b1e83836Smrg return insn_is_changing_closure (changes);
44*b1e83836Smrg }
45*b1e83836Smrg
46*b1e83836Smrg // Restrict CHANGE.move_range so that the changed instruction can perform
47*b1e83836Smrg // all its definitions and uses. Assume that if:
48*b1e83836Smrg //
49*b1e83836Smrg // - CHANGE contains an access A1 of resource R;
50*b1e83836Smrg // - an instruction I2 contains another access A2 to R; and
51*b1e83836Smrg // - IGNORE (I2) is true
52*b1e83836Smrg //
53*b1e83836Smrg // then either:
54*b1e83836Smrg //
55*b1e83836Smrg // - A2 will be removed; or
56*b1e83836Smrg // - something will ensure that A1 and A2 maintain their current order,
57*b1e83836Smrg // without this having to be enforced by CHANGE's move range.
58*b1e83836Smrg //
59*b1e83836Smrg // IGNORE should return true for CHANGE.insn ().
60*b1e83836Smrg //
61*b1e83836Smrg // Return true on success, otherwise leave CHANGE.move_range in an invalid
62*b1e83836Smrg // state.
63*b1e83836Smrg //
64*b1e83836Smrg // This function only works correctly for instructions that remain within
65*b1e83836Smrg // the same extended basic block.
66*b1e83836Smrg template<typename IgnorePredicate>
67*b1e83836Smrg bool
restrict_movement_ignoring(insn_change & change,IgnorePredicate ignore)68*b1e83836Smrg restrict_movement_ignoring (insn_change &change, IgnorePredicate ignore)
69*b1e83836Smrg {
70*b1e83836Smrg // Uses generally lead to failure quicker, so test those first.
71*b1e83836Smrg return (restrict_movement_for_uses_ignoring (change.move_range,
72*b1e83836Smrg change.new_uses, ignore)
73*b1e83836Smrg && restrict_movement_for_defs_ignoring (change.move_range,
74*b1e83836Smrg change.new_defs, ignore)
75*b1e83836Smrg && canonicalize_move_range (change.move_range, change.insn ()));
76*b1e83836Smrg }
77*b1e83836Smrg
78*b1e83836Smrg // Like restrict_movement_ignoring, but ignore only the instruction
79*b1e83836Smrg // that is being changed.
80*b1e83836Smrg inline bool
restrict_movement(insn_change & change)81*b1e83836Smrg restrict_movement (insn_change &change)
82*b1e83836Smrg {
83*b1e83836Smrg return restrict_movement_ignoring (change, insn_is (change.insn ()));
84*b1e83836Smrg }
85*b1e83836Smrg
86*b1e83836Smrg using add_regno_clobber_fn = std::function<bool (insn_change &,
87*b1e83836Smrg unsigned int)>;
88*b1e83836Smrg bool recog_internal (insn_change &, add_regno_clobber_fn);
89*b1e83836Smrg
90*b1e83836Smrg // Try to recognize the new instruction pattern for CHANGE, potentially
91*b1e83836Smrg // tweaking the pattern or adding extra clobbers in order to make it match.
92*b1e83836Smrg //
93*b1e83836Smrg // When adding an extra clobber for register R, restrict CHANGE.move_range
94*b1e83836Smrg // to a range of instructions for which R is not live. When determining
95*b1e83836Smrg // whether R is live, ignore accesses made by an instruction I if
96*b1e83836Smrg // IGNORE (I) is true. The caller then assumes the responsibility
97*b1e83836Smrg // of ensuring that CHANGE and I are placed in a valid order.
98*b1e83836Smrg //
99*b1e83836Smrg // IGNORE should return true for CHANGE.insn ().
100*b1e83836Smrg //
101*b1e83836Smrg // Return true on success. Leave CHANGE unmodified on failure.
102*b1e83836Smrg template<typename IgnorePredicate>
103*b1e83836Smrg inline bool
recog_ignoring(obstack_watermark & watermark,insn_change & change,IgnorePredicate ignore)104*b1e83836Smrg recog_ignoring (obstack_watermark &watermark, insn_change &change,
105*b1e83836Smrg IgnorePredicate ignore)
106*b1e83836Smrg {
107*b1e83836Smrg auto add_regno_clobber = [&](insn_change &change, unsigned int regno)
108*b1e83836Smrg {
109*b1e83836Smrg return crtl->ssa->add_regno_clobber (watermark, change, regno, ignore);
110*b1e83836Smrg };
111*b1e83836Smrg return recog_internal (change, add_regno_clobber);
112*b1e83836Smrg }
113*b1e83836Smrg
114*b1e83836Smrg // As for recog_ignoring, but ignore only the instruction that is being
115*b1e83836Smrg // changed.
116*b1e83836Smrg inline bool
recog(obstack_watermark & watermark,insn_change & change)117*b1e83836Smrg recog (obstack_watermark &watermark, insn_change &change)
118*b1e83836Smrg {
119*b1e83836Smrg return recog_ignoring (watermark, change, insn_is (change.insn ()));
120*b1e83836Smrg }
121*b1e83836Smrg
122*b1e83836Smrg // Check whether insn costs indicate that the net effect of the changes
123*b1e83836Smrg // in CHANGES is worthwhile. Require a strict improvement if STRICT_P,
124*b1e83836Smrg // otherwise allow the new instructions to be the same cost as the old
125*b1e83836Smrg // instructions.
126*b1e83836Smrg bool changes_are_worthwhile (array_slice<insn_change *const> changes,
127*b1e83836Smrg bool strict_p = false);
128*b1e83836Smrg
129*b1e83836Smrg // Like changes_are_worthwhile, but for a single change.
130*b1e83836Smrg inline bool
131*b1e83836Smrg change_is_worthwhile (insn_change &change, bool strict_p = false)
132*b1e83836Smrg {
133*b1e83836Smrg insn_change *changes[] = { &change };
134*b1e83836Smrg return changes_are_worthwhile (changes, strict_p);
135*b1e83836Smrg }
136*b1e83836Smrg
137*b1e83836Smrg }
138