1 /* Derivation and subsumption rules for constraints.
2 Copyright (C) 2013-2017 Free Software Foundation, Inc.
3 Contributed by Andrew Sutton (andrew.n.sutton@gmail.com)
5 This file is part of GCC.
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)
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.
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/>. */
24 #include "coretypes.h"
30 #include "double-int.h"
37 #include "stringpool.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"
48 #include "type-utils.h"
61 template<typename I
, typename P
>
63 any_p (I first
, I last
, P pred
)
74 bool prove_implication (tree
, tree
);
76 /*---------------------------------------------------------------------------
78 ---------------------------------------------------------------------------*/
85 /* Hashing function and equality for constraint entries. */
87 struct term_hasher
: ggc_ptr_hash
<term_entry
>
89 static hashval_t
hash (term_entry
*e
)
91 return iterative_hash_template_arg (e
->t
, 0);
94 static bool equal (term_entry
*e1
, term_entry
*e2
)
96 return cp_tree_equal (e1
->t
, e2
->t
);
100 /* A term list is a list of atomic constraints. It is used
101 to maintain the lists of assumptions and conclusions in a
104 Each term list maintains an iterator that refers to the current
105 term. This can be used by various tactics to support iteration
106 and stateful manipulation of the list. */
109 typedef std::list
<tree
>::iterator iterator
;
114 bool includes (tree
);
115 iterator
insert (iterator
, tree
);
116 iterator
push_back (tree
);
117 iterator
erase (iterator
);
118 iterator
replace (iterator
, tree
);
119 iterator
replace (iterator
, tree
, tree
);
121 iterator
begin() { return seq
.begin(); }
122 iterator
end() { return seq
.end(); }
125 hash_table
<term_hasher
> tab
;
129 term_list::term_list ()
134 /* Initialize a term list with an initial term. */
137 term_list::term_list (tree t
)
143 /* Returns true if T is the in the tree. */
146 term_list::includes (tree t
)
148 term_entry ent
= {t
};
149 return tab
.find (&ent
);
152 /* Append a term to the list. */
153 inline term_list::iterator
154 term_list::push_back (tree t
)
156 return insert (end(), t
);
159 /* Insert a new (unseen) term T into the list before the proposition
160 indicated by ITER. Returns the iterator to the newly inserted
164 term_list::insert (iterator iter
, tree t
)
166 gcc_assert (!includes (t
));
167 iter
= seq
.insert (iter
, t
);
168 term_entry ent
= {t
};
169 term_entry
** slot
= tab
.find_slot (&ent
, INSERT
);
170 term_entry
* ptr
= ggc_alloc
<term_entry
> ();
176 /* Remove an existing term from the list. Returns an iterator referring
177 to the element after the removed term. This may be end(). */
180 term_list::erase (iterator iter
)
182 gcc_assert (includes (*iter
));
183 term_entry ent
= {*iter
};
184 tab
.remove_elt (&ent
);
185 iter
= seq
.erase (iter
);
189 /* Replace the given term with that specified. If the term has
190 been previously seen, do not insert the term. Returns the
191 first iterator past the current term. */
194 term_list::replace (iterator iter
, tree t
)
203 /* Replace the term at the given position by the supplied T1
204 followed by t2. This is used in certain logical operators to
205 load a list of assumptions or conclusions. */
208 term_list::replace (iterator iter
, tree t1
, tree t2
)
218 /* A goal (or subgoal) models a sequent of the form
219 'A |- C' where A and C are lists of assumptions and
220 conclusions written as propositions in the constraint
221 language (i.e., lists of trees). */
225 term_list assumptions
;
226 term_list conclusions
;
229 /* A proof state owns a list of goals and tracks the
230 current sub-goal. The class also provides facilities
231 for managing subgoals and constructing term lists. */
233 struct proof_state
: std::list
<proof_goal
>
237 iterator
branch (iterator i
);
238 iterator
discharge (iterator i
);
241 /* Initialize the state with a single empty goal, and set that goal
242 as the current subgoal. */
245 proof_state::proof_state ()
246 : std::list
<proof_goal
> (1)
250 /* Branch the current goal by creating a new subgoal, returning a
251 reference to the new object. This does not update the current goal. */
253 inline proof_state::iterator
254 proof_state::branch (iterator i
)
256 gcc_assert (i
!= end());
258 return insert (++i
, g
);
261 /* Discharge the current goal, setting it equal to the
262 next non-satisfied goal. */
264 inline proof_state::iterator
265 proof_state::discharge (iterator i
)
267 gcc_assert (i
!= end());
272 /*---------------------------------------------------------------------------
274 ---------------------------------------------------------------------------*/
277 // debug (term_list& ts)
279 // for (term_list::iterator i = ts.begin(); i != ts.end(); ++i)
280 // verbatim (" # %E", *i);
284 // debug (proof_goal& g)
286 // debug (g.assumptions);
288 // debug (g.conclusions);
291 /*---------------------------------------------------------------------------
292 Atomicity of constraints
293 ---------------------------------------------------------------------------*/
295 /* Returns true if T is not an atomic constraint. */
298 non_atomic_constraint_p (tree t
)
300 switch (TREE_CODE (t
))
308 /* A pack expansion isn't atomic, but it can't decompose to prove an
309 atom, so it shouldn't cause analyze_atom to return undecided. */
310 case EXPR_PACK_EXPANSION
:
322 /* Returns true if any constraints in T are not atomic. */
325 any_non_atomic_constraints_p (term_list
& t
)
327 return any_p (t
.begin(), t
.end(), non_atomic_constraint_p
);
330 /*---------------------------------------------------------------------------
332 ---------------------------------------------------------------------------*/
341 proof_result
check_term (term_list
&, tree
);
345 analyze_atom (term_list
& ts
, tree t
)
347 /* FIXME: Hook into special cases, if any. */
349 term_list::iterator iter = ts.begin();
350 term_list::iterator end = ts.end();
357 if (non_atomic_constraint_p (t
))
359 if (any_non_atomic_constraints_p (ts
))
364 /* Search for a pack expansion in the list of assumptions that would
365 make this expansion valid. */
368 analyze_pack (term_list
& ts
, tree t
)
370 tree c1
= normalize_expression (PACK_EXPANSION_PATTERN (t
));
371 term_list::iterator iter
= ts
.begin();
372 term_list::iterator end
= ts
.end();
375 if (TREE_CODE (*iter
) == TREE_CODE (t
))
377 tree c2
= normalize_expression (PACK_EXPANSION_PATTERN (*iter
));
378 if (prove_implication (c2
, c1
))
388 /* Search for concept checks in TS that we know subsume T. */
391 search_known_subsumptions (term_list
& ts
, tree t
)
393 for (term_list::iterator i
= ts
.begin(); i
!= ts
.end(); ++i
)
394 if (TREE_CODE (*i
) == CHECK_CONSTR
)
396 if (bool* b
= lookup_subsumption_result (*i
, t
))
397 return *b
? valid
: invalid
;
402 /* Determine if the terms in TS provide sufficient support for proving
403 the proposition T. If any term in TS is a concept check that is known
404 to subsume T, then the proof is valid. Otherwise, we have to expand T
405 and continue searching for support. */
408 analyze_check (term_list
& ts
, tree t
)
410 proof_result r
= search_known_subsumptions (ts
, t
);
414 tree tmpl
= CHECK_CONSTR_CONCEPT (t
);
415 tree args
= CHECK_CONSTR_ARGS (t
);
416 tree c
= expand_concept (tmpl
, args
);
417 return check_term (ts
, c
);
420 /* Recursively check constraints of the parameterized constraint. */
423 analyze_parameterized (term_list
& ts
, tree t
)
425 return check_term (ts
, PARM_CONSTR_OPERAND (t
));
429 analyze_conjunction (term_list
& ts
, tree t
)
431 proof_result r
= check_term (ts
, TREE_OPERAND (t
, 0));
432 if (r
== invalid
|| r
== undecided
)
434 return check_term (ts
, TREE_OPERAND (t
, 1));
438 analyze_disjunction (term_list
& ts
, tree t
)
440 proof_result r
= check_term (ts
, TREE_OPERAND (t
, 0));
443 return check_term (ts
, TREE_OPERAND (t
, 1));
447 analyze_term (term_list
& ts
, tree t
)
449 switch (TREE_CODE (t
))
452 return analyze_check (ts
, t
);
455 return analyze_parameterized (ts
, t
);
458 return analyze_conjunction (ts
, t
);
460 return analyze_disjunction (ts
, t
);
468 return analyze_atom (ts
, t
);
470 case EXPR_PACK_EXPANSION
:
471 return analyze_pack (ts
, t
);
474 /* Encountering an error anywhere in a constraint invalidates
475 the proof, since the constraint is ill-formed. */
482 /* Check if a single term can be proven from a set of assumptions.
483 If the proof is not valid, then it is incomplete when either
484 the given term is non-atomic or any term in the list of assumptions
488 check_term (term_list
& ts
, tree t
)
490 /* Try the easy way; search for an equivalent term. */
494 /* The hard way; actually consider what the term means. */
495 return analyze_term (ts
, t
);
498 /* Check to see if any term is proven by the assumptions in the
499 proof goal. The proof is valid if the proof of any term is valid.
500 If validity cannot be determined, but any particular
501 check was undecided, then this goal is undecided. */
504 check_goal (proof_goal
& g
)
506 term_list::iterator iter
= g
.conclusions
.begin ();
507 term_list::iterator end
= g
.conclusions
.end ();
508 bool incomplete
= false;
511 proof_result r
= check_term (g
.assumptions
, *iter
);
519 /* Was the proof complete? */
526 /* Check if the the proof is valid. This is the case when all
527 goals can be discharged. If any goal is invalid, then the
528 entire proof is invalid. Otherwise, the proof is undecided. */
531 check_proof (proof_state
& p
)
533 proof_state::iterator iter
= p
.begin();
534 proof_state::iterator end
= p
.end();
537 proof_result r
= check_goal (*iter
);
541 iter
= p
.discharge (iter
);
546 /* If all goals are discharged, then the proof is valid. */
553 /*---------------------------------------------------------------------------
555 ---------------------------------------------------------------------------*/
558 load_check_assumption (term_list
& ts
, term_list::iterator i
)
560 tree decl
= CHECK_CONSTR_CONCEPT (*i
);
561 tree tmpl
= DECL_TI_TEMPLATE (decl
);
562 tree args
= CHECK_CONSTR_ARGS (*i
);
563 return ts
.replace(i
, expand_concept (tmpl
, args
));
567 load_parameterized_assumption (term_list
& ts
, term_list::iterator i
)
569 return ts
.replace(i
, PARM_CONSTR_OPERAND(*i
));
573 load_conjunction_assumption (term_list
& ts
, term_list::iterator i
)
575 tree t1
= TREE_OPERAND (*i
, 0);
576 tree t2
= TREE_OPERAND (*i
, 1);
577 return ts
.replace(i
, t1
, t2
);
580 /* Examine the terms in the list, and apply left-logical rules to move
581 terms into the set of assumptions. */
584 load_assumptions (proof_goal
& g
)
586 term_list::iterator iter
= g
.assumptions
.begin();
587 term_list::iterator end
= g
.assumptions
.end();
590 switch (TREE_CODE (*iter
))
593 iter
= load_check_assumption (g
.assumptions
, iter
);
596 iter
= load_parameterized_assumption (g
.assumptions
, iter
);
599 iter
= load_conjunction_assumption (g
.assumptions
, iter
);
608 /* In each subgoal, load constraints into the assumption set. */
611 load_assumptions(proof_state
& p
)
613 proof_state::iterator iter
= p
.begin();
614 while (iter
!= p
.end())
616 load_assumptions (*iter
);
622 explode_disjunction (proof_state
& p
, proof_state::iterator gi
, term_list::iterator ti1
)
624 tree t1
= TREE_OPERAND (*ti1
, 0);
625 tree t2
= TREE_OPERAND (*ti1
, 1);
627 /* Erase the current term from the goal. */
628 proof_goal
& g1
= *gi
;
629 proof_goal
& g2
= *p
.branch (gi
);
631 /* Get an iterator to the equivalent position in th enew goal. */
632 int n
= std::distance (g1
.assumptions
.begin (), ti1
);
633 term_list::iterator ti2
= g2
.assumptions
.begin ();
634 std::advance (ti2
, n
);
636 /* Replace the disjunction in both branches. */
637 g1
.assumptions
.replace (ti1
, t1
);
638 g2
.assumptions
.replace (ti2
, t2
);
642 /* Search the assumptions of the goal for the first disjunction. */
645 explode_goal (proof_state
& p
, proof_state::iterator gi
)
647 term_list
& ts
= gi
->assumptions
;
648 term_list::iterator ti
= ts
.begin();
649 term_list::iterator end
= ts
.end();
652 if (TREE_CODE (*ti
) == DISJ_CONSTR
)
654 explode_disjunction (p
, gi
, ti
);
662 /* Search for the first goal with a disjunction, and then branch
663 creating a clone of that subgoal. */
666 explode_assumptions (proof_state
& p
)
668 proof_state::iterator iter
= p
.begin();
669 proof_state::iterator end
= p
.end();
672 if (explode_goal (p
, iter
))
679 /*---------------------------------------------------------------------------
681 ---------------------------------------------------------------------------*/
684 load_disjunction_conclusion (term_list
& g
, term_list::iterator i
)
686 tree t1
= TREE_OPERAND (*i
, 0);
687 tree t2
= TREE_OPERAND (*i
, 1);
688 return g
.replace(i
, t1
, t2
);
691 /* Apply logical rules to the right hand side. This will load the
692 conclusion set with all tpp-level disjunctions. */
695 load_conclusions (proof_goal
& g
)
697 term_list::iterator iter
= g
.conclusions
.begin();
698 term_list::iterator end
= g
.conclusions
.end();
701 if (TREE_CODE (*iter
) == DISJ_CONSTR
)
702 iter
= load_disjunction_conclusion (g
.conclusions
, iter
);
709 load_conclusions (proof_state
& p
)
711 proof_state::iterator iter
= p
.begin();
712 while (iter
!= p
.end())
714 load_conclusions (*iter
);
720 /*---------------------------------------------------------------------------
721 High-level proof tactics
722 ---------------------------------------------------------------------------*/
724 /* Given two constraints A and C, try to derive a proof that
728 prove_implication (tree a
, tree c
)
731 if (cp_tree_equal (a
, c
))
734 /* Build the initial proof state. */
736 proof_goal
& goal
= proof
.front();
737 goal
.assumptions
.push_back(a
);
738 goal
.conclusions
.push_back(c
);
740 /* Perform an initial right-expansion in the off-chance that the right
741 hand side contains disjunctions. */
742 load_conclusions (proof
);
744 int step_max
= 1 << 10;
745 int step_count
= 0; /* FIXME: We shouldn't have this. */
746 std::size_t branch_limit
= 1024; /* FIXME: This needs to be configurable. */
747 while (step_count
< step_max
&& proof
.size() < branch_limit
)
749 /* Determine if we can prove that the assumptions entail the
750 conclusions. If so, we're done. */
751 load_assumptions (proof
);
753 /* Can we solve the proof based on this? */
754 proof_result r
= check_proof (proof
);
758 /* If not, then we need to dig into disjunctions. */
759 explode_assumptions (proof
);
764 if (step_count
== step_max
)
765 error ("subsumption failed to resolve");
767 if (proof
.size() == branch_limit
)
768 error ("exceeded maximum number of branches");
773 /* Returns true if the LEFT constraint subsume the RIGHT constraints.
774 This is done by deriving a proof of the conclusions on the RIGHT
775 from the assumptions on the LEFT assumptions. */
778 subsumes_constraints_nonnull (tree left
, tree right
)
780 gcc_assert (check_constraint_info (left
));
781 gcc_assert (check_constraint_info (right
));
783 auto_timevar
time (TV_CONSTRAINT_SUB
);
784 tree a
= CI_ASSOCIATED_CONSTRAINTS (left
);
785 tree c
= CI_ASSOCIATED_CONSTRAINTS (right
);
786 return prove_implication (a
, c
);
791 /* Returns true if the LEFT constraints subsume the RIGHT
795 subsumes (tree left
, tree right
)
803 return subsumes_constraints_nonnull (left
, right
);