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