Branch data Line data Source code
1 : : /* Rich optional information on why an optimization wasn't possible.
2 : : Copyright (C) 2018-2024 Free Software Foundation, Inc.
3 : : Contributed by David Malcolm <dmalcolm@redhat.com>.
4 : :
5 : : This file is part of GCC.
6 : :
7 : : GCC is free software; you can redistribute it and/or modify it under
8 : : the terms of the GNU General Public License as published by the Free
9 : : Software Foundation; either version 3, or (at your option) any later
10 : : version.
11 : :
12 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 : : for more details.
16 : :
17 : : You should have received a copy of the GNU General Public License
18 : : along with GCC; see the file COPYING3. If not see
19 : : <http://www.gnu.org/licenses/>. */
20 : :
21 : : #include "config.h"
22 : : #include "system.h"
23 : : #include "coretypes.h"
24 : : #include "backend.h"
25 : : #include "tree.h"
26 : : #include "gimple.h"
27 : : #include "pretty-print.h"
28 : : #include "opt-problem.h"
29 : : #include "dump-context.h"
30 : : #include "tree-pass.h"
31 : : #include "selftest.h"
32 : :
33 : : /* opt_problem's ctor.
34 : :
35 : : Use FMT and AP to emit a message to the "immediate" dump destinations
36 : : as if via:
37 : : dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc, ...)
38 : :
39 : : The optinfo_item instances are not emitted yet. Instead, they
40 : : are retained internally so that the message can be replayed and
41 : : emitted when this problem is handled, higher up the call stack. */
42 : :
43 : 20012 : opt_problem::opt_problem (const dump_location_t &loc,
44 : : const char *fmt, va_list *ap)
45 : 20012 : : m_optinfo (loc, OPTINFO_KIND_FAILURE, current_pass)
46 : : {
47 : : /* We shouldn't be bothering to construct these objects if
48 : : dumping isn't enabled. */
49 : 20012 : gcc_assert (dump_enabled_p ());
50 : :
51 : : /* Update the singleton. */
52 : 33002 : delete s_the_problem;
53 : 20012 : s_the_problem = this;
54 : :
55 : : /* Print the location to the "immediate" dump destinations. */
56 : 20012 : dump_context &dc = dump_context::get ();
57 : 20012 : dc.dump_loc (MSG_MISSED_OPTIMIZATION, loc.get_user_location ());
58 : :
59 : : /* Print the formatted string to this opt_problem's optinfo, dumping
60 : : the items to the "immediate" dump destinations, and storing items
61 : : for later retrieval. */
62 : 20012 : {
63 : 20012 : dump_pretty_printer pp (&dump_context::get (), MSG_MISSED_OPTIMIZATION);
64 : :
65 : 20012 : text_info text (fmt, /* No i18n is performed. */
66 : 20012 : ap, errno);
67 : :
68 : : /* Phases 1 and 2, using pp_format. */
69 : 20012 : pp_format (&pp, &text);
70 : :
71 : : /* Phase 3: dump the items to the "immediate" dump destinations,
72 : : and storing them into m_optinfo for later retrieval. */
73 : 20012 : pp.emit_items (&m_optinfo);
74 : 20012 : }
75 : 20012 : }
76 : :
77 : : /* Emit this problem and delete it, clearing the current opt_problem. */
78 : :
79 : : void
80 : 5714 : opt_problem::emit_and_clear ()
81 : : {
82 : 5714 : gcc_assert (this == s_the_problem);
83 : :
84 : 5714 : m_optinfo.emit_for_opt_problem ();
85 : :
86 : 5714 : delete this;
87 : 5714 : s_the_problem = NULL;
88 : 5714 : }
89 : :
90 : : /* The singleton opt_problem *. */
91 : :
92 : : opt_problem *opt_problem::s_the_problem;
93 : :
94 : : #if CHECKING_P
95 : :
96 : : namespace selftest {
97 : :
98 : : static opt_result
99 : 6 : function_that_succeeds ()
100 : : {
101 : 6 : return opt_result::success ();
102 : : }
103 : :
104 : : /* Verify that opt_result::success works. */
105 : :
106 : : static void
107 : 3 : test_opt_result_success ()
108 : : {
109 : : /* Run all tests twice, with and then without dumping enabled. */
110 : 9 : for (int i = 0 ; i < 2; i++)
111 : : {
112 : 6 : bool with_dumping = (i == 0);
113 : :
114 : 6 : temp_dump_context tmp (with_dumping, with_dumping,
115 : 6 : MSG_ALL_KINDS | MSG_ALL_PRIORITIES);
116 : :
117 : 6 : if (with_dumping)
118 : 3 : gcc_assert (dump_enabled_p ());
119 : : else
120 : 3 : gcc_assert (!dump_enabled_p ());
121 : :
122 : 6 : opt_result res = function_that_succeeds ();
123 : :
124 : : /* Verify that "success" can be used as a "true" boolean. */
125 : 6 : ASSERT_TRUE (res);
126 : :
127 : : /* Verify the underlying opt_wrapper<bool>. */
128 : 6 : ASSERT_TRUE (res.get_result ());
129 : 6 : ASSERT_EQ (res.get_problem (), NULL);
130 : :
131 : : /* Nothing should have been dumped. */
132 : 6 : ASSERT_DUMPED_TEXT_EQ (tmp, "");
133 : 6 : optinfo *info = tmp.get_pending_optinfo ();
134 : 6 : ASSERT_EQ (info, NULL);
135 : 6 : }
136 : 3 : }
137 : :
138 : : /* Example of a function that fails, with a non-trivial
139 : : pre-canned error message. */
140 : :
141 : : static opt_result
142 : 336 : function_that_fails (const greturn *stmt)
143 : : {
144 : 336 : gcc_assert (stmt);
145 : 336 : gcc_assert (gimple_return_retval (stmt));
146 : :
147 : 336 : AUTO_DUMP_SCOPE ("function_that_fails", stmt);
148 : :
149 : 336 : return opt_result::failure_at (stmt,
150 : : "can't handle return type: %T for stmt: %G",
151 : 336 : TREE_TYPE (gimple_return_retval (stmt)),
152 : 336 : static_cast <const gimple *> (stmt));
153 : : }
154 : :
155 : : /* Example of a function that indirectly fails. */
156 : :
157 : : static opt_result
158 : 336 : function_that_indirectly_fails (const greturn *stmt)
159 : : {
160 : 336 : AUTO_DUMP_SCOPE ("function_that_indirectly_fails", stmt);
161 : :
162 : 336 : opt_result res = function_that_fails (stmt);
163 : 336 : if (!res)
164 : 336 : return res;
165 : 0 : return opt_result::success ();
166 : : }
167 : :
168 : : /* Verify that opt_result::failure_at works.
169 : : Simulate a failure handling a stmt at one location whilst considering
170 : : an optimization that's notionally at another location (as a microcosm
171 : : of e.g. a problematic statement within a loop that prevents loop
172 : : vectorization). */
173 : :
174 : : static void
175 : 72 : test_opt_result_failure_at (const line_table_case &case_)
176 : : {
177 : : /* Generate a location_t for testing. */
178 : 72 : line_table_test ltt (case_);
179 : 72 : const line_map_ordinary *ord_map
180 : 72 : = linemap_check_ordinary (linemap_add (line_table, LC_ENTER, false,
181 : : "test.c", 0));
182 : 72 : linemap_line_start (line_table, 5, 100);
183 : :
184 : : /* A test location: "test.c:5:10". */
185 : 72 : const location_t line_5 = linemap_position_for_column (line_table, 10);
186 : :
187 : : /* Another test location: "test.c:6:12". */
188 : 72 : const location_t line_6
189 : 72 : = linemap_position_for_line_and_column (line_table, ord_map, 6, 12);
190 : :
191 : 72 : if (line_6 > LINE_MAP_MAX_LOCATION_WITH_COLS)
192 : 30 : return;
193 : :
194 : : /* Generate statements using "line_5" and "line_6" for testing. */
195 : 42 : greturn *stmt_at_5 = gimple_build_return (integer_one_node);
196 : 42 : gimple_set_location (stmt_at_5, line_5);
197 : :
198 : 42 : greturn *stmt_at_6 = gimple_build_return (integer_zero_node);
199 : 42 : gimple_set_location (stmt_at_6, line_6);
200 : :
201 : : /* Run with and then without dumping enabled. */
202 : 126 : for (int i = 0; i < 2; i++)
203 : : {
204 : 84 : bool with_dumping = (i == 0);
205 : :
206 : : /* Run with all 4 combinations of
207 : : with and without MSG_PRIORITY_INTERNALS and
208 : : with and without MSG_PRIORITY_REEMITTED. */
209 : 420 : for (int j = 0; j < 4; j++)
210 : : {
211 : 336 : dump_flags_t filter = MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING;
212 : 336 : if (j / 2)
213 : 168 : filter |= MSG_PRIORITY_INTERNALS;
214 : 336 : if (j % 2)
215 : 168 : filter |= MSG_PRIORITY_REEMITTED;
216 : :
217 : 336 : temp_dump_context tmp (with_dumping, with_dumping, filter);
218 : :
219 : 336 : if (with_dumping)
220 : 168 : gcc_assert (dump_enabled_p ());
221 : : else
222 : 168 : gcc_assert (!dump_enabled_p ());
223 : :
224 : : /* Simulate attempting to optimize "stmt_at_6". */
225 : 336 : opt_result res = function_that_indirectly_fails (stmt_at_6);
226 : :
227 : : /* Verify that "failure" can be used as a "false" boolean. */
228 : 336 : ASSERT_FALSE (res);
229 : :
230 : : /* Verify the underlying opt_wrapper<bool>. */
231 : 336 : ASSERT_FALSE (res.get_result ());
232 : 336 : opt_problem *problem = res.get_problem ();
233 : :
234 : 336 : if (with_dumping)
235 : : {
236 : 168 : ASSERT_NE (problem, NULL);
237 : 168 : ASSERT_EQ (problem->get_dump_location ().get_location_t (),
238 : : line_6);
239 : : #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
240 : : /* Verify that the problem captures the implementation location
241 : : it was emitted from. */
242 : 168 : const dump_impl_location_t &impl_location
243 : 168 : = problem->get_dump_location ().get_impl_location ();
244 : 168 : ASSERT_STR_CONTAINS (impl_location.m_function,
245 : : "function_that_fails");
246 : : #endif
247 : :
248 : : /* Verify that the underlying dump items are retained in the
249 : : opt_problem. */
250 : 168 : const optinfo &info = problem->get_optinfo ();
251 : 168 : ASSERT_EQ (info.get_dump_location ().get_location_t (), line_6);
252 : 168 : ASSERT_EQ (info.num_items (), 4);
253 : 168 : ASSERT_IS_TEXT (info.get_item (0), "can't handle return type: ");
254 : 168 : ASSERT_IS_TREE (info.get_item (1), UNKNOWN_LOCATION, "int");
255 : 168 : ASSERT_IS_TEXT (info.get_item (2), " for stmt: ");
256 : 168 : ASSERT_IS_GIMPLE (info.get_item (3), line_6, "return 0;\n");
257 : :
258 : : /* ...but not in the dump_context's pending_optinfo. */
259 : 168 : ASSERT_EQ (tmp.get_pending_optinfo (), NULL);
260 : :
261 : : /* Simulate emitting a high-level summary message, followed
262 : : by the problem. */
263 : 168 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, stmt_at_5,
264 : : "can't optimize loop\n");
265 : 168 : problem->emit_and_clear ();
266 : 168 : ASSERT_EQ (res.get_problem (), NULL);
267 : :
268 : : /* Verify that the error message was dumped (when the failure
269 : : occurred). We can't use a switch here as not all of the
270 : : values are const expressions (using C++98). */
271 : 168 : dump_flags_t effective_filter
272 : 168 : = filter & (MSG_PRIORITY_INTERNALS | MSG_PRIORITY_REEMITTED);
273 : 168 : if (effective_filter
274 : 168 : == (MSG_PRIORITY_INTERNALS | MSG_PRIORITY_REEMITTED))
275 : : /* The -fopt-info-internals case. */
276 : 42 : ASSERT_DUMPED_TEXT_EQ
277 : : (tmp,
278 : : "test.c:6:12: note: === function_that_indirectly_fails"
279 : : " ===\n"
280 : : "test.c:6:12: note: === function_that_fails ===\n"
281 : : "test.c:6:12: missed: can't handle return type: int"
282 : : " for stmt: return 0;\n"
283 : : "test.c:5:10: missed: can't optimize loop\n"
284 : : "test.c:6:12: missed: can't handle return type: int"
285 : : " for stmt: return 0;\n");
286 : 126 : else if (effective_filter == MSG_PRIORITY_INTERNALS)
287 : : /* The default for dump files. */
288 : 42 : ASSERT_DUMPED_TEXT_EQ
289 : : (tmp,
290 : : "test.c:6:12: note: === function_that_indirectly_fails"
291 : : " ===\n"
292 : : "test.c:6:12: note: === function_that_fails ===\n"
293 : : "test.c:6:12: missed: can't handle return type: int"
294 : : " for stmt: return 0;\n"
295 : : "test.c:5:10: missed: can't optimize loop\n");
296 : 84 : else if (effective_filter == MSG_PRIORITY_REEMITTED)
297 : : /* The default when -fopt-info is enabled. */
298 : 42 : ASSERT_DUMPED_TEXT_EQ
299 : : (tmp,
300 : : "test.c:5:10: missed: can't optimize loop\n"
301 : : "test.c:6:12: missed: can't handle return type: int"
302 : : " for stmt: return 0;\n");
303 : : else
304 : : {
305 : 42 : gcc_assert (effective_filter == 0);
306 : 42 : ASSERT_DUMPED_TEXT_EQ
307 : : (tmp,
308 : : "test.c:5:10: missed: can't optimize loop\n");
309 : : }
310 : : }
311 : : else
312 : : {
313 : : /* If dumping was disabled, then no problem should have been
314 : : created, and nothing should have been dumped. */
315 : 168 : ASSERT_EQ (problem, NULL);
316 : 168 : ASSERT_DUMPED_TEXT_EQ (tmp, "");
317 : : }
318 : 336 : }
319 : : }
320 : 72 : }
321 : :
322 : : /* Run all of the selftests within this file. */
323 : :
324 : : void
325 : 3 : c_opt_problem_cc_tests ()
326 : : {
327 : 3 : test_opt_result_success ();
328 : 3 : for_each_line_table_case (test_opt_result_failure_at);
329 : 3 : }
330 : :
331 : : } // namespace selftest
332 : :
333 : : #endif /* CHECKING_P */
|