LCOV - code coverage report
Current view: top level - gcc - opt-problem.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 99.2 % 120 119
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 8 8
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Rich optional information on why an optimization wasn't possible.
       2              :    Copyright (C) 2018-2026 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        26697 : opt_problem::opt_problem (const dump_location_t &loc,
      44              :                           const char *fmt, va_list *ap)
      45        26697 : : 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        26697 :   gcc_assert (dump_enabled_p ());
      50              : 
      51              :   /* Update the singleton.  */
      52        46437 :   delete s_the_problem;
      53        26697 :   s_the_problem = this;
      54              : 
      55              :   /* Print the location to the "immediate" dump destinations.  */
      56        26697 :   dump_context &dc = dump_context::get ();
      57        26697 :   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        26697 :   {
      63        26697 :     dump_pretty_printer pp (&dump_context::get (), MSG_MISSED_OPTIMIZATION);
      64              : 
      65        26697 :     text_info text (fmt, /* No i18n is performed.  */
      66        26697 :                     ap, errno);
      67              : 
      68              :     /* Phases 1 and 2, using pp_format.  */
      69        26697 :     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        26697 :     pp.set_optinfo (&m_optinfo);
      74        26697 :     pp_output_formatted_text (&pp, nullptr);
      75        26697 :   }
      76        26697 : }
      77              : 
      78              : /* Emit this problem and delete it, clearing the current opt_problem.  */
      79              : 
      80              : void
      81         5932 : opt_problem::emit_and_clear ()
      82              : {
      83         5932 :   gcc_assert (this == s_the_problem);
      84              : 
      85         5932 :   m_optinfo.emit_for_opt_problem ();
      86              : 
      87         5932 :   delete this;
      88         5932 :   s_the_problem = NULL;
      89         5932 : }
      90              : 
      91              : /* The singleton opt_problem *.  */
      92              : 
      93              : opt_problem *opt_problem::s_the_problem;
      94              : 
      95              : #if CHECKING_P
      96              : 
      97              : namespace selftest {
      98              : 
      99              : static opt_result
     100            6 : function_that_succeeds ()
     101              : {
     102            6 :   return opt_result::success ();
     103              : }
     104              : 
     105              : /* Verify that opt_result::success works.  */
     106              : 
     107              : static void
     108            3 : test_opt_result_success ()
     109              : {
     110              :   /* Run all tests twice, with and then without dumping enabled.  */
     111            9 :   for (int i = 0 ; i < 2; i++)
     112              :     {
     113            6 :       bool with_dumping = (i == 0);
     114              : 
     115            6 :       temp_dump_context tmp (with_dumping, with_dumping,
     116            6 :                              MSG_ALL_KINDS | MSG_ALL_PRIORITIES);
     117              : 
     118            6 :       if (with_dumping)
     119            3 :         gcc_assert (dump_enabled_p ());
     120              :       else
     121            3 :         gcc_assert (!dump_enabled_p ());
     122              : 
     123            6 :       opt_result res = function_that_succeeds ();
     124              : 
     125              :       /* Verify that "success" can be used as a "true" boolean.  */
     126            6 :       ASSERT_TRUE (res);
     127              : 
     128              :       /* Verify the underlying opt_wrapper<bool>.  */
     129            6 :       ASSERT_TRUE (res.get_result ());
     130            6 :       ASSERT_EQ (res.get_problem (), NULL);
     131              : 
     132              :       /* Nothing should have been dumped.  */
     133            6 :       ASSERT_DUMPED_TEXT_EQ (tmp, "");
     134            6 :       optinfo *info = tmp.get_pending_optinfo ();
     135            6 :       ASSERT_EQ (info, NULL);
     136            6 :     }
     137            3 : }
     138              : 
     139              : /* Example of a function that fails, with a non-trivial
     140              :    pre-canned error message.  */
     141              : 
     142              : static opt_result
     143          336 : function_that_fails (const greturn *stmt)
     144              : {
     145          336 :   gcc_assert (stmt);
     146          336 :   gcc_assert (gimple_return_retval (stmt));
     147              : 
     148          336 :   AUTO_DUMP_SCOPE ("function_that_fails", stmt);
     149              : 
     150          336 :   return opt_result::failure_at (stmt,
     151              :                                  "can't handle return type: %T for stmt: %G",
     152          336 :                                  TREE_TYPE (gimple_return_retval (stmt)),
     153          336 :                                  static_cast <const gimple *> (stmt));
     154              : }
     155              : 
     156              : /* Example of a function that indirectly fails.  */
     157              : 
     158              : static opt_result
     159          336 : function_that_indirectly_fails (const greturn *stmt)
     160              : {
     161          336 :   AUTO_DUMP_SCOPE ("function_that_indirectly_fails", stmt);
     162              : 
     163          336 :   opt_result res = function_that_fails (stmt);
     164          336 :   if (!res)
     165          336 :     return res;
     166            0 :   return opt_result::success ();
     167              : }
     168              : 
     169              : /* Verify that opt_result::failure_at works.
     170              :    Simulate a failure handling a stmt at one location whilst considering
     171              :    an optimization that's notionally at another location (as a microcosm
     172              :    of e.g. a problematic statement within a loop that prevents loop
     173              :    vectorization).  */
     174              : 
     175              : static void
     176           72 : test_opt_result_failure_at (const line_table_case &case_)
     177              : {
     178              :   /* Generate a location_t for testing.  */
     179           72 :   line_table_test ltt (case_);
     180           72 :   const line_map_ordinary *ord_map
     181           72 :     = linemap_check_ordinary (linemap_add (line_table, LC_ENTER, false,
     182              :                                            "test.c", 0));
     183           72 :   linemap_line_start (line_table, 5, 100);
     184              : 
     185              :   /* A test location: "test.c:5:10".  */
     186           72 :   const location_t line_5 = linemap_position_for_column (line_table, 10);
     187              : 
     188              :   /* Another test location: "test.c:6:12".  */
     189           72 :   const location_t line_6
     190           72 :     = linemap_position_for_line_and_column (line_table, ord_map, 6, 12);
     191              : 
     192           72 :   if (line_6 > LINE_MAP_MAX_LOCATION_WITH_COLS)
     193           30 :     return;
     194              : 
     195              :   /* Generate statements using "line_5" and "line_6" for testing.  */
     196           42 :   greturn *stmt_at_5 = gimple_build_return (integer_one_node);
     197           42 :   gimple_set_location (stmt_at_5, line_5);
     198              : 
     199           42 :   greturn *stmt_at_6 = gimple_build_return (integer_zero_node);
     200           42 :   gimple_set_location (stmt_at_6, line_6);
     201              : 
     202              :   /* Run with and then without dumping enabled.  */
     203          126 :   for (int i = 0; i < 2; i++)
     204              :     {
     205           84 :       bool with_dumping = (i == 0);
     206              : 
     207              :       /* Run with all 4 combinations of
     208              :          with and without MSG_PRIORITY_INTERNALS and
     209              :          with and without MSG_PRIORITY_REEMITTED.  */
     210          420 :       for (int j = 0; j < 4; j++)
     211              :         {
     212          336 :           dump_flags_t filter = MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING;
     213          336 :           if (j / 2)
     214          168 :             filter |= MSG_PRIORITY_INTERNALS;
     215          336 :           if (j % 2)
     216          168 :             filter |= MSG_PRIORITY_REEMITTED;
     217              : 
     218          336 :           temp_dump_context tmp (with_dumping, with_dumping, filter);
     219              : 
     220          336 :           if (with_dumping)
     221          168 :             gcc_assert (dump_enabled_p ());
     222              :           else
     223          168 :             gcc_assert (!dump_enabled_p ());
     224              : 
     225              :           /* Simulate attempting to optimize "stmt_at_6".  */
     226          336 :           opt_result res = function_that_indirectly_fails (stmt_at_6);
     227              : 
     228              :           /* Verify that "failure" can be used as a "false" boolean.  */
     229          336 :           ASSERT_FALSE (res);
     230              : 
     231              :           /* Verify the underlying opt_wrapper<bool>.  */
     232          336 :           ASSERT_FALSE (res.get_result ());
     233          336 :           opt_problem *problem = res.get_problem ();
     234              : 
     235          336 :           if (with_dumping)
     236              :             {
     237          168 :               ASSERT_NE (problem, NULL);
     238          168 :               ASSERT_EQ (problem->get_dump_location ().get_location_t (),
     239              :                          line_6);
     240              : #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
     241              :               /* Verify that the problem captures the implementation location
     242              :                  it was emitted from.  */
     243          168 :               const dump_impl_location_t &impl_location
     244          168 :                 = problem->get_dump_location ().get_impl_location ();
     245          168 :               ASSERT_STR_CONTAINS (impl_location.m_function,
     246              :                                    "function_that_fails");
     247              : #endif
     248              : 
     249              :               /* Verify that the underlying dump items are retained in the
     250              :                  opt_problem.  */
     251          168 :               const optinfo &info = problem->get_optinfo ();
     252          168 :               ASSERT_EQ (info.get_dump_location ().get_location_t (), line_6);
     253          168 :               ASSERT_EQ (info.num_items (), 4);
     254          168 :               ASSERT_IS_TEXT (info.get_item (0), "can't handle return type: ");
     255          168 :               ASSERT_IS_TREE (info.get_item (1), UNKNOWN_LOCATION, "int");
     256          168 :               ASSERT_IS_TEXT (info.get_item (2), " for stmt: ");
     257          168 :               ASSERT_IS_GIMPLE (info.get_item (3), line_6, "return 0;\n");
     258              : 
     259              :               /* ...but not in the dump_context's pending_optinfo.  */
     260          168 :               ASSERT_EQ (tmp.get_pending_optinfo (), NULL);
     261              : 
     262              :               /* Simulate emitting a high-level summary message, followed
     263              :                  by the problem.  */
     264          168 :               dump_printf_loc (MSG_MISSED_OPTIMIZATION, stmt_at_5,
     265              :                                "can't optimize loop\n");
     266          168 :               problem->emit_and_clear ();
     267          168 :               ASSERT_EQ (res.get_problem (), NULL);
     268              : 
     269              :               /* Verify that the error message was dumped (when the failure
     270              :                  occurred).  We can't use a switch here as not all of the
     271              :                  values are const expressions (using C++98).  */
     272          168 :               dump_flags_t effective_filter
     273          168 :                 = filter & (MSG_PRIORITY_INTERNALS | MSG_PRIORITY_REEMITTED);
     274          168 :               if (effective_filter
     275          168 :                   == (MSG_PRIORITY_INTERNALS | MSG_PRIORITY_REEMITTED))
     276              :                 /* The -fopt-info-internals case.  */
     277           42 :                 ASSERT_DUMPED_TEXT_EQ
     278              :                   (tmp,
     279              :                    "test.c:6:12: note:  === function_that_indirectly_fails"
     280              :                    " ===\n"
     281              :                    "test.c:6:12: note:   === function_that_fails ===\n"
     282              :                    "test.c:6:12: missed:   can't handle return type: int"
     283              :                    " for stmt: return 0;\n"
     284              :                    "test.c:5:10: missed: can't optimize loop\n"
     285              :                    "test.c:6:12: missed: can't handle return type: int"
     286              :                    " for stmt: return 0;\n");
     287          126 :               else if (effective_filter == MSG_PRIORITY_INTERNALS)
     288              :                 /* The default for dump files.  */
     289           42 :                 ASSERT_DUMPED_TEXT_EQ
     290              :                   (tmp,
     291              :                    "test.c:6:12: note:  === function_that_indirectly_fails"
     292              :                    " ===\n"
     293              :                    "test.c:6:12: note:   === function_that_fails ===\n"
     294              :                    "test.c:6:12: missed:   can't handle return type: int"
     295              :                      " for stmt: return 0;\n"
     296              :                    "test.c:5:10: missed: can't optimize loop\n");
     297           84 :               else if (effective_filter == MSG_PRIORITY_REEMITTED)
     298              :                 /* The default when -fopt-info is enabled.  */
     299           42 :                 ASSERT_DUMPED_TEXT_EQ
     300              :                   (tmp,
     301              :                    "test.c:5:10: missed: can't optimize loop\n"
     302              :                    "test.c:6:12: missed: can't handle return type: int"
     303              :                    " for stmt: return 0;\n");
     304              :               else
     305              :                 {
     306           42 :                   gcc_assert (effective_filter == 0);
     307           42 :                   ASSERT_DUMPED_TEXT_EQ
     308              :                     (tmp,
     309              :                      "test.c:5:10: missed: can't optimize loop\n");
     310              :                 }
     311              :             }
     312              :           else
     313              :             {
     314              :               /* If dumping was disabled, then no problem should have been
     315              :                  created, and nothing should have been dumped.  */
     316          168 :               ASSERT_EQ (problem, NULL);
     317          168 :               ASSERT_DUMPED_TEXT_EQ (tmp, "");
     318              :             }
     319          336 :         }
     320              :     }
     321           72 : }
     322              : 
     323              : /* Run all of the selftests within this file.  */
     324              : 
     325              : void
     326            3 : c_opt_problem_cc_tests ()
     327              : {
     328            3 :   test_opt_result_success ();
     329            3 :   for_each_line_table_case (test_opt_result_failure_at);
     330            3 : }
     331              : 
     332              : } // namespace selftest
     333              : 
     334              : #endif /* CHECKING_P */
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.