LCOV - code coverage report
Current view: top level - gcc/cp - logic.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 80.0 % 295 236
Test Date: 2026-02-28 14:20:25 Functions: 94.1 % 34 32
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Derivation and subsumption rules for constraints.
       2              :    Copyright (C) 2013-2026 Free Software Foundation, Inc.
       3              :    Contributed by Andrew Sutton (andrew.n.sutton@gmail.com)
       4              : 
       5              : This file is part of GCC.
       6              : 
       7              : GCC is free software; you can redistribute it and/or modify
       8              : it under the terms of the GNU General Public License as published by
       9              : the Free Software Foundation; either version 3, or (at your option)
      10              : any later version.
      11              : 
      12              : GCC is distributed in the hope that it will be useful,
      13              : but WITHOUT ANY WARRANTY; without even the implied warranty of
      14              : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15              : GNU General Public License 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              : #define INCLUDE_LIST
      23              : #include "system.h"
      24              : #include "coretypes.h"
      25              : #include "tm.h"
      26              : #include "timevar.h"
      27              : #include "hash-set.h"
      28              : #include "machmode.h"
      29              : #include "vec.h"
      30              : #include "double-int.h"
      31              : #include "input.h"
      32              : #include "alias.h"
      33              : #include "symtab.h"
      34              : #include "wide-int.h"
      35              : #include "inchash.h"
      36              : #include "tree.h"
      37              : #include "stringpool.h"
      38              : #include "attribs.h"
      39              : #include "intl.h"
      40              : #include "flags.h"
      41              : #include "cp-tree.h"
      42              : #include "c-family/c-common.h"
      43              : #include "c-family/c-objc.h"
      44              : #include "cp-objcp-common.h"
      45              : #include "tree-inline.h"
      46              : #include "decl.h"
      47              : #include "toplev.h"
      48              : #include "type-utils.h"
      49              : 
      50              : /* A conjunctive or disjunctive clause.
      51              : 
      52              :    Each clause maintains an iterator that refers to the current
      53              :    term, which is used in the linear decomposition of a formula
      54              :    into CNF or DNF.  */
      55              : 
      56       121048 : struct clause
      57              : {
      58              :   typedef std::list<tree>::iterator iterator;
      59              :   typedef std::list<tree>::const_iterator const_iterator;
      60              : 
      61              :   /* Initialize a clause with an initial term.  */
      62              : 
      63        93846 :   clause (tree t)
      64        93846 :   {
      65        93846 :     m_terms.push_back (t);
      66        93846 :     if (TREE_CODE (t) == ATOMIC_CONSTR)
      67        27354 :       m_set.add (t);
      68              : 
      69        93846 :     m_current = m_terms.begin ();
      70        93846 :   }
      71              : 
      72              :   /* Create a copy of the current term.  The current
      73              :      iterator is set to point to the same position in the
      74              :      copied list of terms.  */
      75              : 
      76        27202 :   clause (clause const& c)
      77        27202 :     : m_terms (c.m_terms), m_set (c.m_set), m_current (m_terms.begin ())
      78              :   {
      79        27202 :     std::advance (m_current, std::distance (c.begin (), c.current ()));
      80        27202 :   }
      81              : 
      82              :   /* Returns true when all terms are atoms.  */
      83              : 
      84     16879222 :   bool done () const
      85              :   {
      86     16879222 :     return m_current == end ();
      87              :   }
      88              : 
      89              :   /* Advance to the next term.  */
      90              : 
      91      3011549 :   void advance ()
      92              :   {
      93            0 :     gcc_assert (!done ());
      94      3011549 :     ++m_current;
      95      3011549 :   }
      96              : 
      97              :   /* Replaces the current term at position ITER with T.  If
      98              :      T is an atomic constraint that already appears in the
      99              :      clause, remove but do not replace ITER.  Returns a pair
     100              :      containing an iterator to the replace object or past
     101              :      the erased object and a boolean value which is true if
     102              :      an object was erased.  */
     103              : 
     104     10762345 :   std::pair<iterator, bool> replace (iterator iter, tree t)
     105              :   {
     106     10762345 :     gcc_assert (TREE_CODE (*iter) != ATOMIC_CONSTR);
     107     10762345 :     if (TREE_CODE (t) == ATOMIC_CONSTR)
     108              :       {
     109      5275840 :         if (m_set.add (t))
     110      3956327 :           return std::make_pair (m_terms.erase (iter), true);
     111              :       }
     112      6806018 :     *iter = t;
     113      6806018 :     return std::make_pair (iter, false);
     114              :   }
     115              : 
     116              :   /* Inserts T before ITER in the list of terms.  If T is an atomic
     117              :      constraint that already appears in the clause, no action is taken,
     118              :      and the current iterator is returned.  Returns a pair of an iterator
     119              :      to the inserted object or ITER if no insertion occurred and a boolean
     120              :      value which is true if an object was inserted.  */
     121              : 
     122     10707941 :   std::pair<iterator, bool> insert (iterator iter, tree t)
     123              :   {
     124     10707941 :     if (TREE_CODE (t) == ATOMIC_CONSTR)
     125              :       {
     126      5525794 :         if (m_set.add (t))
     127      3861046 :           return std::make_pair (iter, false);
     128              :       }
     129      6846895 :     return std::make_pair (m_terms.insert (iter, t), true);
     130              :   }
     131              : 
     132              :   /* Replaces the current term with T.  In the case where the
     133              :      current term is erased (because T is redundant), update
     134              :      the position of the current term to the next term.  */
     135              : 
     136        54404 :   void replace (tree t)
     137              :   {
     138        54404 :     m_current = replace (m_current, t).first;
     139        54404 :   }
     140              : 
     141              :   /* Replace the current term with T1 and T2, in that order.  */
     142              : 
     143     10707941 :   void replace (tree t1, tree t2)
     144              :   {
     145              :     /* Replace the current term with t1.  Ensure that iter points
     146              :        to the term before which t2 will be inserted.  Update the
     147              :        current term as needed.  */
     148     10707941 :     std::pair<iterator, bool> rep = replace (m_current, t1);
     149     10707941 :     if (rep.second)
     150      3956327 :       m_current = rep.first;
     151              :     else
     152      6751614 :       ++rep.first;
     153              : 
     154              :     /* Insert the t2.  Make this the current term if we erased
     155              :        the prior term.  */
     156     10707941 :     std::pair<iterator, bool> ins = insert (rep.first, t2);
     157     10707941 :     if (rep.second && ins.second)
     158      1062914 :       m_current = ins.first;
     159     10707941 :   }
     160              : 
     161              :   /* Returns true if the clause contains the term T.  */
     162              : 
     163      2392622 :   bool contains (tree t)
     164              :   {
     165      2392622 :     gcc_assert (TREE_CODE (t) == ATOMIC_CONSTR);
     166      2392622 :     return m_set.contains (t);
     167              :   }
     168              : 
     169              : 
     170              :   /* Returns an iterator to the first clause in the formula.  */
     171              : 
     172            0 :   iterator begin ()
     173              :   {
     174            0 :     return m_terms.begin ();
     175              :   }
     176              : 
     177              :   /* Returns an iterator to the first clause in the formula.  */
     178              : 
     179        27202 :   const_iterator begin () const
     180              :   {
     181        27202 :     return m_terms.begin ();
     182              :   }
     183              : 
     184              :   /* Returns an iterator past the last clause in the formula.  */
     185              : 
     186            0 :   iterator end ()
     187              :   {
     188            0 :     return m_terms.end ();
     189              :   }
     190              : 
     191              :   /* Returns an iterator past the last clause in the formula.  */
     192              : 
     193     16879222 :   const_iterator end () const
     194              :   {
     195      3011549 :     return m_terms.end ();
     196              :   }
     197              : 
     198              :   /* Returns the current iterator.  */
     199              : 
     200     13773894 :   const_iterator current () const
     201              :   {
     202        27202 :     return m_current;
     203              :   }
     204              : 
     205              :   std::list<tree> m_terms; /* The list of terms.  */
     206              :   hash_set<tree> m_set; /* The set of atomic constraints.  */
     207              :   iterator m_current; /* The current term.  */
     208              : };
     209              : 
     210              : 
     211              : /* A proof state owns a list of goals and tracks the
     212              :    current sub-goal.  The class also provides facilities
     213              :    for managing subgoals and constructing term lists.  */
     214              : 
     215       187692 : struct formula
     216              : {
     217              :   typedef std::list<clause>::iterator iterator;
     218              :   typedef std::list<clause>::const_iterator const_iterator;
     219              : 
     220              :   /* Construct a formula with an initial formula in a
     221              :      single clause.  */
     222              : 
     223        93846 :   formula (tree t)
     224        93846 :   {
     225        93846 :     m_clauses.emplace_back (t);
     226        93846 :     m_current = m_clauses.begin ();
     227        93846 :   }
     228              : 
     229              :   /* Returns true when all clauses are atomic.  */
     230       316017 :   bool done () const
     231              :   {
     232       316017 :     return m_current == end ();
     233              :   }
     234              : 
     235              :   /* Advance to the next term.  */
     236       120981 :   void advance ()
     237              :   {
     238            0 :     gcc_assert (!done ());
     239       120981 :     ++m_current;
     240       120981 :   }
     241              : 
     242              :   /* Insert a copy of clause into the formula.  This corresponds
     243              :      to a distribution of one logical operation over the other.  */
     244              : 
     245        27202 :   clause& branch ()
     246              :   {
     247            0 :     gcc_assert (!done ());
     248        54404 :     return *m_clauses.insert (std::next (m_current), *m_current);
     249              :   }
     250              : 
     251              :   /* Returns the position of the current clause.  */
     252              : 
     253              :   iterator current ()
     254              :   {
     255              :     return m_current;
     256              :   }
     257              : 
     258              :   /* Returns an iterator to the first clause in the formula.  */
     259              : 
     260            0 :   iterator begin ()
     261              :   {
     262            0 :     return m_clauses.begin ();
     263              :   }
     264              : 
     265              :   /* Returns an iterator to the first clause in the formula.  */
     266              : 
     267              :   const_iterator begin () const
     268              :   {
     269              :     return m_clauses.begin ();
     270              :   }
     271              : 
     272              :   /* Returns an iterator past the last clause in the formula.  */
     273              : 
     274            0 :   iterator end ()
     275              :   {
     276            0 :     return m_clauses.end ();
     277              :   }
     278              : 
     279              :   /* Returns an iterator past the last clause in the formula.  */
     280              : 
     281       316017 :   const_iterator end () const
     282              :   {
     283       148183 :     return m_clauses.end ();
     284              :   }
     285              : 
     286              :   /* Remove the specified clause from the formula.  */
     287              : 
     288        73988 :   void erase (iterator i)
     289              :   {
     290        73988 :     gcc_assert (i != m_current);
     291        73988 :     m_clauses.erase (i);
     292        73988 :   }
     293              : 
     294              :   std::list<clause> m_clauses; /* The list of clauses.  */
     295              :   iterator m_current; /* The current clause.  */
     296              : };
     297              : 
     298              : void
     299            0 : debug (clause& c)
     300              : {
     301            0 :   for (clause::iterator i = c.begin (); i != c.end (); ++i)
     302            0 :     verbatim ("  # %E", *i);
     303            0 : }
     304              : 
     305              : void
     306            0 : debug (formula& f)
     307              : {
     308            0 :   for (formula::iterator i = f.begin (); i != f.end (); ++i)
     309              :     {
     310              :       /* Format punctuators via %s to avoid -Wformat-diag.  */
     311            0 :       verbatim ("%s", "(((");
     312            0 :       debug (*i);
     313            0 :       verbatim ("%s", ")))");
     314              :     }
     315            0 : }
     316              : 
     317              : /* The logical rules used to analyze a logical formula.  The
     318              :    "left" and "right" refer to the position of formula in a
     319              :    sequent (as in sequent calculus).  */
     320              : 
     321              : enum rules
     322              : {
     323              :   left, right
     324              : };
     325              : 
     326              : /* Distribution counting.  */
     327              : 
     328              : static inline bool
     329     64410984 : disjunction_p (tree t)
     330              : {
     331     64410984 :   return TREE_CODE (t) == DISJ_CONSTR;
     332              : }
     333              : 
     334              : static inline bool
     335              : conjunction_p (tree t)
     336              : {
     337              :   return TREE_CODE (t) == CONJ_CONSTR;
     338              : }
     339              : 
     340              : static inline bool
     341     43128348 : atomic_p (tree t)
     342              : {
     343     43128348 :   return TREE_CODE (t) == ATOMIC_CONSTR;
     344              : }
     345              : 
     346              : /* Recursively count the number of clauses produced when converting T
     347              :    to DNF.  Returns a pair containing the number of clauses and a bool
     348              :    value signifying that the tree would be rewritten as a result of
     349              :    distributing.  In general, a conjunction for which this flag is set
     350              :    is considered a disjunction for the purpose of counting.  */
     351              : 
     352              : static std::pair<HOST_WIDE_INT, bool>
     353     21564162 : dnf_size_r (tree t)
     354              : {
     355     21564162 :   if (atomic_p (t))
     356              :     /* Atomic constraints produce no clauses.  */
     357     10829004 :     return std::make_pair (0, false);
     358              : 
     359              :   /* For compound constraints, recursively count clauses and unpack
     360              :      the results.  */
     361     10735158 :   tree lhs = TREE_OPERAND (t, 0);
     362     10735158 :   tree rhs = TREE_OPERAND (t, 1);
     363     10735158 :   auto p1 = dnf_size_r (lhs);
     364     10735158 :   auto p2 = dnf_size_r (rhs);
     365     10735158 :   HOST_WIDE_INT n1 = p1.first, n2 = p2.first;
     366     10735158 :   bool d1 = p1.second, d2 = p2.second;
     367              : 
     368     10735158 :   if (disjunction_p (t))
     369              :     {
     370              :       /* Matches constraints of the form P \/ Q.  Disjunctions contribute
     371              :          linearly to the number of constraints.  When both P and Q are
     372              :          disjunctions, clauses are added.  When only one of P and Q
     373              :          is a disjunction, an additional clause is produced.  When neither
     374              :          P nor Q are disjunctions, two clauses are produced.  */
     375        27202 :       if (disjunction_p (lhs))
     376              :         {
     377            0 :           if (disjunction_p (rhs) || (conjunction_p (rhs) && d2))
     378              :             /* Both P and Q are disjunctions.  */
     379            0 :             return std::make_pair (add_sat_hwi (n1, n2), d1 | d2);
     380              :           else
     381              :             /* Only LHS is a disjunction.  */
     382            0 :             return std::make_pair (add_sat_hwi (1, add_sat_hwi (n1, n2)),
     383            0 :                                    d1 | d2);
     384              :           gcc_unreachable ();
     385              :         }
     386        27202 :       if (conjunction_p (lhs))
     387              :         {
     388        27070 :           if ((disjunction_p (rhs) && d1) || (conjunction_p (rhs) && d1 && d2))
     389              :             /* Both P and Q are disjunctions.  */
     390         9023 :             return std::make_pair (add_sat_hwi (n1, n2), d1 | d2);
     391        18047 :           if (disjunction_p (rhs)
     392        18047 :               || (conjunction_p (rhs) && d1 != d2)
     393        36094 :               || (atomic_p (rhs) && d1))
     394              :             /* Either LHS or RHS is a disjunction.  */
     395            0 :             return std::make_pair (add_sat_hwi (1, add_sat_hwi (n1, n2)),
     396            0 :                                    d1 | d2);
     397              :           else
     398              :             /* Neither LHS nor RHS is a disjunction.  */
     399        18047 :             return std::make_pair (2, false);
     400              :         }
     401          132 :       if (atomic_p (lhs))
     402              :         {
     403          132 :           if (disjunction_p (rhs) || (conjunction_p (rhs) && d2))
     404              :             /* Only RHS is a disjunction.  */
     405            0 :             return std::make_pair (add_sat_hwi (1, add_sat_hwi (n1, n2)),
     406            0 :                                    d1 | d2);
     407              :           else
     408              :             /* Neither LHS nor RHS is a disjunction.  */
     409          132 :             return std::make_pair (2, false);
     410              :         }
     411              :     }
     412              :   else /* conjunction_p (t)  */
     413              :     {
     414              :       /* Matches constraints of the form P /\ Q, possibly resulting
     415              :          in the distribution of one side over the other.  When both
     416              :          P and Q are disjunctions, the number of clauses are multiplied.
     417              :          When only one of P and Q is a disjunction, the number of
     418              :          clauses are added.  Otherwise, neither side is a disjunction and
     419              :          no clauses are created.  */
     420     10707956 :       if (disjunction_p (lhs))
     421              :         {
     422            0 :           if (disjunction_p (rhs) || (conjunction_p (rhs) && d2))
     423              :             /* Both P and Q are disjunctions.  */
     424            0 :             return std::make_pair (mul_sat_hwi (n1, n2), true);
     425              :           else
     426              :             /* Only LHS is a disjunction.  */
     427            0 :             return std::make_pair (add_sat_hwi (n1, n2), true);
     428              :           gcc_unreachable ();
     429              :         }
     430     10707956 :       if (conjunction_p (lhs))
     431              :         {
     432      5441395 :           if ((disjunction_p (rhs) && d1) || (conjunction_p (rhs) && d1 && d2))
     433              :             /* Both P and Q are disjunctions.  */
     434            0 :             return std::make_pair (mul_sat_hwi (n1, n2), true);
     435      5441395 :           if (disjunction_p (rhs)
     436      5423217 :               || (conjunction_p (rhs) && d1 != d2)
     437     10864612 :               || (atomic_p (rhs) && d1))
     438              :             /* Either LHS or RHS is a disjunction.  */
     439        18178 :             return std::make_pair (add_sat_hwi (n1, n2), true);
     440              :           else
     441              :             /* Neither LHS nor RHS is a disjunction.  */
     442      5423217 :             return std::make_pair (0, false);
     443              :         }
     444      5266561 :       if (atomic_p (lhs))
     445              :         {
     446      5266561 :           if (disjunction_p (rhs) || (conjunction_p (rhs) && d2))
     447              :             /* Only RHS is a disjunction.  */
     448         9023 :             return std::make_pair (n1 + n2, true);
     449              :           else
     450              :             /* Neither LHS nor RHS is a disjunction.  */
     451      5257538 :             return std::make_pair (0, false);
     452              :         }
     453              :     }
     454            0 :   gcc_unreachable ();
     455              : }
     456              : 
     457              : /* Recursively count the number of clauses produced when converting T
     458              :    to CNF.  Returns a pair containing the number of clauses and a bool
     459              :    value signifying that the tree would be rewritten as a result of
     460              :    distributing.  In general, a disjunction for which this flag is set
     461              :    is considered a conjunction for the purpose of counting.  */
     462              : 
     463              : static std::pair<HOST_WIDE_INT, bool>
     464     21564186 : cnf_size_r (tree t)
     465              : {
     466     21564186 :   if (atomic_p (t))
     467              :     /* Atomic constraints produce no clauses.  */
     468     10829016 :     return std::make_pair (0, false);
     469              : 
     470              :   /* For compound constraints, recursively count clauses and unpack
     471              :      the results.  */
     472     10735170 :   tree lhs = TREE_OPERAND (t, 0);
     473     10735170 :   tree rhs = TREE_OPERAND (t, 1);
     474     10735170 :   auto p1 = cnf_size_r (lhs);
     475     10735170 :   auto p2 = cnf_size_r (rhs);
     476     10735170 :   HOST_WIDE_INT n1 = p1.first, n2 = p2.first;
     477     10735170 :   bool d1 = p1.second, d2 = p2.second;
     478              : 
     479     10735170 :   if (disjunction_p (t))
     480              :     {
     481              :       /* Matches constraints of the form P \/ Q, possibly resulting
     482              :          in the distribution of one side over the other.  When both
     483              :          P and Q are conjunctions, the number of clauses are multiplied.
     484              :          When only one of P and Q is a conjunction, the number of
     485              :          clauses are added.  Otherwise, neither side is a conjunction and
     486              :          no clauses are created.  */
     487        27211 :       if (disjunction_p (lhs))
     488              :         {
     489            0 :           if ((disjunction_p (rhs) && d1 && d2) || (conjunction_p (rhs) && d1))
     490              :             /* Both P and Q are conjunctions.  */
     491            0 :             return std::make_pair (mul_sat_hwi (n1, n2), true);
     492            0 :           if ((disjunction_p (rhs) && d1 != d2)
     493            0 :               || conjunction_p (rhs)
     494            0 :               || (atomic_p (rhs) && d1))
     495              :             /* Either LHS or RHS is a conjunction.  */
     496            0 :             return std::make_pair (add_sat_hwi (n1, n2), true);
     497              :           else
     498              :             /* Neither LHS nor RHS is a conjunction.  */
     499            0 :             return std::make_pair (0, false);
     500              :         }
     501        27211 :       if (conjunction_p (lhs))
     502              :         {
     503        27070 :           if ((disjunction_p (rhs) && d2) || conjunction_p (rhs))
     504              :             /* Both LHS and RHS are conjunctions.  */
     505        18047 :             return std::make_pair (mul_sat_hwi (n1, n2), true);
     506              :           else
     507              :             /* Only LHS is a conjunction.  */
     508         9023 :             return std::make_pair (add_sat_hwi (n1, n2), true);
     509              :         }
     510          141 :       if (atomic_p (lhs))
     511              :         {
     512          141 :           if ((disjunction_p (rhs) && d2) || conjunction_p (rhs))
     513              :             /* Only RHS is a disjunction.  */
     514            0 :             return std::make_pair (add_sat_hwi (n1, n2), true);
     515              :           else
     516              :             /* Neither LHS nor RHS is a disjunction.  */
     517          141 :             return std::make_pair (0, false);
     518              :         }
     519              :     }
     520              :   else /* conjunction_p (t)  */
     521              :     {
     522              :       /* Matches constraints of the form P /\ Q.  Conjunctions contribute
     523              :          linearly to the number of constraints.  When both P and Q are
     524              :          conjunctions, clauses are added.  When only one of P and Q
     525              :          is a conjunction, an additional clause is produced.  When neither
     526              :          P nor Q are conjunctions, two clauses are produced.  */
     527     10707959 :       if (disjunction_p (lhs))
     528              :         {
     529            0 :           if ((disjunction_p (rhs) && d1 && d2) || (conjunction_p (rhs) && d1))
     530              :             /* Both P and Q are conjunctions.  */
     531            0 :             return std::make_pair (add_sat_hwi (n1, n2), d1 | d2);
     532            0 :           if ((disjunction_p (rhs) && d1 != d2)
     533            0 :               || conjunction_p (rhs)
     534            0 :               || (atomic_p (rhs) && d1))
     535              :             /* Either LHS or RHS is a conjunction.  */
     536            0 :             return std::make_pair (add_sat_hwi (1, add_sat_hwi (n1, n2)),
     537            0 :                                    d1 | d2);
     538              :           else
     539              :             /* Neither LHS nor RHS is a conjunction.  */
     540            0 :             return std::make_pair (2, false);
     541              :         }
     542     10707959 :       if (conjunction_p (lhs))
     543              :         {
     544      5441395 :           if ((disjunction_p (rhs) && d2) || conjunction_p (rhs))
     545              :             /* Both LHS and RHS are conjunctions.  */
     546      4090682 :             return std::make_pair (add_sat_hwi (n1, n2), d1 | d2);
     547              :           else
     548              :             /* Only LHS is a conjunction.  */
     549      1350713 :             return std::make_pair (add_sat_hwi (1, add_sat_hwi (n1, n2)),
     550      2701426 :                                    d1 | d2);
     551              :         }
     552      5266564 :       if (atomic_p (lhs))
     553              :         {
     554      5266564 :           if ((disjunction_p (rhs) && d2) || conjunction_p (rhs))
     555              :             /* Only RHS is a disjunction.  */
     556      1091340 :             return std::make_pair (add_sat_hwi (1, add_sat_hwi (n1, n2)),
     557      2182680 :                                    d1 | d2);
     558              :           else
     559              :             /* Neither LHS nor RHS is a disjunction.  */
     560      4175224 :             return std::make_pair (2, false);
     561              :         }
     562              :     }
     563            0 :   gcc_unreachable ();
     564              : }
     565              : 
     566              : /* Count the number conjunctive clauses that would be created
     567              :    when rewriting T to DNF.  */
     568              : 
     569              : static HOST_WIDE_INT
     570        93846 : dnf_size (tree t)
     571              : {
     572            0 :   auto result = dnf_size_r (t);
     573        93846 :   return result.first == 0 ? 1 : result.first;
     574              : }
     575              : 
     576              : 
     577              : /* Count the number disjunctive clauses that would be created
     578              :    when rewriting T to CNF.  */
     579              : 
     580              : static HOST_WIDE_INT
     581        93846 : cnf_size (tree t)
     582              : {
     583            0 :   auto result = cnf_size_r (t);
     584        93846 :   return result.first == 0 ? 1 : result.first;
     585              : }
     586              : 
     587              : 
     588              : /* A left-conjunction is replaced by its operands.  */
     589              : 
     590              : void
     591     10707941 : replace_term (clause& c, tree t)
     592              : {
     593     10707941 :   tree t1 = TREE_OPERAND (t, 0);
     594     10707941 :   tree t2 = TREE_OPERAND (t, 1);
     595     10707941 :   return c.replace (t1, t2);
     596              : }
     597              : 
     598              : /* Create a new clause in the formula by copying the current
     599              :    clause.  In the current clause, the term at CI is replaced
     600              :    by the first operand, and in the new clause, it is replaced
     601              :    by the second.  */
     602              : 
     603              : void
     604        27202 : branch_clause (formula& f, clause& c1, tree t)
     605              : {
     606        27202 :   tree t1 = TREE_OPERAND (t, 0);
     607        27202 :   tree t2 = TREE_OPERAND (t, 1);
     608        27202 :   clause& c2 = f.branch ();
     609        27202 :   c1.replace (t1);
     610        27202 :   c2.replace (t2);
     611        27202 : }
     612              : 
     613              : /* Decompose t1 /\ t2 according to the rules R.  */
     614              : 
     615              : inline void
     616     10707941 : decompose_conjuntion (formula& f, clause& c, tree t, rules r)
     617              : {
     618     10707941 :   if (r == left)
     619     10707941 :     replace_term (c, t);
     620              :   else
     621            0 :     branch_clause (f, c, t);
     622     10707941 : }
     623              : 
     624              : /* Decompose t1 \/ t2 according to the rules R.  */
     625              : 
     626              : inline void
     627        27202 : decompose_disjunction (formula& f, clause& c, tree t, rules r)
     628              : {
     629        27202 :   if (r == right)
     630            0 :     replace_term (c, t);
     631              :   else
     632        27202 :     branch_clause (f, c, t);
     633        27202 : }
     634              : 
     635              : /* An atomic constraint is already decomposed.  */
     636              : inline void
     637      3011549 : decompose_atom (clause& c)
     638              : {
     639      3011549 :   c.advance ();
     640      3011549 : }
     641              : 
     642              : /* Decompose a term of clause C (in formula F) according to the
     643              :    logical rules R.  */
     644              : 
     645              : void
     646     13746692 : decompose_term (formula& f, clause& c, tree t, rules r)
     647              : {
     648     13746692 :   switch (TREE_CODE (t))
     649              :     {
     650     10707941 :     case CONJ_CONSTR:
     651     10707941 :       return decompose_conjuntion (f, c, t, r);
     652        27202 :     case DISJ_CONSTR:
     653        27202 :       return decompose_disjunction (f, c, t, r);
     654      3011549 :     default:
     655      3011549 :       return decompose_atom (c);
     656              :     }
     657              : }
     658              : 
     659              : /* Decompose C (in F) using the logical rules R until it
     660              :    is comprised of only atomic constraints.  */
     661              : 
     662              : void
     663       120981 : decompose_clause (formula& f, clause& c, rules r)
     664              : {
     665     13867673 :   while (!c.done ())
     666     13746692 :     decompose_term (f, c, *c.current (), r);
     667       120981 :   f.advance ();
     668       120981 : }
     669              : 
     670              : static bool derive_proof (clause&, tree, rules);
     671              : 
     672              : /* Derive a proof of both operands of T.  */
     673              : 
     674              : static bool
     675      2446659 : derive_proof_for_both_operands (clause& c, tree t, rules r)
     676              : {
     677      2446659 :   if (!derive_proof (c, TREE_OPERAND (t, 0), r))
     678              :     return false;
     679      2254239 :   return derive_proof (c, TREE_OPERAND (t, 1), r);
     680              : }
     681              : 
     682              : /* Derive a proof of either operand of T.  */
     683              : 
     684              : static bool
     685        17477 : derive_proof_for_either_operand (clause& c, tree t, rules r)
     686              : {
     687        17477 :   if (derive_proof (c, TREE_OPERAND (t, 0), r))
     688              :     return true;
     689        17402 :   return derive_proof (c, TREE_OPERAND (t, 1), r);
     690              : }
     691              : 
     692              : /* Derive a proof of the atomic constraint T in clause C.  */
     693              : 
     694              : static bool
     695      2392622 : derive_atomic_proof (clause& c, tree t)
     696              : {
     697            0 :   return c.contains (t);
     698              : }
     699              : 
     700              : /* Derive a proof of T from the terms in C.  */
     701              : 
     702              : static bool
     703      4856758 : derive_proof (clause& c, tree t, rules r)
     704              : {
     705      4856758 :   switch (TREE_CODE (t))
     706              :   {
     707      2446659 :     case CONJ_CONSTR:
     708      2446659 :       if (r == left)
     709      2446659 :         return derive_proof_for_both_operands (c, t, r);
     710              :       else
     711            0 :         return derive_proof_for_either_operand (c, t, r);
     712        17477 :     case DISJ_CONSTR:
     713        17477 :       if (r == left)
     714        17477 :         return derive_proof_for_either_operand (c, t, r);
     715              :       else
     716            0 :         return derive_proof_for_both_operands (c, t, r);
     717      2392622 :     default:
     718      2392622 :       return derive_atomic_proof (c, t);
     719              :   }
     720              : }
     721              : 
     722              : /* Key/value pair for caching subsumption results.  This associates a pair of
     723              :    constraints with a boolean value indicating the result.  */
     724              : 
     725              : struct GTY((for_user)) subsumption_entry
     726              : {
     727              :   tree lhs;
     728              :   tree rhs;
     729              :   bool result;
     730              : };
     731              : 
     732              : /* Hashing function and equality for constraint entries.  */
     733              : 
     734              : struct subsumption_hasher : ggc_ptr_hash<subsumption_entry>
     735              : {
     736       449145 :   static hashval_t hash (subsumption_entry *e)
     737              :   {
     738       449145 :     hashval_t val = 0;
     739       449145 :     val = iterative_hash_constraint (e->lhs, val);
     740       449145 :     val = iterative_hash_constraint (e->rhs, val);
     741       449145 :     return val;
     742              :   }
     743              : 
     744       282762 :   static bool equal (subsumption_entry *e1, subsumption_entry *e2)
     745              :   {
     746       282762 :     if (!constraints_equivalent_p (e1->lhs, e2->lhs))
     747              :       return false;
     748        70100 :     if (!constraints_equivalent_p (e1->rhs, e2->rhs))
     749              :       return false;
     750              :     return true;
     751              :   }
     752              : };
     753              : 
     754              : /* Caches the results of subsumes_constraints_nonnull (t1, t1).  */
     755              : 
     756              : static GTY ((deletable)) hash_table<subsumption_hasher> *subsumption_cache;
     757              : 
     758              : /* Search for a previously cached subsumption result.  */
     759              : 
     760              : static bool*
     761       157096 : lookup_subsumption (tree t1, tree t2)
     762              : {
     763       157096 :   if (!subsumption_cache)
     764              :     return NULL;
     765       137645 :   subsumption_entry elt = { t1, t2, false };
     766       137645 :   subsumption_entry* found = subsumption_cache->find (&elt);
     767       137645 :   if (found)
     768        63250 :     return &found->result;
     769              :   else
     770              :     return 0;
     771              : }
     772              : 
     773              : /* Save a subsumption result.  */
     774              : 
     775              : static bool
     776        93846 : save_subsumption (tree t1, tree t2, bool result)
     777              : {
     778        93846 :   if (!subsumption_cache)
     779        19451 :     subsumption_cache = hash_table<subsumption_hasher>::create_ggc (31);
     780        93846 :   subsumption_entry elt = {t1, t2, result};
     781        93846 :   subsumption_entry** slot = subsumption_cache->find_slot (&elt, INSERT);
     782        93846 :   subsumption_entry* entry = ggc_alloc<subsumption_entry> ();
     783        93846 :   *entry = elt;
     784        93846 :   *slot = entry;
     785        93846 :   return result;
     786              : }
     787              : 
     788              : 
     789              : /* Returns true if the LEFT constraint subsume the RIGHT constraints.
     790              :    This is done by deriving a proof of the conclusions on the RIGHT
     791              :    from the assumptions on the LEFT assumptions.  */
     792              : 
     793              : static bool
     794       157096 : subsumes_constraints_nonnull (tree lhs, tree rhs)
     795              : {
     796       157096 :   auto_timevar time (TV_CONSTRAINT_SUB);
     797              : 
     798       157096 :   if (bool *b = lookup_subsumption (lhs, rhs))
     799        63250 :     return *b;
     800              : 
     801        93846 :   tree x, y;
     802        93846 :   rules r;
     803       281538 :   if (dnf_size (lhs) <= cnf_size (rhs))
     804              :     /* When LHS looks simpler than RHS, we'll determine subsumption by
     805              :        decomposing LHS into its disjunctive normal form and checking that
     806              :        each (conjunctive) clause in the decomposed LHS implies RHS.  */
     807              :     x = lhs, y = rhs, r = left;
     808              :   else
     809              :     /* Otherwise, we'll determine subsumption by decomposing RHS into its
     810              :        conjunctive normal form and checking that each (disjunctive) clause
     811              :        in the decomposed RHS implies LHS.  */
     812            0 :     x = rhs, y = lhs, r = right;
     813              : 
     814              :   /* Decompose X into a list of sequents according to R, and recursively
     815              :      check for implication of Y.  */
     816        93846 :   bool result = true;
     817        93846 :   formula f (x);
     818       261680 :   while (!f.done ())
     819              :     {
     820       120981 :       auto i = f.current ();
     821       120981 :       decompose_clause (f, *i, r);
     822       120981 :       if (!derive_proof (*i, y, r))
     823              :         {
     824              :           result = false;
     825        93846 :           break;
     826              :         }
     827        73988 :       f.erase (i);
     828              :     }
     829              : 
     830        93846 :   return save_subsumption (lhs, rhs, result);
     831       157096 : }
     832              : 
     833              : /* Returns true if the LEFT constraints subsume the RIGHT
     834              :    constraints.  */
     835              : 
     836              : bool
     837     16015437 : subsumes (tree lhs, tree rhs)
     838              : {
     839     16015437 :   if (lhs == rhs)
     840              :     return true;
     841      4104686 :   if (!lhs || lhs == error_mark_node)
     842              :     return false;
     843      2130878 :   if (!rhs || rhs == error_mark_node)
     844              :     return true;
     845       157096 :   return subsumes_constraints_nonnull (lhs, rhs);
     846              : }
     847              : 
     848              : #include "gt-cp-logic.h"
        

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.