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