1*38fd1498Szrj /* Derivation and subsumption rules for constraints.
2*38fd1498Szrj Copyright (C) 2013-2018 Free Software Foundation, Inc.
3*38fd1498Szrj Contributed by Andrew Sutton (andrew.n.sutton@gmail.com)
4*38fd1498Szrj
5*38fd1498Szrj This file is part of GCC.
6*38fd1498Szrj
7*38fd1498Szrj GCC is free software; you can redistribute it and/or modify
8*38fd1498Szrj it under the terms of the GNU General Public License as published by
9*38fd1498Szrj the Free Software Foundation; either version 3, or (at your option)
10*38fd1498Szrj any later version.
11*38fd1498Szrj
12*38fd1498Szrj GCC is distributed in the hope that it will be useful,
13*38fd1498Szrj but WITHOUT ANY WARRANTY; without even the implied warranty of
14*38fd1498Szrj MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15*38fd1498Szrj GNU General Public License for more details.
16*38fd1498Szrj
17*38fd1498Szrj You should have received a copy of the GNU General Public License
18*38fd1498Szrj along with GCC; see the file COPYING3. If not see
19*38fd1498Szrj <http://www.gnu.org/licenses/>. */
20*38fd1498Szrj
21*38fd1498Szrj #include "config.h"
22*38fd1498Szrj #define INCLUDE_LIST
23*38fd1498Szrj #include "system.h"
24*38fd1498Szrj #include "coretypes.h"
25*38fd1498Szrj #include "tm.h"
26*38fd1498Szrj #include "timevar.h"
27*38fd1498Szrj #include "hash-set.h"
28*38fd1498Szrj #include "machmode.h"
29*38fd1498Szrj #include "vec.h"
30*38fd1498Szrj #include "double-int.h"
31*38fd1498Szrj #include "input.h"
32*38fd1498Szrj #include "alias.h"
33*38fd1498Szrj #include "symtab.h"
34*38fd1498Szrj #include "wide-int.h"
35*38fd1498Szrj #include "inchash.h"
36*38fd1498Szrj #include "tree.h"
37*38fd1498Szrj #include "stringpool.h"
38*38fd1498Szrj #include "attribs.h"
39*38fd1498Szrj #include "intl.h"
40*38fd1498Szrj #include "flags.h"
41*38fd1498Szrj #include "cp-tree.h"
42*38fd1498Szrj #include "c-family/c-common.h"
43*38fd1498Szrj #include "c-family/c-objc.h"
44*38fd1498Szrj #include "cp-objcp-common.h"
45*38fd1498Szrj #include "tree-inline.h"
46*38fd1498Szrj #include "decl.h"
47*38fd1498Szrj #include "toplev.h"
48*38fd1498Szrj #include "type-utils.h"
49*38fd1498Szrj
50*38fd1498Szrj namespace {
51*38fd1498Szrj
52*38fd1498Szrj // Helper algorithms
53*38fd1498Szrj
54*38fd1498Szrj template<typename I>
55*38fd1498Szrj inline I
next(I iter)56*38fd1498Szrj next (I iter)
57*38fd1498Szrj {
58*38fd1498Szrj return ++iter;
59*38fd1498Szrj }
60*38fd1498Szrj
61*38fd1498Szrj template<typename I, typename P>
62*38fd1498Szrj inline bool
any_p(I first,I last,P pred)63*38fd1498Szrj any_p (I first, I last, P pred)
64*38fd1498Szrj {
65*38fd1498Szrj while (first != last)
66*38fd1498Szrj {
67*38fd1498Szrj if (pred(*first))
68*38fd1498Szrj return true;
69*38fd1498Szrj ++first;
70*38fd1498Szrj }
71*38fd1498Szrj return false;
72*38fd1498Szrj }
73*38fd1498Szrj
74*38fd1498Szrj bool prove_implication (tree, tree);
75*38fd1498Szrj
76*38fd1498Szrj /*---------------------------------------------------------------------------
77*38fd1498Szrj Proof state
78*38fd1498Szrj ---------------------------------------------------------------------------*/
79*38fd1498Szrj
80*38fd1498Szrj struct term_entry
81*38fd1498Szrj {
82*38fd1498Szrj tree t;
83*38fd1498Szrj };
84*38fd1498Szrj
85*38fd1498Szrj /* Hashing function and equality for constraint entries. */
86*38fd1498Szrj
87*38fd1498Szrj struct term_hasher : ggc_ptr_hash<term_entry>
88*38fd1498Szrj {
hash__anon26caefdf0111::term_hasher89*38fd1498Szrj static hashval_t hash (term_entry *e)
90*38fd1498Szrj {
91*38fd1498Szrj return iterative_hash_template_arg (e->t, 0);
92*38fd1498Szrj }
93*38fd1498Szrj
equal__anon26caefdf0111::term_hasher94*38fd1498Szrj static bool equal (term_entry *e1, term_entry *e2)
95*38fd1498Szrj {
96*38fd1498Szrj return cp_tree_equal (e1->t, e2->t);
97*38fd1498Szrj }
98*38fd1498Szrj };
99*38fd1498Szrj
100*38fd1498Szrj /* A term list is a list of atomic constraints. It is used
101*38fd1498Szrj to maintain the lists of assumptions and conclusions in a
102*38fd1498Szrj proof goal.
103*38fd1498Szrj
104*38fd1498Szrj Each term list maintains an iterator that refers to the current
105*38fd1498Szrj term. This can be used by various tactics to support iteration
106*38fd1498Szrj and stateful manipulation of the list. */
107*38fd1498Szrj struct term_list
108*38fd1498Szrj {
109*38fd1498Szrj typedef std::list<tree>::iterator iterator;
110*38fd1498Szrj
111*38fd1498Szrj term_list ();
112*38fd1498Szrj term_list (tree);
113*38fd1498Szrj
114*38fd1498Szrj bool includes (tree);
115*38fd1498Szrj iterator insert (iterator, tree);
116*38fd1498Szrj iterator push_back (tree);
117*38fd1498Szrj iterator erase (iterator);
118*38fd1498Szrj iterator replace (iterator, tree);
119*38fd1498Szrj iterator replace (iterator, tree, tree);
120*38fd1498Szrj
begin__anon26caefdf0111::term_list121*38fd1498Szrj iterator begin() { return seq.begin(); }
end__anon26caefdf0111::term_list122*38fd1498Szrj iterator end() { return seq.end(); }
123*38fd1498Szrj
124*38fd1498Szrj std::list<tree> seq;
125*38fd1498Szrj hash_table<term_hasher> tab;
126*38fd1498Szrj };
127*38fd1498Szrj
128*38fd1498Szrj inline
term_list()129*38fd1498Szrj term_list::term_list ()
130*38fd1498Szrj : seq(), tab (11)
131*38fd1498Szrj {
132*38fd1498Szrj }
133*38fd1498Szrj
134*38fd1498Szrj /* Initialize a term list with an initial term. */
135*38fd1498Szrj
136*38fd1498Szrj inline
term_list(tree t)137*38fd1498Szrj term_list::term_list (tree t)
138*38fd1498Szrj : seq (), tab (11)
139*38fd1498Szrj {
140*38fd1498Szrj push_back (t);
141*38fd1498Szrj }
142*38fd1498Szrj
143*38fd1498Szrj /* Returns true if T is the in the tree. */
144*38fd1498Szrj
145*38fd1498Szrj inline bool
includes(tree t)146*38fd1498Szrj term_list::includes (tree t)
147*38fd1498Szrj {
148*38fd1498Szrj term_entry ent = {t};
149*38fd1498Szrj return tab.find (&ent);
150*38fd1498Szrj }
151*38fd1498Szrj
152*38fd1498Szrj /* Append a term to the list. */
153*38fd1498Szrj inline term_list::iterator
push_back(tree t)154*38fd1498Szrj term_list::push_back (tree t)
155*38fd1498Szrj {
156*38fd1498Szrj return insert (end(), t);
157*38fd1498Szrj }
158*38fd1498Szrj
159*38fd1498Szrj /* Insert a new (unseen) term T into the list before the proposition
160*38fd1498Szrj indicated by ITER. Returns the iterator to the newly inserted
161*38fd1498Szrj element. */
162*38fd1498Szrj
163*38fd1498Szrj term_list::iterator
insert(iterator iter,tree t)164*38fd1498Szrj term_list::insert (iterator iter, tree t)
165*38fd1498Szrj {
166*38fd1498Szrj gcc_assert (!includes (t));
167*38fd1498Szrj iter = seq.insert (iter, t);
168*38fd1498Szrj term_entry ent = {t};
169*38fd1498Szrj term_entry** slot = tab.find_slot (&ent, INSERT);
170*38fd1498Szrj term_entry* ptr = ggc_alloc<term_entry> ();
171*38fd1498Szrj *ptr = ent;
172*38fd1498Szrj *slot = ptr;
173*38fd1498Szrj return iter;
174*38fd1498Szrj }
175*38fd1498Szrj
176*38fd1498Szrj /* Remove an existing term from the list. Returns an iterator referring
177*38fd1498Szrj to the element after the removed term. This may be end(). */
178*38fd1498Szrj
179*38fd1498Szrj term_list::iterator
erase(iterator iter)180*38fd1498Szrj term_list::erase (iterator iter)
181*38fd1498Szrj {
182*38fd1498Szrj gcc_assert (includes (*iter));
183*38fd1498Szrj term_entry ent = {*iter};
184*38fd1498Szrj tab.remove_elt (&ent);
185*38fd1498Szrj iter = seq.erase (iter);
186*38fd1498Szrj return iter;
187*38fd1498Szrj }
188*38fd1498Szrj
189*38fd1498Szrj /* Replace the given term with that specified. If the term has
190*38fd1498Szrj been previously seen, do not insert the term. Returns the
191*38fd1498Szrj first iterator past the current term. */
192*38fd1498Szrj
193*38fd1498Szrj term_list::iterator
replace(iterator iter,tree t)194*38fd1498Szrj term_list::replace (iterator iter, tree t)
195*38fd1498Szrj {
196*38fd1498Szrj iter = erase (iter);
197*38fd1498Szrj if (!includes (t))
198*38fd1498Szrj insert (iter, t);
199*38fd1498Szrj return iter;
200*38fd1498Szrj }
201*38fd1498Szrj
202*38fd1498Szrj
203*38fd1498Szrj /* Replace the term at the given position by the supplied T1
204*38fd1498Szrj followed by t2. This is used in certain logical operators to
205*38fd1498Szrj load a list of assumptions or conclusions. */
206*38fd1498Szrj
207*38fd1498Szrj term_list::iterator
replace(iterator iter,tree t1,tree t2)208*38fd1498Szrj term_list::replace (iterator iter, tree t1, tree t2)
209*38fd1498Szrj {
210*38fd1498Szrj iter = erase (iter);
211*38fd1498Szrj if (!includes (t1))
212*38fd1498Szrj insert (iter, t1);
213*38fd1498Szrj if (!includes (t2))
214*38fd1498Szrj insert (iter, t2);
215*38fd1498Szrj return iter;
216*38fd1498Szrj }
217*38fd1498Szrj
218*38fd1498Szrj /* A goal (or subgoal) models a sequent of the form
219*38fd1498Szrj 'A |- C' where A and C are lists of assumptions and
220*38fd1498Szrj conclusions written as propositions in the constraint
221*38fd1498Szrj language (i.e., lists of trees). */
222*38fd1498Szrj
223*38fd1498Szrj struct proof_goal
224*38fd1498Szrj {
225*38fd1498Szrj term_list assumptions;
226*38fd1498Szrj term_list conclusions;
227*38fd1498Szrj };
228*38fd1498Szrj
229*38fd1498Szrj /* A proof state owns a list of goals and tracks the
230*38fd1498Szrj current sub-goal. The class also provides facilities
231*38fd1498Szrj for managing subgoals and constructing term lists. */
232*38fd1498Szrj
233*38fd1498Szrj struct proof_state : std::list<proof_goal>
234*38fd1498Szrj {
235*38fd1498Szrj proof_state ();
236*38fd1498Szrj
237*38fd1498Szrj iterator branch (iterator i);
238*38fd1498Szrj iterator discharge (iterator i);
239*38fd1498Szrj };
240*38fd1498Szrj
241*38fd1498Szrj /* Initialize the state with a single empty goal, and set that goal
242*38fd1498Szrj as the current subgoal. */
243*38fd1498Szrj
244*38fd1498Szrj inline
proof_state()245*38fd1498Szrj proof_state::proof_state ()
246*38fd1498Szrj : std::list<proof_goal> (1)
247*38fd1498Szrj { }
248*38fd1498Szrj
249*38fd1498Szrj
250*38fd1498Szrj /* Branch the current goal by creating a new subgoal, returning a
251*38fd1498Szrj reference to the new object. This does not update the current goal. */
252*38fd1498Szrj
253*38fd1498Szrj inline proof_state::iterator
branch(iterator i)254*38fd1498Szrj proof_state::branch (iterator i)
255*38fd1498Szrj {
256*38fd1498Szrj gcc_assert (i != end());
257*38fd1498Szrj proof_goal& g = *i;
258*38fd1498Szrj return insert (++i, g);
259*38fd1498Szrj }
260*38fd1498Szrj
261*38fd1498Szrj /* Discharge the current goal, setting it equal to the
262*38fd1498Szrj next non-satisfied goal. */
263*38fd1498Szrj
264*38fd1498Szrj inline proof_state::iterator
discharge(iterator i)265*38fd1498Szrj proof_state::discharge (iterator i)
266*38fd1498Szrj {
267*38fd1498Szrj gcc_assert (i != end());
268*38fd1498Szrj return erase (i);
269*38fd1498Szrj }
270*38fd1498Szrj
271*38fd1498Szrj
272*38fd1498Szrj /*---------------------------------------------------------------------------
273*38fd1498Szrj Debugging
274*38fd1498Szrj ---------------------------------------------------------------------------*/
275*38fd1498Szrj
276*38fd1498Szrj // void
277*38fd1498Szrj // debug (term_list& ts)
278*38fd1498Szrj // {
279*38fd1498Szrj // for (term_list::iterator i = ts.begin(); i != ts.end(); ++i)
280*38fd1498Szrj // verbatim (" # %E", *i);
281*38fd1498Szrj // }
282*38fd1498Szrj //
283*38fd1498Szrj // void
284*38fd1498Szrj // debug (proof_goal& g)
285*38fd1498Szrj // {
286*38fd1498Szrj // debug (g.assumptions);
287*38fd1498Szrj // verbatim (" |-");
288*38fd1498Szrj // debug (g.conclusions);
289*38fd1498Szrj // }
290*38fd1498Szrj
291*38fd1498Szrj /*---------------------------------------------------------------------------
292*38fd1498Szrj Atomicity of constraints
293*38fd1498Szrj ---------------------------------------------------------------------------*/
294*38fd1498Szrj
295*38fd1498Szrj /* Returns true if T is not an atomic constraint. */
296*38fd1498Szrj
297*38fd1498Szrj bool
non_atomic_constraint_p(tree t)298*38fd1498Szrj non_atomic_constraint_p (tree t)
299*38fd1498Szrj {
300*38fd1498Szrj switch (TREE_CODE (t))
301*38fd1498Szrj {
302*38fd1498Szrj case PRED_CONSTR:
303*38fd1498Szrj case EXPR_CONSTR:
304*38fd1498Szrj case TYPE_CONSTR:
305*38fd1498Szrj case ICONV_CONSTR:
306*38fd1498Szrj case DEDUCT_CONSTR:
307*38fd1498Szrj case EXCEPT_CONSTR:
308*38fd1498Szrj /* A pack expansion isn't atomic, but it can't decompose to prove an
309*38fd1498Szrj atom, so it shouldn't cause analyze_atom to return undecided. */
310*38fd1498Szrj case EXPR_PACK_EXPANSION:
311*38fd1498Szrj return false;
312*38fd1498Szrj case CHECK_CONSTR:
313*38fd1498Szrj case PARM_CONSTR:
314*38fd1498Szrj case CONJ_CONSTR:
315*38fd1498Szrj case DISJ_CONSTR:
316*38fd1498Szrj return true;
317*38fd1498Szrj default:
318*38fd1498Szrj gcc_unreachable ();
319*38fd1498Szrj }
320*38fd1498Szrj }
321*38fd1498Szrj
322*38fd1498Szrj /* Returns true if any constraints in T are not atomic. */
323*38fd1498Szrj
324*38fd1498Szrj bool
any_non_atomic_constraints_p(term_list & t)325*38fd1498Szrj any_non_atomic_constraints_p (term_list& t)
326*38fd1498Szrj {
327*38fd1498Szrj return any_p (t.begin(), t.end(), non_atomic_constraint_p);
328*38fd1498Szrj }
329*38fd1498Szrj
330*38fd1498Szrj /*---------------------------------------------------------------------------
331*38fd1498Szrj Proof validations
332*38fd1498Szrj ---------------------------------------------------------------------------*/
333*38fd1498Szrj
334*38fd1498Szrj enum proof_result
335*38fd1498Szrj {
336*38fd1498Szrj invalid,
337*38fd1498Szrj valid,
338*38fd1498Szrj undecided
339*38fd1498Szrj };
340*38fd1498Szrj
341*38fd1498Szrj proof_result check_term (term_list&, tree);
342*38fd1498Szrj
343*38fd1498Szrj
344*38fd1498Szrj proof_result
analyze_atom(term_list & ts,tree t)345*38fd1498Szrj analyze_atom (term_list& ts, tree t)
346*38fd1498Szrj {
347*38fd1498Szrj /* FIXME: Hook into special cases, if any. */
348*38fd1498Szrj /*
349*38fd1498Szrj term_list::iterator iter = ts.begin();
350*38fd1498Szrj term_list::iterator end = ts.end();
351*38fd1498Szrj while (iter != end)
352*38fd1498Szrj {
353*38fd1498Szrj ++iter;
354*38fd1498Szrj }
355*38fd1498Szrj */
356*38fd1498Szrj
357*38fd1498Szrj if (non_atomic_constraint_p (t))
358*38fd1498Szrj return undecided;
359*38fd1498Szrj if (any_non_atomic_constraints_p (ts))
360*38fd1498Szrj return undecided;
361*38fd1498Szrj return invalid;
362*38fd1498Szrj }
363*38fd1498Szrj
364*38fd1498Szrj /* Search for a pack expansion in the list of assumptions that would
365*38fd1498Szrj make this expansion valid. */
366*38fd1498Szrj
367*38fd1498Szrj proof_result
analyze_pack(term_list & ts,tree t)368*38fd1498Szrj analyze_pack (term_list& ts, tree t)
369*38fd1498Szrj {
370*38fd1498Szrj tree c1 = normalize_expression (PACK_EXPANSION_PATTERN (t));
371*38fd1498Szrj term_list::iterator iter = ts.begin();
372*38fd1498Szrj term_list::iterator end = ts.end();
373*38fd1498Szrj while (iter != end)
374*38fd1498Szrj {
375*38fd1498Szrj if (TREE_CODE (*iter) == TREE_CODE (t))
376*38fd1498Szrj {
377*38fd1498Szrj tree c2 = normalize_expression (PACK_EXPANSION_PATTERN (*iter));
378*38fd1498Szrj if (prove_implication (c2, c1))
379*38fd1498Szrj return valid;
380*38fd1498Szrj else
381*38fd1498Szrj return invalid;
382*38fd1498Szrj }
383*38fd1498Szrj ++iter;
384*38fd1498Szrj }
385*38fd1498Szrj return invalid;
386*38fd1498Szrj }
387*38fd1498Szrj
388*38fd1498Szrj /* Search for concept checks in TS that we know subsume T. */
389*38fd1498Szrj
390*38fd1498Szrj proof_result
search_known_subsumptions(term_list & ts,tree t)391*38fd1498Szrj search_known_subsumptions (term_list& ts, tree t)
392*38fd1498Szrj {
393*38fd1498Szrj for (term_list::iterator i = ts.begin(); i != ts.end(); ++i)
394*38fd1498Szrj if (TREE_CODE (*i) == CHECK_CONSTR)
395*38fd1498Szrj {
396*38fd1498Szrj if (bool* b = lookup_subsumption_result (*i, t))
397*38fd1498Szrj return *b ? valid : invalid;
398*38fd1498Szrj }
399*38fd1498Szrj return undecided;
400*38fd1498Szrj }
401*38fd1498Szrj
402*38fd1498Szrj /* Determine if the terms in TS provide sufficient support for proving
403*38fd1498Szrj the proposition T. If any term in TS is a concept check that is known
404*38fd1498Szrj to subsume T, then the proof is valid. Otherwise, we have to expand T
405*38fd1498Szrj and continue searching for support. */
406*38fd1498Szrj
407*38fd1498Szrj proof_result
analyze_check(term_list & ts,tree t)408*38fd1498Szrj analyze_check (term_list& ts, tree t)
409*38fd1498Szrj {
410*38fd1498Szrj proof_result r = search_known_subsumptions (ts, t);
411*38fd1498Szrj if (r != undecided)
412*38fd1498Szrj return r;
413*38fd1498Szrj
414*38fd1498Szrj tree tmpl = CHECK_CONSTR_CONCEPT (t);
415*38fd1498Szrj tree args = CHECK_CONSTR_ARGS (t);
416*38fd1498Szrj tree c = expand_concept (tmpl, args);
417*38fd1498Szrj return check_term (ts, c);
418*38fd1498Szrj }
419*38fd1498Szrj
420*38fd1498Szrj /* Recursively check constraints of the parameterized constraint. */
421*38fd1498Szrj
422*38fd1498Szrj proof_result
analyze_parameterized(term_list & ts,tree t)423*38fd1498Szrj analyze_parameterized (term_list& ts, tree t)
424*38fd1498Szrj {
425*38fd1498Szrj return check_term (ts, PARM_CONSTR_OPERAND (t));
426*38fd1498Szrj }
427*38fd1498Szrj
428*38fd1498Szrj proof_result
analyze_conjunction(term_list & ts,tree t)429*38fd1498Szrj analyze_conjunction (term_list& ts, tree t)
430*38fd1498Szrj {
431*38fd1498Szrj proof_result r = check_term (ts, TREE_OPERAND (t, 0));
432*38fd1498Szrj if (r == invalid || r == undecided)
433*38fd1498Szrj return r;
434*38fd1498Szrj return check_term (ts, TREE_OPERAND (t, 1));
435*38fd1498Szrj }
436*38fd1498Szrj
437*38fd1498Szrj proof_result
analyze_disjunction(term_list & ts,tree t)438*38fd1498Szrj analyze_disjunction (term_list& ts, tree t)
439*38fd1498Szrj {
440*38fd1498Szrj proof_result r = check_term (ts, TREE_OPERAND (t, 0));
441*38fd1498Szrj if (r == valid)
442*38fd1498Szrj return r;
443*38fd1498Szrj return check_term (ts, TREE_OPERAND (t, 1));
444*38fd1498Szrj }
445*38fd1498Szrj
446*38fd1498Szrj proof_result
analyze_term(term_list & ts,tree t)447*38fd1498Szrj analyze_term (term_list& ts, tree t)
448*38fd1498Szrj {
449*38fd1498Szrj switch (TREE_CODE (t))
450*38fd1498Szrj {
451*38fd1498Szrj case CHECK_CONSTR:
452*38fd1498Szrj return analyze_check (ts, t);
453*38fd1498Szrj
454*38fd1498Szrj case PARM_CONSTR:
455*38fd1498Szrj return analyze_parameterized (ts, t);
456*38fd1498Szrj
457*38fd1498Szrj case CONJ_CONSTR:
458*38fd1498Szrj return analyze_conjunction (ts, t);
459*38fd1498Szrj case DISJ_CONSTR:
460*38fd1498Szrj return analyze_disjunction (ts, t);
461*38fd1498Szrj
462*38fd1498Szrj case PRED_CONSTR:
463*38fd1498Szrj case EXPR_CONSTR:
464*38fd1498Szrj case TYPE_CONSTR:
465*38fd1498Szrj case ICONV_CONSTR:
466*38fd1498Szrj case DEDUCT_CONSTR:
467*38fd1498Szrj case EXCEPT_CONSTR:
468*38fd1498Szrj return analyze_atom (ts, t);
469*38fd1498Szrj
470*38fd1498Szrj case EXPR_PACK_EXPANSION:
471*38fd1498Szrj return analyze_pack (ts, t);
472*38fd1498Szrj
473*38fd1498Szrj case ERROR_MARK:
474*38fd1498Szrj /* Encountering an error anywhere in a constraint invalidates
475*38fd1498Szrj the proof, since the constraint is ill-formed. */
476*38fd1498Szrj return invalid;
477*38fd1498Szrj default:
478*38fd1498Szrj gcc_unreachable ();
479*38fd1498Szrj }
480*38fd1498Szrj }
481*38fd1498Szrj
482*38fd1498Szrj /* Check if a single term can be proven from a set of assumptions.
483*38fd1498Szrj If the proof is not valid, then it is incomplete when either
484*38fd1498Szrj the given term is non-atomic or any term in the list of assumptions
485*38fd1498Szrj is not-atomic. */
486*38fd1498Szrj
487*38fd1498Szrj proof_result
check_term(term_list & ts,tree t)488*38fd1498Szrj check_term (term_list& ts, tree t)
489*38fd1498Szrj {
490*38fd1498Szrj /* Try the easy way; search for an equivalent term. */
491*38fd1498Szrj if (ts.includes (t))
492*38fd1498Szrj return valid;
493*38fd1498Szrj
494*38fd1498Szrj /* The hard way; actually consider what the term means. */
495*38fd1498Szrj return analyze_term (ts, t);
496*38fd1498Szrj }
497*38fd1498Szrj
498*38fd1498Szrj /* Check to see if any term is proven by the assumptions in the
499*38fd1498Szrj proof goal. The proof is valid if the proof of any term is valid.
500*38fd1498Szrj If validity cannot be determined, but any particular
501*38fd1498Szrj check was undecided, then this goal is undecided. */
502*38fd1498Szrj
503*38fd1498Szrj proof_result
check_goal(proof_goal & g)504*38fd1498Szrj check_goal (proof_goal& g)
505*38fd1498Szrj {
506*38fd1498Szrj term_list::iterator iter = g.conclusions.begin ();
507*38fd1498Szrj term_list::iterator end = g.conclusions.end ();
508*38fd1498Szrj bool incomplete = false;
509*38fd1498Szrj while (iter != end)
510*38fd1498Szrj {
511*38fd1498Szrj proof_result r = check_term (g.assumptions, *iter);
512*38fd1498Szrj if (r == valid)
513*38fd1498Szrj return r;
514*38fd1498Szrj if (r == undecided)
515*38fd1498Szrj incomplete = true;
516*38fd1498Szrj ++iter;
517*38fd1498Szrj }
518*38fd1498Szrj
519*38fd1498Szrj /* Was the proof complete? */
520*38fd1498Szrj if (incomplete)
521*38fd1498Szrj return undecided;
522*38fd1498Szrj else
523*38fd1498Szrj return invalid;
524*38fd1498Szrj }
525*38fd1498Szrj
526*38fd1498Szrj /* Check if the the proof is valid. This is the case when all
527*38fd1498Szrj goals can be discharged. If any goal is invalid, then the
528*38fd1498Szrj entire proof is invalid. Otherwise, the proof is undecided. */
529*38fd1498Szrj
530*38fd1498Szrj proof_result
check_proof(proof_state & p)531*38fd1498Szrj check_proof (proof_state& p)
532*38fd1498Szrj {
533*38fd1498Szrj proof_state::iterator iter = p.begin();
534*38fd1498Szrj proof_state::iterator end = p.end();
535*38fd1498Szrj while (iter != end)
536*38fd1498Szrj {
537*38fd1498Szrj proof_result r = check_goal (*iter);
538*38fd1498Szrj if (r == invalid)
539*38fd1498Szrj return r;
540*38fd1498Szrj if (r == valid)
541*38fd1498Szrj iter = p.discharge (iter);
542*38fd1498Szrj else
543*38fd1498Szrj ++iter;
544*38fd1498Szrj }
545*38fd1498Szrj
546*38fd1498Szrj /* If all goals are discharged, then the proof is valid. */
547*38fd1498Szrj if (p.empty())
548*38fd1498Szrj return valid;
549*38fd1498Szrj else
550*38fd1498Szrj return undecided;
551*38fd1498Szrj }
552*38fd1498Szrj
553*38fd1498Szrj /*---------------------------------------------------------------------------
554*38fd1498Szrj Left logical rules
555*38fd1498Szrj ---------------------------------------------------------------------------*/
556*38fd1498Szrj
557*38fd1498Szrj term_list::iterator
load_check_assumption(term_list & ts,term_list::iterator i)558*38fd1498Szrj load_check_assumption (term_list& ts, term_list::iterator i)
559*38fd1498Szrj {
560*38fd1498Szrj tree decl = CHECK_CONSTR_CONCEPT (*i);
561*38fd1498Szrj tree tmpl = DECL_TI_TEMPLATE (decl);
562*38fd1498Szrj tree args = CHECK_CONSTR_ARGS (*i);
563*38fd1498Szrj return ts.replace(i, expand_concept (tmpl, args));
564*38fd1498Szrj }
565*38fd1498Szrj
566*38fd1498Szrj term_list::iterator
load_parameterized_assumption(term_list & ts,term_list::iterator i)567*38fd1498Szrj load_parameterized_assumption (term_list& ts, term_list::iterator i)
568*38fd1498Szrj {
569*38fd1498Szrj return ts.replace(i, PARM_CONSTR_OPERAND(*i));
570*38fd1498Szrj }
571*38fd1498Szrj
572*38fd1498Szrj term_list::iterator
load_conjunction_assumption(term_list & ts,term_list::iterator i)573*38fd1498Szrj load_conjunction_assumption (term_list& ts, term_list::iterator i)
574*38fd1498Szrj {
575*38fd1498Szrj tree t1 = TREE_OPERAND (*i, 0);
576*38fd1498Szrj tree t2 = TREE_OPERAND (*i, 1);
577*38fd1498Szrj return ts.replace(i, t1, t2);
578*38fd1498Szrj }
579*38fd1498Szrj
580*38fd1498Szrj /* Examine the terms in the list, and apply left-logical rules to move
581*38fd1498Szrj terms into the set of assumptions. */
582*38fd1498Szrj
583*38fd1498Szrj void
load_assumptions(proof_goal & g)584*38fd1498Szrj load_assumptions (proof_goal& g)
585*38fd1498Szrj {
586*38fd1498Szrj term_list::iterator iter = g.assumptions.begin();
587*38fd1498Szrj term_list::iterator end = g.assumptions.end();
588*38fd1498Szrj while (iter != end)
589*38fd1498Szrj {
590*38fd1498Szrj switch (TREE_CODE (*iter))
591*38fd1498Szrj {
592*38fd1498Szrj case CHECK_CONSTR:
593*38fd1498Szrj iter = load_check_assumption (g.assumptions, iter);
594*38fd1498Szrj break;
595*38fd1498Szrj case PARM_CONSTR:
596*38fd1498Szrj iter = load_parameterized_assumption (g.assumptions, iter);
597*38fd1498Szrj break;
598*38fd1498Szrj case CONJ_CONSTR:
599*38fd1498Szrj iter = load_conjunction_assumption (g.assumptions, iter);
600*38fd1498Szrj break;
601*38fd1498Szrj default:
602*38fd1498Szrj ++iter;
603*38fd1498Szrj break;
604*38fd1498Szrj }
605*38fd1498Szrj }
606*38fd1498Szrj }
607*38fd1498Szrj
608*38fd1498Szrj /* In each subgoal, load constraints into the assumption set. */
609*38fd1498Szrj
610*38fd1498Szrj void
load_assumptions(proof_state & p)611*38fd1498Szrj load_assumptions(proof_state& p)
612*38fd1498Szrj {
613*38fd1498Szrj proof_state::iterator iter = p.begin();
614*38fd1498Szrj while (iter != p.end())
615*38fd1498Szrj {
616*38fd1498Szrj load_assumptions (*iter);
617*38fd1498Szrj ++iter;
618*38fd1498Szrj }
619*38fd1498Szrj }
620*38fd1498Szrj
621*38fd1498Szrj void
explode_disjunction(proof_state & p,proof_state::iterator gi,term_list::iterator ti1)622*38fd1498Szrj explode_disjunction (proof_state& p, proof_state::iterator gi, term_list::iterator ti1)
623*38fd1498Szrj {
624*38fd1498Szrj tree t1 = TREE_OPERAND (*ti1, 0);
625*38fd1498Szrj tree t2 = TREE_OPERAND (*ti1, 1);
626*38fd1498Szrj
627*38fd1498Szrj /* Erase the current term from the goal. */
628*38fd1498Szrj proof_goal& g1 = *gi;
629*38fd1498Szrj proof_goal& g2 = *p.branch (gi);
630*38fd1498Szrj
631*38fd1498Szrj /* Get an iterator to the equivalent position in th enew goal. */
632*38fd1498Szrj int n = std::distance (g1.assumptions.begin (), ti1);
633*38fd1498Szrj term_list::iterator ti2 = g2.assumptions.begin ();
634*38fd1498Szrj std::advance (ti2, n);
635*38fd1498Szrj
636*38fd1498Szrj /* Replace the disjunction in both branches. */
637*38fd1498Szrj g1.assumptions.replace (ti1, t1);
638*38fd1498Szrj g2.assumptions.replace (ti2, t2);
639*38fd1498Szrj }
640*38fd1498Szrj
641*38fd1498Szrj
642*38fd1498Szrj /* Search the assumptions of the goal for the first disjunction. */
643*38fd1498Szrj
644*38fd1498Szrj bool
explode_goal(proof_state & p,proof_state::iterator gi)645*38fd1498Szrj explode_goal (proof_state& p, proof_state::iterator gi)
646*38fd1498Szrj {
647*38fd1498Szrj term_list& ts = gi->assumptions;
648*38fd1498Szrj term_list::iterator ti = ts.begin();
649*38fd1498Szrj term_list::iterator end = ts.end();
650*38fd1498Szrj while (ti != end)
651*38fd1498Szrj {
652*38fd1498Szrj if (TREE_CODE (*ti) == DISJ_CONSTR)
653*38fd1498Szrj {
654*38fd1498Szrj explode_disjunction (p, gi, ti);
655*38fd1498Szrj return true;
656*38fd1498Szrj }
657*38fd1498Szrj else ++ti;
658*38fd1498Szrj }
659*38fd1498Szrj return false;
660*38fd1498Szrj }
661*38fd1498Szrj
662*38fd1498Szrj /* Search for the first goal with a disjunction, and then branch
663*38fd1498Szrj creating a clone of that subgoal. */
664*38fd1498Szrj
665*38fd1498Szrj void
explode_assumptions(proof_state & p)666*38fd1498Szrj explode_assumptions (proof_state& p)
667*38fd1498Szrj {
668*38fd1498Szrj proof_state::iterator iter = p.begin();
669*38fd1498Szrj proof_state::iterator end = p.end();
670*38fd1498Szrj while (iter != end)
671*38fd1498Szrj {
672*38fd1498Szrj if (explode_goal (p, iter))
673*38fd1498Szrj return;
674*38fd1498Szrj ++iter;
675*38fd1498Szrj }
676*38fd1498Szrj }
677*38fd1498Szrj
678*38fd1498Szrj
679*38fd1498Szrj /*---------------------------------------------------------------------------
680*38fd1498Szrj Right logical rules
681*38fd1498Szrj ---------------------------------------------------------------------------*/
682*38fd1498Szrj
683*38fd1498Szrj term_list::iterator
load_disjunction_conclusion(term_list & g,term_list::iterator i)684*38fd1498Szrj load_disjunction_conclusion (term_list& g, term_list::iterator i)
685*38fd1498Szrj {
686*38fd1498Szrj tree t1 = TREE_OPERAND (*i, 0);
687*38fd1498Szrj tree t2 = TREE_OPERAND (*i, 1);
688*38fd1498Szrj return g.replace(i, t1, t2);
689*38fd1498Szrj }
690*38fd1498Szrj
691*38fd1498Szrj /* Apply logical rules to the right hand side. This will load the
692*38fd1498Szrj conclusion set with all tpp-level disjunctions. */
693*38fd1498Szrj
694*38fd1498Szrj void
load_conclusions(proof_goal & g)695*38fd1498Szrj load_conclusions (proof_goal& g)
696*38fd1498Szrj {
697*38fd1498Szrj term_list::iterator iter = g.conclusions.begin();
698*38fd1498Szrj term_list::iterator end = g.conclusions.end();
699*38fd1498Szrj while (iter != end)
700*38fd1498Szrj {
701*38fd1498Szrj if (TREE_CODE (*iter) == DISJ_CONSTR)
702*38fd1498Szrj iter = load_disjunction_conclusion (g.conclusions, iter);
703*38fd1498Szrj else
704*38fd1498Szrj ++iter;
705*38fd1498Szrj }
706*38fd1498Szrj }
707*38fd1498Szrj
708*38fd1498Szrj void
load_conclusions(proof_state & p)709*38fd1498Szrj load_conclusions (proof_state& p)
710*38fd1498Szrj {
711*38fd1498Szrj proof_state::iterator iter = p.begin();
712*38fd1498Szrj while (iter != p.end())
713*38fd1498Szrj {
714*38fd1498Szrj load_conclusions (*iter);
715*38fd1498Szrj ++iter;
716*38fd1498Szrj }
717*38fd1498Szrj }
718*38fd1498Szrj
719*38fd1498Szrj
720*38fd1498Szrj /*---------------------------------------------------------------------------
721*38fd1498Szrj High-level proof tactics
722*38fd1498Szrj ---------------------------------------------------------------------------*/
723*38fd1498Szrj
724*38fd1498Szrj /* Given two constraints A and C, try to derive a proof that
725*38fd1498Szrj A implies C. */
726*38fd1498Szrj
727*38fd1498Szrj bool
prove_implication(tree a,tree c)728*38fd1498Szrj prove_implication (tree a, tree c)
729*38fd1498Szrj {
730*38fd1498Szrj /* Quick accept. */
731*38fd1498Szrj if (cp_tree_equal (a, c))
732*38fd1498Szrj return true;
733*38fd1498Szrj
734*38fd1498Szrj /* Build the initial proof state. */
735*38fd1498Szrj proof_state proof;
736*38fd1498Szrj proof_goal& goal = proof.front();
737*38fd1498Szrj goal.assumptions.push_back(a);
738*38fd1498Szrj goal.conclusions.push_back(c);
739*38fd1498Szrj
740*38fd1498Szrj /* Perform an initial right-expansion in the off-chance that the right
741*38fd1498Szrj hand side contains disjunctions. */
742*38fd1498Szrj load_conclusions (proof);
743*38fd1498Szrj
744*38fd1498Szrj int step_max = 1 << 10;
745*38fd1498Szrj int step_count = 0; /* FIXME: We shouldn't have this. */
746*38fd1498Szrj std::size_t branch_limit = 1024; /* FIXME: This needs to be configurable. */
747*38fd1498Szrj while (step_count < step_max && proof.size() < branch_limit)
748*38fd1498Szrj {
749*38fd1498Szrj /* Determine if we can prove that the assumptions entail the
750*38fd1498Szrj conclusions. If so, we're done. */
751*38fd1498Szrj load_assumptions (proof);
752*38fd1498Szrj
753*38fd1498Szrj /* Can we solve the proof based on this? */
754*38fd1498Szrj proof_result r = check_proof (proof);
755*38fd1498Szrj if (r != undecided)
756*38fd1498Szrj return r == valid;
757*38fd1498Szrj
758*38fd1498Szrj /* If not, then we need to dig into disjunctions. */
759*38fd1498Szrj explode_assumptions (proof);
760*38fd1498Szrj
761*38fd1498Szrj ++step_count;
762*38fd1498Szrj }
763*38fd1498Szrj
764*38fd1498Szrj if (step_count == step_max)
765*38fd1498Szrj error ("subsumption failed to resolve");
766*38fd1498Szrj
767*38fd1498Szrj if (proof.size() == branch_limit)
768*38fd1498Szrj error ("exceeded maximum number of branches");
769*38fd1498Szrj
770*38fd1498Szrj return false;
771*38fd1498Szrj }
772*38fd1498Szrj
773*38fd1498Szrj /* Returns true if the LEFT constraint subsume the RIGHT constraints.
774*38fd1498Szrj This is done by deriving a proof of the conclusions on the RIGHT
775*38fd1498Szrj from the assumptions on the LEFT assumptions. */
776*38fd1498Szrj
777*38fd1498Szrj bool
subsumes_constraints_nonnull(tree left,tree right)778*38fd1498Szrj subsumes_constraints_nonnull (tree left, tree right)
779*38fd1498Szrj {
780*38fd1498Szrj gcc_assert (check_constraint_info (left));
781*38fd1498Szrj gcc_assert (check_constraint_info (right));
782*38fd1498Szrj
783*38fd1498Szrj auto_timevar time (TV_CONSTRAINT_SUB);
784*38fd1498Szrj tree a = CI_ASSOCIATED_CONSTRAINTS (left);
785*38fd1498Szrj tree c = CI_ASSOCIATED_CONSTRAINTS (right);
786*38fd1498Szrj return prove_implication (a, c);
787*38fd1498Szrj }
788*38fd1498Szrj
789*38fd1498Szrj } /* namespace */
790*38fd1498Szrj
791*38fd1498Szrj /* Returns true if the LEFT constraints subsume the RIGHT
792*38fd1498Szrj constraints. */
793*38fd1498Szrj
794*38fd1498Szrj bool
subsumes(tree left,tree right)795*38fd1498Szrj subsumes (tree left, tree right)
796*38fd1498Szrj {
797*38fd1498Szrj if (left == right)
798*38fd1498Szrj return true;
799*38fd1498Szrj if (!left)
800*38fd1498Szrj return false;
801*38fd1498Szrj if (!right)
802*38fd1498Szrj return true;
803*38fd1498Szrj return subsumes_constraints_nonnull (left, right);
804*38fd1498Szrj }
805