Home | History | Annotate | Line # | Download | only in gcc
      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