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