11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Copyright (C) 2008 Dan Carpenter.
31f5207b7SJohn Levon  *
41f5207b7SJohn Levon  * This program is free software; you can redistribute it and/or
51f5207b7SJohn Levon  * modify it under the terms of the GNU General Public License
61f5207b7SJohn Levon  * as published by the Free Software Foundation; either version 2
71f5207b7SJohn Levon  * of the License, or (at your option) any later version.
81f5207b7SJohn Levon  *
91f5207b7SJohn Levon  * This program is distributed in the hope that it will be useful,
101f5207b7SJohn Levon  * but WITHOUT ANY WARRANTY; without even the implied warranty of
111f5207b7SJohn Levon  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
121f5207b7SJohn Levon  * GNU General Public License for more details.
131f5207b7SJohn Levon  *
141f5207b7SJohn Levon  * You should have received a copy of the GNU General Public License
151f5207b7SJohn Levon  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
167ae7577cSJohn Levon  *
177ae7577cSJohn Levon  * Copyright 2019 Joyent, Inc.
181f5207b7SJohn Levon  */
191f5207b7SJohn Levon 
201f5207b7SJohn Levon /*
211f5207b7SJohn Levon  * Imagine we have this code:
221f5207b7SJohn Levon  * foo = 1;
231f5207b7SJohn Levon  * if (bar)
241f5207b7SJohn Levon  *         foo = 99;
251f5207b7SJohn Levon  * else
261f5207b7SJohn Levon  *         frob();
271f5207b7SJohn Levon  *                   //  <-- point #1
281f5207b7SJohn Levon  * if (foo == 99)    //  <-- point #2
291f5207b7SJohn Levon  *         bar->baz; //  <-- point #3
301f5207b7SJohn Levon  *
311f5207b7SJohn Levon  *
321f5207b7SJohn Levon  * At point #3 bar is non null and can be dereferenced.
331f5207b7SJohn Levon  *
341f5207b7SJohn Levon  * It's smatch_implied.c which sets bar to non null at point #2.
351f5207b7SJohn Levon  *
361f5207b7SJohn Levon  * At point #1 merge_slist() stores the list of states from both
371f5207b7SJohn Levon  * the true and false paths.  On the true path foo == 99 and on
381f5207b7SJohn Levon  * the false path foo == 1.  merge_slist() sets their pool
391f5207b7SJohn Levon  * list to show the other states which were there when foo == 99.
401f5207b7SJohn Levon  *
411f5207b7SJohn Levon  * When it comes to the if (foo == 99) the smatch implied hook
421f5207b7SJohn Levon  * looks for all the pools where foo was not 99.  It makes a list
431f5207b7SJohn Levon  * of those.
441f5207b7SJohn Levon  *
451f5207b7SJohn Levon  * Then for bar (and all the other states) it says, ok bar is a
461f5207b7SJohn Levon  * merged state that came from these previous states.  We'll
471f5207b7SJohn Levon  * chop out all the states where it came from a pool where
481f5207b7SJohn Levon  * foo != 99 and merge it all back together.
491f5207b7SJohn Levon  *
501f5207b7SJohn Levon  * That is the implied state of bar.
511f5207b7SJohn Levon  *
521f5207b7SJohn Levon  * merge_slist() sets up ->pool.  An sm_state only has one ->pool and
531f5207b7SJohn Levon  *    that is the pool where it was first set.  The my pool gets set when
541f5207b7SJohn Levon  *    code paths merge.  States that have been set since the last merge do
551f5207b7SJohn Levon  *    not have a ->pool.
561f5207b7SJohn Levon  * merge_sm_state() sets ->left and ->right.  (These are the states which were
571f5207b7SJohn Levon  *    merged to form the current state.)
581f5207b7SJohn Levon  * a pool:  a pool is an slist that has been merged with another slist.
591f5207b7SJohn Levon  */
601f5207b7SJohn Levon 
611f5207b7SJohn Levon #include <time.h>
621f5207b7SJohn Levon #include "smatch.h"
631f5207b7SJohn Levon #include "smatch_slist.h"
641f5207b7SJohn Levon #include "smatch_extra.h"
651f5207b7SJohn Levon 
661f5207b7SJohn Levon char *implied_debug_msg;
671f5207b7SJohn Levon 
68efe51d0cSJohn Levon bool implications_off;
69efe51d0cSJohn Levon 
70efe51d0cSJohn Levon #define implied_debug 0
71efe51d0cSJohn Levon #define DIMPLIED(msg...) do { if (implied_debug) printf(msg); } while (0)
721f5207b7SJohn Levon 
debug_implied(void)73c85f09ccSJohn Levon bool debug_implied(void)
74c85f09ccSJohn Levon {
75*6523a3aaSJohn Levon 	if (option_debug)
76*6523a3aaSJohn Levon 		return true;
77c85f09ccSJohn Levon 	return implied_debug;
78c85f09ccSJohn Levon }
79c85f09ccSJohn Levon 
801f5207b7SJohn Levon /*
811f5207b7SJohn Levon  * tmp_range_list():
821f5207b7SJohn Levon  * It messes things up to free range list allocations.  This helper fuction
831f5207b7SJohn Levon  * lets us reuse memory instead of doing new allocations.
841f5207b7SJohn Levon  */
tmp_range_list(struct symbol * type,long long num)851f5207b7SJohn Levon static struct range_list *tmp_range_list(struct symbol *type, long long num)
861f5207b7SJohn Levon {
871f5207b7SJohn Levon 	static struct range_list *my_list = NULL;
881f5207b7SJohn Levon 	static struct data_range *my_range;
891f5207b7SJohn Levon 
901f5207b7SJohn Levon 	__free_ptr_list((struct ptr_list **)&my_list);
911f5207b7SJohn Levon 	my_range = alloc_range(ll_to_sval(num), ll_to_sval(num));
921f5207b7SJohn Levon 	add_ptr_list(&my_list, my_range);
931f5207b7SJohn Levon 	return my_list;
941f5207b7SJohn Levon }
951f5207b7SJohn Levon 
show_comparison(int op)96*6523a3aaSJohn Levon static const char *show_comparison(int op)
97*6523a3aaSJohn Levon {
98*6523a3aaSJohn Levon 	if (op == PARAM_LIMIT)
99*6523a3aaSJohn Levon 		return "<lim>";
100*6523a3aaSJohn Levon 	return show_special(op);
101*6523a3aaSJohn Levon }
102*6523a3aaSJohn Levon 
print_debug_tf(struct sm_state * sm,int istrue,int isfalse)1031f5207b7SJohn Levon static void print_debug_tf(struct sm_state *sm, int istrue, int isfalse)
1041f5207b7SJohn Levon {
105efe51d0cSJohn Levon 	if (!implied_debug && !option_debug)
1061f5207b7SJohn Levon 		return;
1071f5207b7SJohn Levon 
1081f5207b7SJohn Levon 	if (istrue && isfalse) {
1091f5207b7SJohn Levon 		printf("%s: %d: does not exist.\n", show_sm(sm), sm->line);
1101f5207b7SJohn Levon 	} else if (istrue) {
1111f5207b7SJohn Levon 		printf("'%s = %s' from %d is true. %s[stree %d]\n", sm->name, show_state(sm->state),
1121f5207b7SJohn Levon 			sm->line, sm->merged ? "[merged]" : "[leaf]",
1131f5207b7SJohn Levon 			get_stree_id(sm->pool));
1141f5207b7SJohn Levon 	} else if (isfalse) {
1151f5207b7SJohn Levon 		printf("'%s = %s' from %d is false. %s[stree %d]\n", sm->name, show_state(sm->state),
1161f5207b7SJohn Levon 			sm->line,
1171f5207b7SJohn Levon 			sm->merged ? "[merged]" : "[leaf]",
1181f5207b7SJohn Levon 			get_stree_id(sm->pool));
1191f5207b7SJohn Levon 	} else {
1201f5207b7SJohn Levon 		printf("'%s = %s' from %d could be true or false. %s[stree %d]\n", sm->name,
1211f5207b7SJohn Levon 			show_state(sm->state), sm->line,
1221f5207b7SJohn Levon 			sm->merged ? "[merged]" : "[leaf]",
1231f5207b7SJohn Levon 			get_stree_id(sm->pool));
1241f5207b7SJohn Levon 	}
1251f5207b7SJohn Levon }
1261f5207b7SJohn Levon 
split_comparison_helper(struct range_list * left_orig,int op,struct range_list * right_orig,struct range_list ** left_true_rl,struct range_list ** left_false_rl)127*6523a3aaSJohn Levon void split_comparison_helper(struct range_list *left_orig, int op, struct range_list *right_orig,
128*6523a3aaSJohn Levon 		struct range_list **left_true_rl, struct range_list **left_false_rl)
129*6523a3aaSJohn Levon {
130*6523a3aaSJohn Levon 	if (op == PARAM_LIMIT) {
131*6523a3aaSJohn Levon 		*left_true_rl = rl_intersection(left_orig, right_orig);
132*6523a3aaSJohn Levon 		*left_false_rl = rl_filter(left_orig, right_orig);
133*6523a3aaSJohn Levon 		return;
134*6523a3aaSJohn Levon 	}
135*6523a3aaSJohn Levon 
136*6523a3aaSJohn Levon 	split_comparison_rl(left_orig, op, right_orig, left_true_rl, left_false_rl, NULL, NULL);
137*6523a3aaSJohn Levon }
138*6523a3aaSJohn Levon 
create_fake_history(struct sm_state * sm,int comparison,struct range_list * rl)1391f5207b7SJohn Levon static int create_fake_history(struct sm_state *sm, int comparison, struct range_list *rl)
1401f5207b7SJohn Levon {
1411f5207b7SJohn Levon 	struct range_list *orig_rl;
1421f5207b7SJohn Levon 	struct range_list *true_rl, *false_rl;
1431f5207b7SJohn Levon 	struct stree *true_stree, *false_stree;
1441f5207b7SJohn Levon 	struct sm_state *true_sm, *false_sm;
1451f5207b7SJohn Levon 	sval_t sval;
1461f5207b7SJohn Levon 
1471f5207b7SJohn Levon 	if (is_merged(sm) || sm->left || sm->right)
1481f5207b7SJohn Levon 		return 0;
1491f5207b7SJohn Levon 	if (!rl_to_sval(rl, &sval))
1501f5207b7SJohn Levon 		return 0;
1511f5207b7SJohn Levon 	if (!estate_rl(sm->state))
1521f5207b7SJohn Levon 		return 0;
1531f5207b7SJohn Levon 
1541f5207b7SJohn Levon 	orig_rl = cast_rl(rl_type(rl), estate_rl(sm->state));
155*6523a3aaSJohn Levon 	split_comparison_helper(orig_rl, comparison, rl, &true_rl, &false_rl);
1561f5207b7SJohn Levon 
1571f5207b7SJohn Levon 	true_rl = rl_truncate_cast(estate_type(sm->state), true_rl);
1581f5207b7SJohn Levon 	false_rl = rl_truncate_cast(estate_type(sm->state), false_rl);
1591f5207b7SJohn Levon 	if (is_whole_rl(true_rl) || is_whole_rl(false_rl) ||
1601f5207b7SJohn Levon 	    !true_rl || !false_rl ||
1611f5207b7SJohn Levon 	    rl_equiv(orig_rl, true_rl) || rl_equiv(orig_rl, false_rl) ||
1621f5207b7SJohn Levon 	    rl_equiv(estate_rl(sm->state), true_rl) || rl_equiv(estate_rl(sm->state), false_rl))
1631f5207b7SJohn Levon 		return 0;
1641f5207b7SJohn Levon 
1651f5207b7SJohn Levon 	if (rl_intersection(true_rl, false_rl)) {
1665a0e240fSJohn Levon 		/*
1675a0e240fSJohn Levon 		 * Normally these won't intersect, but one exception is when
1685a0e240fSJohn Levon 		 * we're dealing with mtags.  We have a long list of mtags and
1695a0e240fSJohn Levon 		 * then negate the list.  Now it's over the limit for mtag list
1705a0e240fSJohn Levon 		 * length and we squash it down to 4096-ptr_max.  So then it's
1715a0e240fSJohn Levon 		 * possible for the true and false rl to overlap.
1725a0e240fSJohn Levon 		 */
1731f5207b7SJohn Levon 		return 0;
1741f5207b7SJohn Levon 	}
1751f5207b7SJohn Levon 
176efe51d0cSJohn Levon 	if (implied_debug)
177efe51d0cSJohn Levon 		sm_msg("fake_history: %s vs %s.  %s %s %s. --> T: %s F: %s",
178*6523a3aaSJohn Levon 		       sm->name, show_rl(rl), sm->state->name, show_comparison(comparison), show_rl(rl),
1791f5207b7SJohn Levon 		       show_rl(true_rl), show_rl(false_rl));
1801f5207b7SJohn Levon 
1811f5207b7SJohn Levon 	true_sm = clone_sm(sm);
1821f5207b7SJohn Levon 	false_sm = clone_sm(sm);
1831f5207b7SJohn Levon 
184efe51d0cSJohn Levon 	true_sm->state = clone_partial_estate(sm->state, true_rl);
1851f5207b7SJohn Levon 	free_slist(&true_sm->possible);
1861f5207b7SJohn Levon 	add_possible_sm(true_sm, true_sm);
187efe51d0cSJohn Levon 	false_sm->state = clone_partial_estate(sm->state, false_rl);
1881f5207b7SJohn Levon 	free_slist(&false_sm->possible);
1891f5207b7SJohn Levon 	add_possible_sm(false_sm, false_sm);
1901f5207b7SJohn Levon 
1911f5207b7SJohn Levon 	true_stree = clone_stree(sm->pool);
1921f5207b7SJohn Levon 	false_stree = clone_stree(sm->pool);
1931f5207b7SJohn Levon 
1941f5207b7SJohn Levon 	overwrite_sm_state_stree(&true_stree, true_sm);
1951f5207b7SJohn Levon 	overwrite_sm_state_stree(&false_stree, false_sm);
1961f5207b7SJohn Levon 
1971f5207b7SJohn Levon 	true_sm->pool = true_stree;
1981f5207b7SJohn Levon 	false_sm->pool = false_stree;
1991f5207b7SJohn Levon 
2001f5207b7SJohn Levon 	sm->merged = 1;
2011f5207b7SJohn Levon 	sm->left = true_sm;
2021f5207b7SJohn Levon 	sm->right = false_sm;
2031f5207b7SJohn Levon 
2041f5207b7SJohn Levon 	return 1;
2051f5207b7SJohn Levon }
2061f5207b7SJohn Levon 
2071f5207b7SJohn Levon /*
2081f5207b7SJohn Levon  * add_pool() adds a slist to *pools. If the slist has already been
2091f5207b7SJohn Levon  * added earlier then it doesn't get added a second time.
2101f5207b7SJohn Levon  */
add_pool(struct state_list ** pools,struct sm_state * new)2111f5207b7SJohn Levon void add_pool(struct state_list **pools, struct sm_state *new)
2121f5207b7SJohn Levon {
2131f5207b7SJohn Levon 	struct sm_state *tmp;
2141f5207b7SJohn Levon 
2151f5207b7SJohn Levon 	FOR_EACH_PTR(*pools, tmp) {
2161f5207b7SJohn Levon 		if (tmp->pool < new->pool)
2171f5207b7SJohn Levon 			continue;
2181f5207b7SJohn Levon 		else if (tmp->pool == new->pool) {
2191f5207b7SJohn Levon 			return;
2201f5207b7SJohn Levon 		} else {
2211f5207b7SJohn Levon 			INSERT_CURRENT(new, tmp);
2221f5207b7SJohn Levon 			return;
2231f5207b7SJohn Levon 		}
2241f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
2251f5207b7SJohn Levon 	add_ptr_list(pools, new);
2261f5207b7SJohn Levon }
2271f5207b7SJohn Levon 
pool_in_pools(struct stree * pool,const struct state_list * slist)2281f5207b7SJohn Levon static int pool_in_pools(struct stree *pool,
2291f5207b7SJohn Levon 			 const struct state_list *slist)
2301f5207b7SJohn Levon {
2311f5207b7SJohn Levon 	struct sm_state *tmp;
2321f5207b7SJohn Levon 
2331f5207b7SJohn Levon 	FOR_EACH_PTR(slist, tmp) {
2341f5207b7SJohn Levon 		if (!tmp->pool)
2351f5207b7SJohn Levon 			continue;
2361f5207b7SJohn Levon 		if (tmp->pool == pool)
2371f5207b7SJohn Levon 			return 1;
2381f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
2391f5207b7SJohn Levon 	return 0;
2401f5207b7SJohn Levon }
2411f5207b7SJohn Levon 
remove_pool(struct state_list ** pools,struct stree * remove)2421f5207b7SJohn Levon static int remove_pool(struct state_list **pools, struct stree *remove)
2431f5207b7SJohn Levon {
2441f5207b7SJohn Levon 	struct sm_state *tmp;
2451f5207b7SJohn Levon 	int ret = 0;
2461f5207b7SJohn Levon 
2471f5207b7SJohn Levon 	FOR_EACH_PTR(*pools, tmp) {
2481f5207b7SJohn Levon 		if (tmp->pool == remove) {
2491f5207b7SJohn Levon 			DELETE_CURRENT_PTR(tmp);
2501f5207b7SJohn Levon 			ret = 1;
2511f5207b7SJohn Levon 		}
2521f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
2531f5207b7SJohn Levon 
2541f5207b7SJohn Levon 	return ret;
2551f5207b7SJohn Levon }
2561f5207b7SJohn Levon 
possibly_true_helper(struct range_list * var_rl,int comparison,struct range_list * rl)257*6523a3aaSJohn Levon static bool possibly_true_helper(struct range_list *var_rl, int comparison, struct range_list *rl)
258*6523a3aaSJohn Levon {
259*6523a3aaSJohn Levon 	if (comparison == PARAM_LIMIT) {
260*6523a3aaSJohn Levon 		struct range_list *intersect;
261*6523a3aaSJohn Levon 
262*6523a3aaSJohn Levon 		intersect = rl_intersection(var_rl, rl);
263*6523a3aaSJohn Levon 		if (intersect)
264*6523a3aaSJohn Levon 			return true;
265*6523a3aaSJohn Levon 		return false;
266*6523a3aaSJohn Levon 	}
267*6523a3aaSJohn Levon 	return possibly_true_rl(var_rl, comparison, rl);
268*6523a3aaSJohn Levon }
269*6523a3aaSJohn Levon 
possibly_false_helper(struct range_list * var_rl,int comparison,struct range_list * rl)270*6523a3aaSJohn Levon static bool possibly_false_helper(struct range_list *var_rl, int comparison, struct range_list *rl)
271*6523a3aaSJohn Levon {
272*6523a3aaSJohn Levon 	if (comparison == PARAM_LIMIT) {
273*6523a3aaSJohn Levon 		struct range_list *intersect;
274*6523a3aaSJohn Levon 
275*6523a3aaSJohn Levon 		intersect = rl_intersection(var_rl, rl);
276*6523a3aaSJohn Levon 		if (!rl_equiv(var_rl, intersect))
277*6523a3aaSJohn Levon 			return true;
278*6523a3aaSJohn Levon 		return false;
279*6523a3aaSJohn Levon 	}
280*6523a3aaSJohn Levon 	return possibly_false_rl(var_rl, comparison, rl);
281*6523a3aaSJohn Levon }
282*6523a3aaSJohn Levon 
2831f5207b7SJohn Levon /*
2841f5207b7SJohn Levon  * If 'foo' == 99 add it that pool to the true pools.  If it's false, add it to
2851f5207b7SJohn Levon  * the false pools.  If we're not sure, then we don't add it to either.
2861f5207b7SJohn Levon  */
do_compare(struct sm_state * sm,int comparison,struct range_list * rl,struct state_list ** true_stack,struct state_list ** maybe_stack,struct state_list ** false_stack,int * mixed,struct sm_state * gate_sm)2871f5207b7SJohn Levon static void do_compare(struct sm_state *sm, int comparison, struct range_list *rl,
2881f5207b7SJohn Levon 			struct state_list **true_stack,
2891f5207b7SJohn Levon 			struct state_list **maybe_stack,
2901f5207b7SJohn Levon 			struct state_list **false_stack,
2911f5207b7SJohn Levon 			int *mixed, struct sm_state *gate_sm)
2921f5207b7SJohn Levon {
2931f5207b7SJohn Levon 	int istrue;
2941f5207b7SJohn Levon 	int isfalse;
2951f5207b7SJohn Levon 	struct range_list *var_rl;
2961f5207b7SJohn Levon 
2971f5207b7SJohn Levon 	if (!sm->pool)
2981f5207b7SJohn Levon 		return;
2991f5207b7SJohn Levon 
3001f5207b7SJohn Levon 	var_rl = cast_rl(rl_type(rl), estate_rl(sm->state));
3011f5207b7SJohn Levon 
302*6523a3aaSJohn Levon 	istrue = !possibly_false_helper(var_rl, comparison, rl);
303*6523a3aaSJohn Levon 	isfalse = !possibly_true_helper(var_rl, comparison, rl);
3041f5207b7SJohn Levon 
3051f5207b7SJohn Levon 	print_debug_tf(sm, istrue, isfalse);
3061f5207b7SJohn Levon 
3071f5207b7SJohn Levon 	/* give up if we have borrowed implications (smatch_equiv.c) */
3081f5207b7SJohn Levon 	if (sm->sym != gate_sm->sym ||
3091f5207b7SJohn Levon 	    strcmp(sm->name, gate_sm->name) != 0) {
3101f5207b7SJohn Levon 		if (mixed)
3111f5207b7SJohn Levon 			*mixed = 1;
3121f5207b7SJohn Levon 	}
3131f5207b7SJohn Levon 
3141f5207b7SJohn Levon 	if (mixed && !*mixed && !is_merged(sm) && !istrue && !isfalse) {
3151f5207b7SJohn Levon 		if (!create_fake_history(sm, comparison, rl))
3161f5207b7SJohn Levon 			*mixed = 1;
3171f5207b7SJohn Levon 	}
3181f5207b7SJohn Levon 
3191f5207b7SJohn Levon 	if (istrue)
3201f5207b7SJohn Levon 		add_pool(true_stack, sm);
3211f5207b7SJohn Levon 	else if (isfalse)
3221f5207b7SJohn Levon 		add_pool(false_stack, sm);
3231f5207b7SJohn Levon 	else
3241f5207b7SJohn Levon 		add_pool(maybe_stack, sm);
3251f5207b7SJohn Levon }
3261f5207b7SJohn Levon 
is_checked(struct state_list * checked,struct sm_state * sm)3271f5207b7SJohn Levon static int is_checked(struct state_list *checked, struct sm_state *sm)
3281f5207b7SJohn Levon {
3291f5207b7SJohn Levon 	struct sm_state *tmp;
3301f5207b7SJohn Levon 
3311f5207b7SJohn Levon 	FOR_EACH_PTR(checked, tmp) {
3321f5207b7SJohn Levon 		if (tmp == sm)
3331f5207b7SJohn Levon 			return 1;
3341f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
3351f5207b7SJohn Levon 	return 0;
3361f5207b7SJohn Levon }
3371f5207b7SJohn Levon 
3381f5207b7SJohn Levon /*
3391f5207b7SJohn Levon  * separate_pools():
3401f5207b7SJohn Levon  * Example code:  if (foo == 99) {
3411f5207b7SJohn Levon  *
3421f5207b7SJohn Levon  * Say 'foo' is a merged state that has many possible values.  It is the combination
3431f5207b7SJohn Levon  * of merges.  separate_pools() iterates through the pools recursively and calls
3441f5207b7SJohn Levon  * do_compare() for each time 'foo' was set.
3451f5207b7SJohn Levon  */
__separate_pools(struct sm_state * sm,int comparison,struct range_list * rl,struct state_list ** true_stack,struct state_list ** maybe_stack,struct state_list ** false_stack,struct state_list ** checked,int * mixed,struct sm_state * gate_sm,struct timeval * start_time)3461f5207b7SJohn Levon static void __separate_pools(struct sm_state *sm, int comparison, struct range_list *rl,
3471f5207b7SJohn Levon 			struct state_list **true_stack,
3481f5207b7SJohn Levon 			struct state_list **maybe_stack,
3491f5207b7SJohn Levon 			struct state_list **false_stack,
350efe51d0cSJohn Levon 			struct state_list **checked, int *mixed, struct sm_state *gate_sm,
351efe51d0cSJohn Levon 			struct timeval *start_time)
3521f5207b7SJohn Levon {
3531f5207b7SJohn Levon 	int free_checked = 0;
3541f5207b7SJohn Levon 	struct state_list *checked_states = NULL;
355c85f09ccSJohn Levon 	struct timeval now, diff;
3561f5207b7SJohn Levon 
3571f5207b7SJohn Levon 	if (!sm)
3581f5207b7SJohn Levon 		return;
3591f5207b7SJohn Levon 
360efe51d0cSJohn Levon 	gettimeofday(&now, NULL);
361c85f09ccSJohn Levon 	timersub(&now, start_time, &diff);
362c85f09ccSJohn Levon 	if (diff.tv_sec >= 1) {
363efe51d0cSJohn Levon 		if (implied_debug) {
364efe51d0cSJohn Levon 			sm_msg("debug: %s: implications taking too long.  (%s %s %s)",
365*6523a3aaSJohn Levon 			       __func__, sm->state->name, show_comparison(comparison), show_rl(rl));
3661f5207b7SJohn Levon 		}
367efe51d0cSJohn Levon 		if (mixed)
368efe51d0cSJohn Levon 			*mixed = 1;
3691f5207b7SJohn Levon 	}
3701f5207b7SJohn Levon 
3711f5207b7SJohn Levon 	if (checked == NULL) {
3721f5207b7SJohn Levon 		checked = &checked_states;
3731f5207b7SJohn Levon 		free_checked = 1;
3741f5207b7SJohn Levon 	}
3751f5207b7SJohn Levon 	if (is_checked(*checked, sm))
3761f5207b7SJohn Levon 		return;
3771f5207b7SJohn Levon 	add_ptr_list(checked, sm);
3781f5207b7SJohn Levon 
3791f5207b7SJohn Levon 	do_compare(sm, comparison, rl, true_stack, maybe_stack, false_stack, mixed, gate_sm);
3801f5207b7SJohn Levon 
381efe51d0cSJohn Levon 	__separate_pools(sm->left, comparison, rl, true_stack, maybe_stack, false_stack, checked, mixed, gate_sm, start_time);
382efe51d0cSJohn Levon 	__separate_pools(sm->right, comparison, rl, true_stack, maybe_stack, false_stack, checked, mixed, gate_sm, start_time);
3831f5207b7SJohn Levon 	if (free_checked)
3841f5207b7SJohn Levon 		free_slist(checked);
3851f5207b7SJohn Levon }
3861f5207b7SJohn Levon 
separate_pools(struct sm_state * sm,int comparison,struct range_list * rl,struct state_list ** true_stack,struct state_list ** false_stack,struct state_list ** checked,int * mixed)3871f5207b7SJohn Levon static void separate_pools(struct sm_state *sm, int comparison, struct range_list *rl,
3881f5207b7SJohn Levon 			struct state_list **true_stack,
3891f5207b7SJohn Levon 			struct state_list **false_stack,
3901f5207b7SJohn Levon 			struct state_list **checked, int *mixed)
3911f5207b7SJohn Levon {
3921f5207b7SJohn Levon 	struct state_list *maybe_stack = NULL;
3931f5207b7SJohn Levon 	struct sm_state *tmp;
394efe51d0cSJohn Levon 	struct timeval start_time;
395efe51d0cSJohn Levon 
3961f5207b7SJohn Levon 
397efe51d0cSJohn Levon 	gettimeofday(&start_time, NULL);
398efe51d0cSJohn Levon 	__separate_pools(sm, comparison, rl, true_stack, &maybe_stack, false_stack, checked, mixed, sm, &start_time);
3991f5207b7SJohn Levon 
400efe51d0cSJohn Levon 	if (implied_debug) {
4011f5207b7SJohn Levon 		struct sm_state *sm;
4021f5207b7SJohn Levon 
4031f5207b7SJohn Levon 		FOR_EACH_PTR(*true_stack, sm) {
4041f5207b7SJohn Levon 			sm_msg("TRUE %s [stree %d]", show_sm(sm), get_stree_id(sm->pool));
4051f5207b7SJohn Levon 		} END_FOR_EACH_PTR(sm);
4061f5207b7SJohn Levon 
4071f5207b7SJohn Levon 		FOR_EACH_PTR(maybe_stack, sm) {
408efe51d0cSJohn Levon 			sm_msg("MAYBE %s %s[stree %d]",
409efe51d0cSJohn Levon 			       show_sm(sm), sm->merged ? "(merged) ": "", get_stree_id(sm->pool));
4101f5207b7SJohn Levon 		} END_FOR_EACH_PTR(sm);
4111f5207b7SJohn Levon 
4121f5207b7SJohn Levon 		FOR_EACH_PTR(*false_stack, sm) {
4131f5207b7SJohn Levon 			sm_msg("FALSE %s [stree %d]", show_sm(sm), get_stree_id(sm->pool));
4141f5207b7SJohn Levon 		} END_FOR_EACH_PTR(sm);
4151f5207b7SJohn Levon 	}
4161f5207b7SJohn Levon 	/* if it's a maybe then remove it */
4171f5207b7SJohn Levon 	FOR_EACH_PTR(maybe_stack, tmp) {
4181f5207b7SJohn Levon 		remove_pool(false_stack, tmp->pool);
4191f5207b7SJohn Levon 		remove_pool(true_stack, tmp->pool);
4201f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
4211f5207b7SJohn Levon 
4221f5207b7SJohn Levon 	/* if it's both true and false remove it from both */
4231f5207b7SJohn Levon 	FOR_EACH_PTR(*true_stack, tmp) {
4241f5207b7SJohn Levon 		if (remove_pool(false_stack, tmp->pool))
4251f5207b7SJohn Levon 			DELETE_CURRENT_PTR(tmp);
4261f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
4271f5207b7SJohn Levon }
4281f5207b7SJohn Levon 
sm_in_keep_leafs(struct sm_state * sm,const struct state_list * keep_gates)4291f5207b7SJohn Levon static int sm_in_keep_leafs(struct sm_state *sm, const struct state_list *keep_gates)
4301f5207b7SJohn Levon {
4311f5207b7SJohn Levon 	struct sm_state *tmp, *old;
4321f5207b7SJohn Levon 
4331f5207b7SJohn Levon 	FOR_EACH_PTR(keep_gates, tmp) {
4341f5207b7SJohn Levon 		if (is_merged(tmp))
4351f5207b7SJohn Levon 			continue;
4361f5207b7SJohn Levon 		old = get_sm_state_stree(tmp->pool, sm->owner, sm->name, sm->sym);
4371f5207b7SJohn Levon 		if (!old)
4381f5207b7SJohn Levon 			continue;
4391f5207b7SJohn Levon 		if (old == sm)
4401f5207b7SJohn Levon 			return 1;
4411f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
4421f5207b7SJohn Levon 	return 0;
4431f5207b7SJohn Levon }
4441f5207b7SJohn Levon 
going_too_slow(void)445efe51d0cSJohn Levon static int going_too_slow(void)
4461f5207b7SJohn Levon {
4471f5207b7SJohn Levon 	static void *printed;
4481f5207b7SJohn Levon 
449efe51d0cSJohn Levon 	if (out_of_memory()) {
450efe51d0cSJohn Levon 		implications_off = true;
4511f5207b7SJohn Levon 		return 1;
452efe51d0cSJohn Levon 	}
4531f5207b7SJohn Levon 
454efe51d0cSJohn Levon 	if (!option_timeout || time_parsing_function() < option_timeout) {
455efe51d0cSJohn Levon 		implications_off = false;
4561f5207b7SJohn Levon 		return 0;
457efe51d0cSJohn Levon 	}
4581f5207b7SJohn Levon 
4591f5207b7SJohn Levon 	if (!__inline_fn && printed != cur_func_sym) {
4601f5207b7SJohn Levon 		if (!is_skipped_function())
461efe51d0cSJohn Levon 			sm_perror("turning off implications after %d seconds", option_timeout);
4621f5207b7SJohn Levon 		printed = cur_func_sym;
4631f5207b7SJohn Levon 	}
464efe51d0cSJohn Levon 	implications_off = true;
4651f5207b7SJohn Levon 	return 1;
4661f5207b7SJohn Levon }
4671f5207b7SJohn Levon 
sm_state_info(struct sm_state * sm)468efe51d0cSJohn Levon static char *sm_state_info(struct sm_state *sm)
469efe51d0cSJohn Levon {
470efe51d0cSJohn Levon 	static char buf[512];
471efe51d0cSJohn Levon 	int n = 0;
472efe51d0cSJohn Levon 
473efe51d0cSJohn Levon 	n += snprintf(buf + n, sizeof(buf) - n, "[stree %d line %d] ",
474efe51d0cSJohn Levon 		      get_stree_id(sm->pool),  sm->line);
475efe51d0cSJohn Levon 	if (n >= sizeof(buf))
476efe51d0cSJohn Levon 		return buf;
477efe51d0cSJohn Levon 	n += snprintf(buf + n, sizeof(buf) - n, "%s ", show_sm(sm));
478efe51d0cSJohn Levon 	if (n >= sizeof(buf))
479efe51d0cSJohn Levon 		return buf;
480efe51d0cSJohn Levon 	n += snprintf(buf + n, sizeof(buf) - n, "left = %s [stree %d] ",
481efe51d0cSJohn Levon 		      sm->left ? sm->left->state->name : "<none>",
482efe51d0cSJohn Levon 		      sm->left ? get_stree_id(sm->left->pool) : -1);
483efe51d0cSJohn Levon 	if (n >= sizeof(buf))
484efe51d0cSJohn Levon 		return buf;
485efe51d0cSJohn Levon 	n += snprintf(buf + n, sizeof(buf) - n, "right = %s [stree %d]",
486efe51d0cSJohn Levon 		      sm->right ? sm->right->state->name : "<none>",
487efe51d0cSJohn Levon 		      sm->right ? get_stree_id(sm->right->pool) : -1);
488efe51d0cSJohn Levon 	return buf;
489efe51d0cSJohn Levon }
490efe51d0cSJohn Levon 
4911f5207b7SJohn Levon /*
4921f5207b7SJohn Levon  * NOTE: If a state is in both the keep stack and the remove stack then that is
4931f5207b7SJohn Levon  * a bug.  Only add states which are definitely true or definitely false.  If
4941f5207b7SJohn Levon  * you have a leaf state that could be both true and false, then create a fake
4951f5207b7SJohn Levon  * split history where one side is true and one side is false.  Otherwise, if
4961f5207b7SJohn Levon  * you can't do that, then don't add it to either list.
4971f5207b7SJohn Levon  */
498efe51d0cSJohn Levon #define RECURSE_LIMIT 300
filter_pools(struct sm_state * sm,const struct state_list * remove_stack,const struct state_list * keep_stack,int * modified,int * recurse_cnt,struct timeval * start,int * skip,int * bail)4991f5207b7SJohn Levon struct sm_state *filter_pools(struct sm_state *sm,
5001f5207b7SJohn Levon 			      const struct state_list *remove_stack,
5011f5207b7SJohn Levon 			      const struct state_list *keep_stack,
5021f5207b7SJohn Levon 			      int *modified, int *recurse_cnt,
503efe51d0cSJohn Levon 			      struct timeval *start, int *skip, int *bail)
5041f5207b7SJohn Levon {
5051f5207b7SJohn Levon 	struct sm_state *ret = NULL;
5061f5207b7SJohn Levon 	struct sm_state *left;
5071f5207b7SJohn Levon 	struct sm_state *right;
5081f5207b7SJohn Levon 	int removed = 0;
509c85f09ccSJohn Levon 	struct timeval now, diff;
5101f5207b7SJohn Levon 
5111f5207b7SJohn Levon 	if (!sm)
5121f5207b7SJohn Levon 		return NULL;
513efe51d0cSJohn Levon 	if (*bail)
514efe51d0cSJohn Levon 		return NULL;
5151f5207b7SJohn Levon 	gettimeofday(&now, NULL);
516c85f09ccSJohn Levon 	timersub(&now, start, &diff);
517c85f09ccSJohn Levon 	if (diff.tv_sec >= 3) {
518efe51d0cSJohn Levon 		DIMPLIED("%s: implications taking too long: %s\n", __func__, sm_state_info(sm));
519efe51d0cSJohn Levon 		*bail = 1;
520efe51d0cSJohn Levon 		return NULL;
521efe51d0cSJohn Levon 	}
522efe51d0cSJohn Levon 	if ((*recurse_cnt)++ > RECURSE_LIMIT) {
523efe51d0cSJohn Levon 		DIMPLIED("%s: recursed too far:  %s\n", __func__, sm_state_info(sm));
524efe51d0cSJohn Levon 		*skip = 1;
525efe51d0cSJohn Levon 		return NULL;
5261f5207b7SJohn Levon 	}
5271f5207b7SJohn Levon 
5281f5207b7SJohn Levon 	if (pool_in_pools(sm->pool, remove_stack)) {
529efe51d0cSJohn Levon 		DIMPLIED("%s: remove: %s\n", __func__, sm_state_info(sm));
5301f5207b7SJohn Levon 		*modified = 1;
5311f5207b7SJohn Levon 		return NULL;
5321f5207b7SJohn Levon 	}
5331f5207b7SJohn Levon 
5341f5207b7SJohn Levon 	if (!is_merged(sm) || pool_in_pools(sm->pool, keep_stack) || sm_in_keep_leafs(sm, keep_stack)) {
535efe51d0cSJohn Levon 		DIMPLIED("%s: keep %s (%s, %s, %s): %s\n", __func__, sm->state->name,
5361f5207b7SJohn Levon 			is_merged(sm) ? "merged" : "not merged",
5371f5207b7SJohn Levon 			pool_in_pools(sm->pool, keep_stack) ? "not in keep pools" : "in keep pools",
538efe51d0cSJohn Levon 			sm_in_keep_leafs(sm, keep_stack) ? "reachable keep leaf" : "no keep leaf",
539efe51d0cSJohn Levon 			sm_state_info(sm));
5401f5207b7SJohn Levon 		return sm;
5411f5207b7SJohn Levon 	}
5421f5207b7SJohn Levon 
543efe51d0cSJohn Levon 	left = filter_pools(sm->left, remove_stack, keep_stack, &removed, recurse_cnt, start, skip, bail);
544efe51d0cSJohn Levon 	right = filter_pools(sm->right, remove_stack, keep_stack, &removed, recurse_cnt, start, skip, bail);
545efe51d0cSJohn Levon 	if (*bail || *skip)
546efe51d0cSJohn Levon 		return NULL;
5471f5207b7SJohn Levon 	if (!removed) {
548efe51d0cSJohn Levon 		DIMPLIED("%s: kept all: %s\n", __func__, sm_state_info(sm));
5491f5207b7SJohn Levon 		return sm;
5501f5207b7SJohn Levon 	}
5511f5207b7SJohn Levon 	*modified = 1;
5521f5207b7SJohn Levon 	if (!left && !right) {
553efe51d0cSJohn Levon 		DIMPLIED("%s: removed all: %s\n", __func__, sm_state_info(sm));
5541f5207b7SJohn Levon 		return NULL;
5551f5207b7SJohn Levon 	}
5561f5207b7SJohn Levon 
5571f5207b7SJohn Levon 	if (!left) {
5581f5207b7SJohn Levon 		ret = clone_sm(right);
5591f5207b7SJohn Levon 		ret->merged = 1;
5601f5207b7SJohn Levon 		ret->right = right;
5611f5207b7SJohn Levon 		ret->left = NULL;
5621f5207b7SJohn Levon 	} else if (!right) {
5631f5207b7SJohn Levon 		ret = clone_sm(left);
5641f5207b7SJohn Levon 		ret->merged = 1;
5651f5207b7SJohn Levon 		ret->left = left;
5661f5207b7SJohn Levon 		ret->right = NULL;
5671f5207b7SJohn Levon 	} else {
5681f5207b7SJohn Levon 		if (left->sym != sm->sym || strcmp(left->name, sm->name) != 0) {
5691f5207b7SJohn Levon 			left = clone_sm(left);
5701f5207b7SJohn Levon 			left->sym = sm->sym;
5711f5207b7SJohn Levon 			left->name = sm->name;
5721f5207b7SJohn Levon 		}
5731f5207b7SJohn Levon 		if (right->sym != sm->sym || strcmp(right->name, sm->name) != 0) {
5741f5207b7SJohn Levon 			right = clone_sm(right);
5751f5207b7SJohn Levon 			right->sym = sm->sym;
5761f5207b7SJohn Levon 			right->name = sm->name;
5771f5207b7SJohn Levon 		}
5781f5207b7SJohn Levon 		ret = merge_sm_states(left, right);
5791f5207b7SJohn Levon 	}
5801f5207b7SJohn Levon 
5811f5207b7SJohn Levon 	ret->pool = sm->pool;
5821f5207b7SJohn Levon 
583efe51d0cSJohn Levon 	DIMPLIED("%s: partial: %s\n", __func__, sm_state_info(sm));
5841f5207b7SJohn Levon 	return ret;
5851f5207b7SJohn Levon }
5861f5207b7SJohn Levon 
filter_stack(struct sm_state * gate_sm,struct stree * pre_stree,const struct state_list * remove_stack,const struct state_list * keep_stack)5871f5207b7SJohn Levon static struct stree *filter_stack(struct sm_state *gate_sm,
588*6523a3aaSJohn Levon 				  struct stree *pre_stree,
589*6523a3aaSJohn Levon 				  const struct state_list *remove_stack,
590*6523a3aaSJohn Levon 				  const struct state_list *keep_stack)
5911f5207b7SJohn Levon {
5921f5207b7SJohn Levon 	struct stree *ret = NULL;
5931f5207b7SJohn Levon 	struct sm_state *tmp;
5941f5207b7SJohn Levon 	struct sm_state *filtered_sm;
5951f5207b7SJohn Levon 	int modified;
5961f5207b7SJohn Levon 	int recurse_cnt;
5971f5207b7SJohn Levon 	struct timeval start;
598efe51d0cSJohn Levon 	int skip;
599efe51d0cSJohn Levon 	int bail = 0;
6001f5207b7SJohn Levon 
6011f5207b7SJohn Levon 	if (!remove_stack)
6021f5207b7SJohn Levon 		return NULL;
6031f5207b7SJohn Levon 
604efe51d0cSJohn Levon 	gettimeofday(&start, NULL);
6051f5207b7SJohn Levon 	FOR_EACH_SM(pre_stree, tmp) {
606efe51d0cSJohn Levon 		if (!tmp->merged || sm_in_keep_leafs(tmp, keep_stack))
6071f5207b7SJohn Levon 			continue;
6081f5207b7SJohn Levon 		modified = 0;
6091f5207b7SJohn Levon 		recurse_cnt = 0;
610efe51d0cSJohn Levon 		skip = 0;
611efe51d0cSJohn Levon 		filtered_sm = filter_pools(tmp, remove_stack, keep_stack, &modified, &recurse_cnt, &start, &skip, &bail);
612efe51d0cSJohn Levon 		if (going_too_slow())
613efe51d0cSJohn Levon 			return NULL;
614efe51d0cSJohn Levon 		if (bail)
615efe51d0cSJohn Levon 			return ret;  /* Return the implications we figured out before time ran out. */
616efe51d0cSJohn Levon 
617efe51d0cSJohn Levon 
618efe51d0cSJohn Levon 		if (skip || !filtered_sm || !modified)
6191f5207b7SJohn Levon 			continue;
6201f5207b7SJohn Levon 		/* the assignments here are for borrowed implications */
6211f5207b7SJohn Levon 		filtered_sm->name = tmp->name;
6221f5207b7SJohn Levon 		filtered_sm->sym = tmp->sym;
6231f5207b7SJohn Levon 		avl_insert(&ret, filtered_sm);
6241f5207b7SJohn Levon 	} END_FOR_EACH_SM(tmp);
6251f5207b7SJohn Levon 	return ret;
6261f5207b7SJohn Levon }
6271f5207b7SJohn Levon 
separate_and_filter(struct sm_state * sm,int comparison,struct range_list * rl,struct stree * pre_stree,struct stree ** true_states,struct stree ** false_states,int * mixed)6281f5207b7SJohn Levon static void separate_and_filter(struct sm_state *sm, int comparison, struct range_list *rl,
6291f5207b7SJohn Levon 		struct stree *pre_stree,
6301f5207b7SJohn Levon 		struct stree **true_states,
6311f5207b7SJohn Levon 		struct stree **false_states,
6321f5207b7SJohn Levon 		int *mixed)
6331f5207b7SJohn Levon {
6341f5207b7SJohn Levon 	struct state_list *true_stack = NULL;
6351f5207b7SJohn Levon 	struct state_list *false_stack = NULL;
6361f5207b7SJohn Levon 	struct timeval time_before;
6371f5207b7SJohn Levon 	struct timeval time_after;
6381f5207b7SJohn Levon 	int sec;
6391f5207b7SJohn Levon 
6401f5207b7SJohn Levon 	gettimeofday(&time_before, NULL);
6411f5207b7SJohn Levon 
642efe51d0cSJohn Levon 	DIMPLIED("checking implications: (%s (%s) %s %s)\n",
643*6523a3aaSJohn Levon 		 sm->name, sm->state->name, show_comparison(comparison), show_rl(rl));
644efe51d0cSJohn Levon 
6451f5207b7SJohn Levon 	if (!is_merged(sm)) {
646efe51d0cSJohn Levon 		DIMPLIED("%d '%s' from line %d is not merged.\n", get_lineno(), sm->name, sm->line);
6471f5207b7SJohn Levon 		return;
6481f5207b7SJohn Levon 	}
6491f5207b7SJohn Levon 
6501f5207b7SJohn Levon 	separate_pools(sm, comparison, rl, &true_stack, &false_stack, NULL, mixed);
6511f5207b7SJohn Levon 
6521f5207b7SJohn Levon 	DIMPLIED("filtering true stack.\n");
6531f5207b7SJohn Levon 	*true_states = filter_stack(sm, pre_stree, false_stack, true_stack);
6541f5207b7SJohn Levon 	DIMPLIED("filtering false stack.\n");
6551f5207b7SJohn Levon 	*false_states = filter_stack(sm, pre_stree, true_stack, false_stack);
6561f5207b7SJohn Levon 	free_slist(&true_stack);
6571f5207b7SJohn Levon 	free_slist(&false_stack);
6581f5207b7SJohn Levon 
6591f5207b7SJohn Levon 	gettimeofday(&time_after, NULL);
6601f5207b7SJohn Levon 	sec = time_after.tv_sec - time_before.tv_sec;
661efe51d0cSJohn Levon 	if (option_timeout && sec > option_timeout) {
6621f5207b7SJohn Levon 		sm_perror("Function too hairy.  Ignoring implications after %d seconds.", sec);
6631f5207b7SJohn Levon 	}
6641f5207b7SJohn Levon }
6651f5207b7SJohn Levon 
get_last_expr(struct statement * stmt)6661f5207b7SJohn Levon static struct expression *get_last_expr(struct statement *stmt)
6671f5207b7SJohn Levon {
6681f5207b7SJohn Levon 	struct statement *last;
6691f5207b7SJohn Levon 
6701f5207b7SJohn Levon 	last = last_ptr_list((struct ptr_list *)stmt->stmts);
6711f5207b7SJohn Levon 	if (last->type == STMT_EXPRESSION)
6721f5207b7SJohn Levon 		return last->expression;
6731f5207b7SJohn Levon 
6741f5207b7SJohn Levon 	if (last->type == STMT_LABEL) {
6751f5207b7SJohn Levon 		if (last->label_statement &&
6761f5207b7SJohn Levon 		    last->label_statement->type == STMT_EXPRESSION)
6771f5207b7SJohn Levon 			return last->label_statement->expression;
6781f5207b7SJohn Levon 	}
6791f5207b7SJohn Levon 
6801f5207b7SJohn Levon 	return NULL;
6811f5207b7SJohn Levon }
6821f5207b7SJohn Levon 
get_left_most_expr(struct expression * expr)6831f5207b7SJohn Levon static struct expression *get_left_most_expr(struct expression *expr)
6841f5207b7SJohn Levon {
6851f5207b7SJohn Levon 	struct statement *compound;
6861f5207b7SJohn Levon 
6871f5207b7SJohn Levon 	compound = get_expression_statement(expr);
6881f5207b7SJohn Levon 	if (compound)
6891f5207b7SJohn Levon 		return get_last_expr(compound);
6901f5207b7SJohn Levon 
6911f5207b7SJohn Levon 	expr = strip_parens(expr);
6921f5207b7SJohn Levon 	if (expr->type == EXPR_ASSIGNMENT)
6931f5207b7SJohn Levon 		return get_left_most_expr(expr->left);
6941f5207b7SJohn Levon 	return expr;
6951f5207b7SJohn Levon }
6961f5207b7SJohn Levon 
is_merged_expr(struct expression * expr)6971f5207b7SJohn Levon static int is_merged_expr(struct expression  *expr)
6981f5207b7SJohn Levon {
6991f5207b7SJohn Levon 	struct sm_state *sm;
7001f5207b7SJohn Levon 	sval_t dummy;
7011f5207b7SJohn Levon 
7021f5207b7SJohn Levon 	if (get_value(expr, &dummy))
7031f5207b7SJohn Levon 		return 0;
7041f5207b7SJohn Levon 	sm = get_sm_state_expr(SMATCH_EXTRA, expr);
7051f5207b7SJohn Levon 	if (!sm)
7061f5207b7SJohn Levon 		return 0;
7071f5207b7SJohn Levon 	if (is_merged(sm))
7081f5207b7SJohn Levon 		return 1;
7091f5207b7SJohn Levon 	return 0;
7101f5207b7SJohn Levon }
7111f5207b7SJohn Levon 
delete_gate_sm_equiv(struct stree ** stree,const char * name,struct symbol * sym)7121f5207b7SJohn Levon static void delete_gate_sm_equiv(struct stree **stree, const char *name, struct symbol *sym)
7131f5207b7SJohn Levon {
7141f5207b7SJohn Levon 	struct smatch_state *state;
7151f5207b7SJohn Levon 	struct relation *rel;
7161f5207b7SJohn Levon 
7171f5207b7SJohn Levon 	state = get_state(SMATCH_EXTRA, name, sym);
7181f5207b7SJohn Levon 	if (!state)
7191f5207b7SJohn Levon 		return;
7201f5207b7SJohn Levon 	FOR_EACH_PTR(estate_related(state), rel) {
7211f5207b7SJohn Levon 		delete_state_stree(stree, SMATCH_EXTRA, rel->name, rel->sym);
7221f5207b7SJohn Levon 	} END_FOR_EACH_PTR(rel);
7231f5207b7SJohn Levon }
7241f5207b7SJohn Levon 
delete_gate_sm(struct stree ** stree,const char * name,struct symbol * sym)7251f5207b7SJohn Levon static void delete_gate_sm(struct stree **stree, const char *name, struct symbol *sym)
7261f5207b7SJohn Levon {
7271f5207b7SJohn Levon 	delete_state_stree(stree, SMATCH_EXTRA, name, sym);
7281f5207b7SJohn Levon }
7291f5207b7SJohn Levon 
handle_comparison(struct expression * expr,struct stree ** implied_true,struct stree ** implied_false)7301f5207b7SJohn Levon static int handle_comparison(struct expression *expr,
7311f5207b7SJohn Levon 			      struct stree **implied_true,
7321f5207b7SJohn Levon 			      struct stree **implied_false)
7331f5207b7SJohn Levon {
7341f5207b7SJohn Levon 	struct sm_state *sm = NULL;
7351f5207b7SJohn Levon 	struct range_list *rl = NULL;
7361f5207b7SJohn Levon 	struct expression *left;
7371f5207b7SJohn Levon 	struct expression *right;
7381f5207b7SJohn Levon 	struct symbol *type;
7391f5207b7SJohn Levon 	int comparison = expr->op;
7401f5207b7SJohn Levon 	int mixed = 0;
7411f5207b7SJohn Levon 
7421f5207b7SJohn Levon 	left = get_left_most_expr(expr->left);
7431f5207b7SJohn Levon 	right = get_left_most_expr(expr->right);
7441f5207b7SJohn Levon 
7451f5207b7SJohn Levon 	if (is_merged_expr(left)) {
7461f5207b7SJohn Levon 		sm = get_sm_state_expr(SMATCH_EXTRA, left);
7471f5207b7SJohn Levon 		get_implied_rl(right, &rl);
7481f5207b7SJohn Levon 	} else if (is_merged_expr(right)) {
7491f5207b7SJohn Levon 		sm = get_sm_state_expr(SMATCH_EXTRA, right);
7501f5207b7SJohn Levon 		get_implied_rl(left, &rl);
7511f5207b7SJohn Levon 		comparison = flip_comparison(comparison);
7521f5207b7SJohn Levon 	}
7531f5207b7SJohn Levon 
7541f5207b7SJohn Levon 	if (!rl || !sm)
7551f5207b7SJohn Levon 		return 0;
7561f5207b7SJohn Levon 
7571f5207b7SJohn Levon 	type = get_type(expr);
7581f5207b7SJohn Levon 	if (!type)
7591f5207b7SJohn Levon 		return 0;
7601f5207b7SJohn Levon 	if (type_positive_bits(rl_type(rl)) > type_positive_bits(type))
7611f5207b7SJohn Levon 		type = rl_type(rl);
7621f5207b7SJohn Levon 	if (type_positive_bits(type) < 31)
7631f5207b7SJohn Levon 		type = &int_ctype;
7641f5207b7SJohn Levon 	rl = cast_rl(type, rl);
7651f5207b7SJohn Levon 
7661f5207b7SJohn Levon 	separate_and_filter(sm, comparison, rl, __get_cur_stree(), implied_true, implied_false, &mixed);
7671f5207b7SJohn Levon 
7681f5207b7SJohn Levon 	delete_gate_sm_equiv(implied_true, sm->name, sm->sym);
7691f5207b7SJohn Levon 	delete_gate_sm_equiv(implied_false, sm->name, sm->sym);
7701f5207b7SJohn Levon 	if (mixed) {
7711f5207b7SJohn Levon 		delete_gate_sm(implied_true, sm->name, sm->sym);
7721f5207b7SJohn Levon 		delete_gate_sm(implied_false, sm->name, sm->sym);
7731f5207b7SJohn Levon 	}
7741f5207b7SJohn Levon 
7751f5207b7SJohn Levon 	return 1;
7761f5207b7SJohn Levon }
7771f5207b7SJohn Levon 
handle_zero_comparison(struct expression * expr,struct stree ** implied_true,struct stree ** implied_false)7781f5207b7SJohn Levon static int handle_zero_comparison(struct expression *expr,
7791f5207b7SJohn Levon 				struct stree **implied_true,
7801f5207b7SJohn Levon 				struct stree **implied_false)
7811f5207b7SJohn Levon {
7821f5207b7SJohn Levon 	struct symbol *sym;
7831f5207b7SJohn Levon 	char *name;
7841f5207b7SJohn Levon 	struct sm_state *sm;
7851f5207b7SJohn Levon 	int mixed = 0;
7861f5207b7SJohn Levon 	int ret = 0;
7871f5207b7SJohn Levon 
7881f5207b7SJohn Levon 	if (expr->type == EXPR_POSTOP)
7891f5207b7SJohn Levon 		expr = strip_expr(expr->unop);
7901f5207b7SJohn Levon 
7911f5207b7SJohn Levon 	if (expr->type == EXPR_ASSIGNMENT) {
7921f5207b7SJohn Levon 		/* most of the time ->pools will be empty here because we
7931f5207b7SJohn Levon 		   just set the state, but if have assigned a conditional
7941f5207b7SJohn Levon 		   function there are implications. */
7951f5207b7SJohn Levon 		expr = expr->left;
7961f5207b7SJohn Levon 	}
7971f5207b7SJohn Levon 
7981f5207b7SJohn Levon 	name = expr_to_var_sym(expr, &sym);
7991f5207b7SJohn Levon 	if (!name || !sym)
8001f5207b7SJohn Levon 		goto free;
8011f5207b7SJohn Levon 	sm = get_sm_state(SMATCH_EXTRA, name, sym);
802*6523a3aaSJohn Levon 	if (!sm || !sm->merged)
8031f5207b7SJohn Levon 		goto free;
8041f5207b7SJohn Levon 
8051f5207b7SJohn Levon 	separate_and_filter(sm, SPECIAL_NOTEQUAL, tmp_range_list(estate_type(sm->state), 0), __get_cur_stree(), implied_true, implied_false, &mixed);
8061f5207b7SJohn Levon 	delete_gate_sm_equiv(implied_true, sm->name, sm->sym);
8071f5207b7SJohn Levon 	delete_gate_sm_equiv(implied_false, sm->name, sm->sym);
8081f5207b7SJohn Levon 	if (mixed) {
8091f5207b7SJohn Levon 		delete_gate_sm(implied_true, sm->name, sm->sym);
8101f5207b7SJohn Levon 		delete_gate_sm(implied_false, sm->name, sm->sym);
8111f5207b7SJohn Levon 	}
8121f5207b7SJohn Levon 
8131f5207b7SJohn Levon 	ret = 1;
8141f5207b7SJohn Levon free:
8151f5207b7SJohn Levon 	free_string(name);
8161f5207b7SJohn Levon 	return ret;
8171f5207b7SJohn Levon }
8181f5207b7SJohn Levon 
handled_by_comparison_hook(struct expression * expr,struct stree ** implied_true,struct stree ** implied_false)8191f5207b7SJohn Levon static int handled_by_comparison_hook(struct expression *expr,
820*6523a3aaSJohn Levon 				      struct stree **implied_true,
821*6523a3aaSJohn Levon 				      struct stree **implied_false)
8221f5207b7SJohn Levon {
823*6523a3aaSJohn Levon 	struct sm_state *sm, *true_sm, *false_sm;
8241f5207b7SJohn Levon 	struct state_list *true_stack = NULL;
8251f5207b7SJohn Levon 	struct state_list *false_stack = NULL;
8261f5207b7SJohn Levon 	struct stree *pre_stree;
8271f5207b7SJohn Levon 
8281f5207b7SJohn Levon 	sm = comparison_implication_hook(expr, &true_stack, &false_stack);
8291f5207b7SJohn Levon 	if (!sm)
8301f5207b7SJohn Levon 		return 0;
8311f5207b7SJohn Levon 
8321f5207b7SJohn Levon 	pre_stree = clone_stree(__get_cur_stree());
8331f5207b7SJohn Levon 
8341f5207b7SJohn Levon 	*implied_true = filter_stack(sm, pre_stree, false_stack, true_stack);
8351f5207b7SJohn Levon 	*implied_false = filter_stack(sm, pre_stree, true_stack, false_stack);
8361f5207b7SJohn Levon 
837*6523a3aaSJohn Levon 	true_sm = get_sm_state_stree(*implied_true, sm->owner, sm->name, sm->sym);
838*6523a3aaSJohn Levon 	false_sm = get_sm_state_stree(*implied_false, sm->owner, sm->name, sm->sym);
839*6523a3aaSJohn Levon 	if (true_sm && strcmp(true_sm->state->name, "unknown") == 0)
840*6523a3aaSJohn Levon 		delete_state_stree(implied_true, sm->owner, sm->name, sm->sym);
841*6523a3aaSJohn Levon 	if (false_sm && strcmp(false_sm->state->name, "unknown") == 0)
842*6523a3aaSJohn Levon 		delete_state_stree(implied_false, sm->owner, sm->name, sm->sym);
843*6523a3aaSJohn Levon 
8441f5207b7SJohn Levon 	free_stree(&pre_stree);
8451f5207b7SJohn Levon 	free_slist(&true_stack);
8461f5207b7SJohn Levon 	free_slist(&false_stack);
8471f5207b7SJohn Levon 
8481f5207b7SJohn Levon 	return 1;
8491f5207b7SJohn Levon }
8501f5207b7SJohn Levon 
handled_by_extra_states(struct expression * expr,struct stree ** implied_true,struct stree ** implied_false)8511f5207b7SJohn Levon static int handled_by_extra_states(struct expression *expr,
8521f5207b7SJohn Levon 				   struct stree **implied_true,
8531f5207b7SJohn Levon 				   struct stree **implied_false)
8541f5207b7SJohn Levon {
855c85f09ccSJohn Levon 	sval_t sval;
856c85f09ccSJohn Levon 
857c85f09ccSJohn Levon 	/* If the expression is known then it has no implications.  */
858c85f09ccSJohn Levon 	if (get_implied_value(expr, &sval))
859c85f09ccSJohn Levon 		return true;
860c85f09ccSJohn Levon 
8611f5207b7SJohn Levon 	if (expr->type == EXPR_COMPARE)
8621f5207b7SJohn Levon 		return handle_comparison(expr, implied_true, implied_false);
8631f5207b7SJohn Levon 	else
8641f5207b7SJohn Levon 		return handle_zero_comparison(expr, implied_true, implied_false);
8651f5207b7SJohn Levon }
8661f5207b7SJohn Levon 
handled_by_parsed_conditions(struct expression * expr,struct stree ** implied_true,struct stree ** implied_false)8675a0e240fSJohn Levon static int handled_by_parsed_conditions(struct expression *expr,
8685a0e240fSJohn Levon 					struct stree **implied_true,
8695a0e240fSJohn Levon 					struct stree **implied_false)
8705a0e240fSJohn Levon {
8715a0e240fSJohn Levon 	struct state_list *true_stack = NULL;
8725a0e240fSJohn Levon 	struct state_list *false_stack = NULL;
8735a0e240fSJohn Levon 	struct stree *pre_stree;
8745a0e240fSJohn Levon 	struct sm_state *sm;
8755a0e240fSJohn Levon 
8765a0e240fSJohn Levon 	sm = parsed_condition_implication_hook(expr, &true_stack, &false_stack);
8775a0e240fSJohn Levon 	if (!sm)
8785a0e240fSJohn Levon 		return 0;
8795a0e240fSJohn Levon 
8805a0e240fSJohn Levon 	pre_stree = clone_stree(__get_cur_stree());
8815a0e240fSJohn Levon 
8825a0e240fSJohn Levon 	*implied_true = filter_stack(sm, pre_stree, false_stack, true_stack);
8835a0e240fSJohn Levon 	*implied_false = filter_stack(sm, pre_stree, true_stack, false_stack);
8845a0e240fSJohn Levon 
8855a0e240fSJohn Levon 	free_stree(&pre_stree);
8865a0e240fSJohn Levon 	free_slist(&true_stack);
8875a0e240fSJohn Levon 	free_slist(&false_stack);
8885a0e240fSJohn Levon 
8895a0e240fSJohn Levon 	return 1;
8905a0e240fSJohn Levon }
8915a0e240fSJohn Levon 
handled_by_stored_conditions(struct expression * expr,struct stree ** implied_true,struct stree ** implied_false)8921f5207b7SJohn Levon static int handled_by_stored_conditions(struct expression *expr,
8931f5207b7SJohn Levon 					struct stree **implied_true,
8941f5207b7SJohn Levon 					struct stree **implied_false)
8951f5207b7SJohn Levon {
8961f5207b7SJohn Levon 	struct state_list *true_stack = NULL;
8971f5207b7SJohn Levon 	struct state_list *false_stack = NULL;
8981f5207b7SJohn Levon 	struct stree *pre_stree;
8991f5207b7SJohn Levon 	struct sm_state *sm;
9001f5207b7SJohn Levon 
9011f5207b7SJohn Levon 	sm = stored_condition_implication_hook(expr, &true_stack, &false_stack);
9021f5207b7SJohn Levon 	if (!sm)
9031f5207b7SJohn Levon 		return 0;
9041f5207b7SJohn Levon 
9051f5207b7SJohn Levon 	pre_stree = clone_stree(__get_cur_stree());
9061f5207b7SJohn Levon 
9071f5207b7SJohn Levon 	*implied_true = filter_stack(sm, pre_stree, false_stack, true_stack);
9081f5207b7SJohn Levon 	*implied_false = filter_stack(sm, pre_stree, true_stack, false_stack);
9091f5207b7SJohn Levon 
9101f5207b7SJohn Levon 	free_stree(&pre_stree);
9111f5207b7SJohn Levon 	free_slist(&true_stack);
9121f5207b7SJohn Levon 	free_slist(&false_stack);
9131f5207b7SJohn Levon 
9141f5207b7SJohn Levon 	return 1;
9151f5207b7SJohn Levon }
9161f5207b7SJohn Levon 
9171f5207b7SJohn Levon static struct stree *saved_implied_true;
9181f5207b7SJohn Levon static struct stree *saved_implied_false;
9191f5207b7SJohn Levon static struct stree *extra_saved_implied_true;
9201f5207b7SJohn Levon static struct stree *extra_saved_implied_false;
9211f5207b7SJohn Levon 
separate_implication_states(struct stree ** implied_true,struct stree ** implied_false,int owner)9225a0e240fSJohn Levon static void separate_implication_states(struct stree **implied_true,
9235a0e240fSJohn Levon 					 struct stree **implied_false,
9245a0e240fSJohn Levon 					 int owner)
9251f5207b7SJohn Levon {
9261f5207b7SJohn Levon 	struct sm_state *sm;
9271f5207b7SJohn Levon 
9285a0e240fSJohn Levon 	/* We process these states later to preserve the implications. */
9291f5207b7SJohn Levon 	FOR_EACH_SM(*implied_true, sm) {
9305a0e240fSJohn Levon 		if (sm->owner == owner)
9311f5207b7SJohn Levon 			overwrite_sm_state_stree(&extra_saved_implied_true, sm);
9321f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
9331f5207b7SJohn Levon 	FOR_EACH_SM(extra_saved_implied_true, sm) {
9341f5207b7SJohn Levon 		delete_state_stree(implied_true, sm->owner, sm->name, sm->sym);
9351f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
9361f5207b7SJohn Levon 
9371f5207b7SJohn Levon 	FOR_EACH_SM(*implied_false, sm) {
9385a0e240fSJohn Levon 		if (sm->owner == owner)
9391f5207b7SJohn Levon 			overwrite_sm_state_stree(&extra_saved_implied_false, sm);
9401f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
9411f5207b7SJohn Levon 	FOR_EACH_SM(extra_saved_implied_false, sm) {
9421f5207b7SJohn Levon 		delete_state_stree(implied_false, sm->owner, sm->name, sm->sym);
9431f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
9441f5207b7SJohn Levon }
9451f5207b7SJohn Levon 
get_tf_states(struct expression * expr,struct stree ** implied_true,struct stree ** implied_false)9461f5207b7SJohn Levon static void get_tf_states(struct expression *expr,
9471f5207b7SJohn Levon 			  struct stree **implied_true,
9481f5207b7SJohn Levon 			  struct stree **implied_false)
9491f5207b7SJohn Levon {
9505a0e240fSJohn Levon 	if (handled_by_parsed_conditions(expr, implied_true, implied_false))
951efe51d0cSJohn Levon 		return;
9521f5207b7SJohn Levon 
9535a0e240fSJohn Levon 	if (handled_by_comparison_hook(expr, implied_true, implied_false)) {
9545a0e240fSJohn Levon 		separate_implication_states(implied_true, implied_false, comparison_id);
9555a0e240fSJohn Levon 		return;
9565a0e240fSJohn Levon 	}
9575a0e240fSJohn Levon 
9581f5207b7SJohn Levon 	if (handled_by_extra_states(expr, implied_true, implied_false)) {
9595a0e240fSJohn Levon 		separate_implication_states(implied_true, implied_false, SMATCH_EXTRA);
960efe51d0cSJohn Levon 		return;
9611f5207b7SJohn Levon 	}
9621f5207b7SJohn Levon 
9631f5207b7SJohn Levon 	if (handled_by_stored_conditions(expr, implied_true, implied_false))
964efe51d0cSJohn Levon 		return;
9651f5207b7SJohn Levon }
9661f5207b7SJohn Levon 
save_implications_hook(struct expression * expr)9671f5207b7SJohn Levon static void save_implications_hook(struct expression *expr)
9681f5207b7SJohn Levon {
969efe51d0cSJohn Levon 	if (going_too_slow())
9701f5207b7SJohn Levon 		return;
9711f5207b7SJohn Levon 	get_tf_states(expr, &saved_implied_true, &saved_implied_false);
9721f5207b7SJohn Levon }
9731f5207b7SJohn Levon 
set_implied_states(struct expression * expr)9741f5207b7SJohn Levon static void set_implied_states(struct expression *expr)
9751f5207b7SJohn Levon {
9761f5207b7SJohn Levon 	struct sm_state *sm;
9771f5207b7SJohn Levon 
978c85f09ccSJohn Levon 	if (implied_debug &&
979c85f09ccSJohn Levon 	    (expr || saved_implied_true || saved_implied_false)) {
980c85f09ccSJohn Levon 		char *name;
981c85f09ccSJohn Levon 
982c85f09ccSJohn Levon 		name = expr_to_str(expr);
983c85f09ccSJohn Levon 		printf("These are the implied states for the true path: (%s)\n", name);
984c85f09ccSJohn Levon 		__print_stree(saved_implied_true);
985c85f09ccSJohn Levon 		printf("These are the implied states for the false path: (%s)\n", name);
986c85f09ccSJohn Levon 		__print_stree(saved_implied_false);
987c85f09ccSJohn Levon 		free_string(name);
988c85f09ccSJohn Levon 	}
989c85f09ccSJohn Levon 
9901f5207b7SJohn Levon 	FOR_EACH_SM(saved_implied_true, sm) {
9911f5207b7SJohn Levon 		__set_true_false_sm(sm, NULL);
9921f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
9931f5207b7SJohn Levon 	free_stree(&saved_implied_true);
9941f5207b7SJohn Levon 
9951f5207b7SJohn Levon 	FOR_EACH_SM(saved_implied_false, sm) {
9961f5207b7SJohn Levon 		__set_true_false_sm(NULL, sm);
9971f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
9981f5207b7SJohn Levon 	free_stree(&saved_implied_false);
9991f5207b7SJohn Levon }
10001f5207b7SJohn Levon 
set_extra_implied_states(struct expression * expr)10011f5207b7SJohn Levon static void set_extra_implied_states(struct expression *expr)
10021f5207b7SJohn Levon {
10031f5207b7SJohn Levon 	saved_implied_true = extra_saved_implied_true;
10041f5207b7SJohn Levon 	saved_implied_false = extra_saved_implied_false;
10051f5207b7SJohn Levon 	extra_saved_implied_true = NULL;
10061f5207b7SJohn Levon 	extra_saved_implied_false = NULL;
10071f5207b7SJohn Levon 	set_implied_states(NULL);
10081f5207b7SJohn Levon }
10091f5207b7SJohn Levon 
param_limit_implications(struct expression * expr,int param,char * key,char * value,struct stree ** implied)1010*6523a3aaSJohn Levon void param_limit_implications(struct expression *expr, int param, char *key, char *value, struct stree **implied)
10111f5207b7SJohn Levon {
1012*6523a3aaSJohn Levon 	struct expression *orig_expr, *arg;
10131f5207b7SJohn Levon 	struct symbol *compare_type;
10141f5207b7SJohn Levon 	char *name;
10151f5207b7SJohn Levon 	struct symbol *sym;
10161f5207b7SJohn Levon 	struct sm_state *sm;
10171f5207b7SJohn Levon 	struct sm_state *tmp;
10181f5207b7SJohn Levon 	struct stree *implied_true = NULL;
10191f5207b7SJohn Levon 	struct stree *implied_false = NULL;
10201f5207b7SJohn Levon 	struct range_list *orig, *limit;
1021*6523a3aaSJohn Levon 	char *left_name = NULL;
1022*6523a3aaSJohn Levon 	struct symbol *left_sym = NULL;
1023*6523a3aaSJohn Levon 	int mixed = 0;
10241f5207b7SJohn Levon 
1025efe51d0cSJohn Levon 	if (time_parsing_function() > 40)
1026efe51d0cSJohn Levon 		return;
1027efe51d0cSJohn Levon 
1028*6523a3aaSJohn Levon 	orig_expr = expr;
10291f5207b7SJohn Levon 	while (expr->type == EXPR_ASSIGNMENT)
10301f5207b7SJohn Levon 		expr = strip_expr(expr->right);
10311f5207b7SJohn Levon 	if (expr->type != EXPR_CALL)
10321f5207b7SJohn Levon 		return;
10331f5207b7SJohn Levon 
10341f5207b7SJohn Levon 	arg = get_argument_from_call_expr(expr->args, param);
10351f5207b7SJohn Levon 	if (!arg)
10361f5207b7SJohn Levon 		return;
10371f5207b7SJohn Levon 
10381f5207b7SJohn Levon 	arg = strip_parens(arg);
10391f5207b7SJohn Levon 	while (arg->type == EXPR_ASSIGNMENT && arg->op == '=')
10401f5207b7SJohn Levon 		arg = strip_parens(arg->left);
10411f5207b7SJohn Levon 
10421f5207b7SJohn Levon 	name = get_variable_from_key(arg, key, &sym);
10431f5207b7SJohn Levon 	if (!name || !sym)
10441f5207b7SJohn Levon 		goto free;
10451f5207b7SJohn Levon 
10461f5207b7SJohn Levon 	sm = get_sm_state(SMATCH_EXTRA, name, sym);
10471f5207b7SJohn Levon 	if (!sm || !sm->merged)
10481f5207b7SJohn Levon 		goto free;
10491f5207b7SJohn Levon 
10501f5207b7SJohn Levon 	if (strcmp(key, "$") == 0)
10511f5207b7SJohn Levon 		compare_type = get_arg_type(expr->fn, param);
10521f5207b7SJohn Levon 	else
10531f5207b7SJohn Levon 		compare_type = get_member_type_from_key(arg, key);
10541f5207b7SJohn Levon 
10551f5207b7SJohn Levon 	orig = estate_rl(sm->state);
10561f5207b7SJohn Levon 	orig = cast_rl(compare_type, orig);
10571f5207b7SJohn Levon 
10581f5207b7SJohn Levon 	call_results_to_rl(expr, compare_type, value, &limit);
10591f5207b7SJohn Levon 
1060*6523a3aaSJohn Levon 	separate_and_filter(sm, PARAM_LIMIT, limit, __get_cur_stree(), &implied_true, &implied_false, &mixed);
1061*6523a3aaSJohn Levon 
1062*6523a3aaSJohn Levon 	if (orig_expr->type == EXPR_ASSIGNMENT)
1063*6523a3aaSJohn Levon 		left_name = expr_to_var_sym(orig_expr->left, &left_sym);
10641f5207b7SJohn Levon 
10651f5207b7SJohn Levon 	FOR_EACH_SM(implied_true, tmp) {
1066*6523a3aaSJohn Levon 		/*
1067*6523a3aaSJohn Levon 		 * What we're trying to do here is preserve the sm state so that
1068*6523a3aaSJohn Levon 		 * smatch extra doesn't create a new sm state when it parses the
1069*6523a3aaSJohn Levon 		 * PARAM_LIMIT.
1070*6523a3aaSJohn Levon 		 */
1071*6523a3aaSJohn Levon 		if (!mixed && tmp->sym == sym &&
1072*6523a3aaSJohn Levon 		    strcmp(tmp->name, name) == 0 &&
1073*6523a3aaSJohn Levon 		    (!left_name || strcmp(left_name, name) != 0)) {
1074*6523a3aaSJohn Levon 			overwrite_sm_state_stree(implied, tmp);
1075*6523a3aaSJohn Levon 			continue;
1076*6523a3aaSJohn Levon 		}
1077*6523a3aaSJohn Levon 
1078*6523a3aaSJohn Levon 		// TODO why can't this just be __set_sm()?
10791f5207b7SJohn Levon 		__set_sm_fake_stree(tmp);
10801f5207b7SJohn Levon 	} END_FOR_EACH_SM(tmp);
10811f5207b7SJohn Levon 
10821f5207b7SJohn Levon 	free_stree(&implied_true);
10831f5207b7SJohn Levon 	free_stree(&implied_false);
10841f5207b7SJohn Levon free:
10851f5207b7SJohn Levon 	free_string(name);
10861f5207b7SJohn Levon }
10871f5207b7SJohn Levon 
__implied_case_stree(struct expression * switch_expr,struct range_list * rl,struct range_list_stack ** remaining_cases,struct stree ** raw_stree)10881f5207b7SJohn Levon struct stree *__implied_case_stree(struct expression *switch_expr,
10891f5207b7SJohn Levon 				   struct range_list *rl,
10901f5207b7SJohn Levon 				   struct range_list_stack **remaining_cases,
10911f5207b7SJohn Levon 				   struct stree **raw_stree)
10921f5207b7SJohn Levon {
10931f5207b7SJohn Levon 	char *name;
10941f5207b7SJohn Levon 	struct symbol *sym;
10951f5207b7SJohn Levon 	struct var_sym_list *vsl;
10961f5207b7SJohn Levon 	struct sm_state *sm;
10971f5207b7SJohn Levon 	struct stree *true_states = NULL;
10981f5207b7SJohn Levon 	struct stree *false_states = NULL;
10991f5207b7SJohn Levon 	struct stree *extra_states;
11001f5207b7SJohn Levon 	struct stree *ret = clone_stree(*raw_stree);
11011f5207b7SJohn Levon 
11021f5207b7SJohn Levon 	name = expr_to_chunk_sym_vsl(switch_expr, &sym, &vsl);
11031f5207b7SJohn Levon 
11041f5207b7SJohn Levon 	if (rl)
11051f5207b7SJohn Levon 		filter_top_rl(remaining_cases, rl);
11061f5207b7SJohn Levon 	else
11071f5207b7SJohn Levon 		rl = clone_rl(top_rl(*remaining_cases));
11081f5207b7SJohn Levon 
11091f5207b7SJohn Levon 	if (name) {
11101f5207b7SJohn Levon 		sm = get_sm_state_stree(*raw_stree, SMATCH_EXTRA, name, sym);
11111f5207b7SJohn Levon 		if (sm)
11121f5207b7SJohn Levon 			separate_and_filter(sm, SPECIAL_EQUAL, rl, *raw_stree, &true_states, &false_states, NULL);
11131f5207b7SJohn Levon 	}
11141f5207b7SJohn Levon 
11151f5207b7SJohn Levon 	__push_fake_cur_stree();
11161f5207b7SJohn Levon 	__unnullify_path();
11171f5207b7SJohn Levon 	if (name)
11181f5207b7SJohn Levon 		set_extra_nomod_vsl(name, sym, vsl, NULL, alloc_estate_rl(rl));
11191f5207b7SJohn Levon 	__pass_case_to_client(switch_expr, rl);
11201f5207b7SJohn Levon 	extra_states = __pop_fake_cur_stree();
11211f5207b7SJohn Levon 	overwrite_stree(extra_states, &true_states);
11221f5207b7SJohn Levon 	overwrite_stree(true_states, &ret);
11231f5207b7SJohn Levon 	free_stree(&extra_states);
11241f5207b7SJohn Levon 	free_stree(&true_states);
11251f5207b7SJohn Levon 	free_stree(&false_states);
11261f5207b7SJohn Levon 
11271f5207b7SJohn Levon 	free_string(name);
11281f5207b7SJohn Levon 	return ret;
11291f5207b7SJohn Levon }
11301f5207b7SJohn Levon 
match_end_func(struct symbol * sym)11311f5207b7SJohn Levon static void match_end_func(struct symbol *sym)
11321f5207b7SJohn Levon {
11331f5207b7SJohn Levon 	if (__inline_fn)
11341f5207b7SJohn Levon 		return;
11351f5207b7SJohn Levon 	implied_debug_msg = NULL;
11361f5207b7SJohn Levon }
11371f5207b7SJohn Levon 
get_tf_stacks_from_pool(struct sm_state * gate_sm,struct sm_state * pool_sm,struct state_list ** true_stack,struct state_list ** false_stack)11381f5207b7SJohn Levon static void get_tf_stacks_from_pool(struct sm_state *gate_sm,
11391f5207b7SJohn Levon 				    struct sm_state *pool_sm,
11401f5207b7SJohn Levon 				    struct state_list **true_stack,
11411f5207b7SJohn Levon 				    struct state_list **false_stack)
11421f5207b7SJohn Levon {
11431f5207b7SJohn Levon 	struct sm_state *tmp;
11441f5207b7SJohn Levon 	int possibly_true = 0;
11451f5207b7SJohn Levon 
11461f5207b7SJohn Levon 	if (!gate_sm)
11471f5207b7SJohn Levon 		return;
11481f5207b7SJohn Levon 
11491f5207b7SJohn Levon 	if (strcmp(gate_sm->state->name, pool_sm->state->name) == 0) {
11501f5207b7SJohn Levon 		add_ptr_list(true_stack, pool_sm);
11511f5207b7SJohn Levon 		return;
11521f5207b7SJohn Levon 	}
11531f5207b7SJohn Levon 
11541f5207b7SJohn Levon 	FOR_EACH_PTR(gate_sm->possible, tmp) {
11551f5207b7SJohn Levon 		if (strcmp(tmp->state->name, pool_sm->state->name) == 0) {
11561f5207b7SJohn Levon 			possibly_true = 1;
11571f5207b7SJohn Levon 			break;
11581f5207b7SJohn Levon 		}
11591f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
11601f5207b7SJohn Levon 
11611f5207b7SJohn Levon 	if (!possibly_true) {
11621f5207b7SJohn Levon 		add_ptr_list(false_stack, gate_sm);
11631f5207b7SJohn Levon 		return;
11641f5207b7SJohn Levon 	}
11651f5207b7SJohn Levon 
11661f5207b7SJohn Levon 	get_tf_stacks_from_pool(gate_sm->left, pool_sm, true_stack, false_stack);
11671f5207b7SJohn Levon 	get_tf_stacks_from_pool(gate_sm->right, pool_sm, true_stack, false_stack);
11681f5207b7SJohn Levon }
11691f5207b7SJohn Levon 
11701f5207b7SJohn Levon /*
11711f5207b7SJohn Levon  * The situation is we have a SMATCH_EXTRA state and we want to break it into
11721f5207b7SJohn Levon  * each of the ->possible states and find the implications of each.  The caller
11731f5207b7SJohn Levon  * has to use __push_fake_cur_stree() to preserve the correct states so they
11741f5207b7SJohn Levon  * can be restored later.
11751f5207b7SJohn Levon  */
overwrite_states_using_pool(struct sm_state * gate_sm,struct sm_state * pool_sm)11761f5207b7SJohn Levon void overwrite_states_using_pool(struct sm_state *gate_sm, struct sm_state *pool_sm)
11771f5207b7SJohn Levon {
11781f5207b7SJohn Levon 	struct state_list *true_stack = NULL;
11791f5207b7SJohn Levon 	struct state_list *false_stack = NULL;
11801f5207b7SJohn Levon 	struct stree *pre_stree;
11811f5207b7SJohn Levon 	struct stree *implied_true;
11821f5207b7SJohn Levon 	struct sm_state *tmp;
11831f5207b7SJohn Levon 
11841f5207b7SJohn Levon 	if (!pool_sm->pool)
11851f5207b7SJohn Levon 		return;
11861f5207b7SJohn Levon 
11871f5207b7SJohn Levon 	get_tf_stacks_from_pool(gate_sm, pool_sm, &true_stack, &false_stack);
11881f5207b7SJohn Levon 
11891f5207b7SJohn Levon 	pre_stree = clone_stree(__get_cur_stree());
11901f5207b7SJohn Levon 
11911f5207b7SJohn Levon 	implied_true = filter_stack(gate_sm, pre_stree, false_stack, true_stack);
11921f5207b7SJohn Levon 
11931f5207b7SJohn Levon 	free_stree(&pre_stree);
11941f5207b7SJohn Levon 	free_slist(&true_stack);
11951f5207b7SJohn Levon 	free_slist(&false_stack);
11961f5207b7SJohn Levon 
11971f5207b7SJohn Levon 	FOR_EACH_SM(implied_true, tmp) {
11981f5207b7SJohn Levon 		set_state(tmp->owner, tmp->name, tmp->sym, tmp->state);
11991f5207b7SJohn Levon 	} END_FOR_EACH_SM(tmp);
12001f5207b7SJohn Levon 
12011f5207b7SJohn Levon 	free_stree(&implied_true);
12021f5207b7SJohn Levon }
12031f5207b7SJohn Levon 
assume(struct expression * expr)12041f5207b7SJohn Levon int assume(struct expression *expr)
12051f5207b7SJohn Levon {
12061f5207b7SJohn Levon 	int orig_final_pass = final_pass;
12071f5207b7SJohn Levon 
12081f5207b7SJohn Levon 	in_fake_env++;
12091f5207b7SJohn Levon 	final_pass = 0;
12101f5207b7SJohn Levon 	__push_fake_cur_stree();
12111f5207b7SJohn Levon 	__split_whole_condition(expr);
12121f5207b7SJohn Levon 	final_pass = orig_final_pass;
12131f5207b7SJohn Levon 	in_fake_env--;
12141f5207b7SJohn Levon 
12151f5207b7SJohn Levon 	return 1;
12161f5207b7SJohn Levon }
12171f5207b7SJohn Levon 
end_assume(void)12181f5207b7SJohn Levon void end_assume(void)
12191f5207b7SJohn Levon {
12201f5207b7SJohn Levon 	__discard_false_states();
12211f5207b7SJohn Levon 	__free_fake_cur_stree();
12221f5207b7SJohn Levon }
12231f5207b7SJohn Levon 
impossible_assumption(struct expression * left,int op,sval_t sval)12241f5207b7SJohn Levon int impossible_assumption(struct expression *left, int op, sval_t sval)
12251f5207b7SJohn Levon {
12261f5207b7SJohn Levon 	struct expression *value;
12271f5207b7SJohn Levon 	struct expression *comparison;
12281f5207b7SJohn Levon 	int ret;
12291f5207b7SJohn Levon 
12301f5207b7SJohn Levon 	value = value_expr(sval.value);
12311f5207b7SJohn Levon 	comparison = compare_expression(left, op, value);
12321f5207b7SJohn Levon 
12331f5207b7SJohn Levon 	if (!assume(comparison))
12341f5207b7SJohn Levon 		return 0;
12351f5207b7SJohn Levon 	ret = is_impossible_path();
12361f5207b7SJohn Levon 	end_assume();
12371f5207b7SJohn Levon 
12381f5207b7SJohn Levon 	return ret;
12391f5207b7SJohn Levon }
12401f5207b7SJohn Levon 
12411f5207b7SJohn Levon void __extra_match_condition(struct expression *expr);
12421f5207b7SJohn Levon void __comparison_match_condition(struct expression *expr);
12431f5207b7SJohn Levon void __stored_condition(struct expression *expr);
register_implications(int id)12441f5207b7SJohn Levon void register_implications(int id)
12451f5207b7SJohn Levon {
12461f5207b7SJohn Levon 	add_hook(&save_implications_hook, CONDITION_HOOK);
12471f5207b7SJohn Levon 	add_hook(&set_implied_states, CONDITION_HOOK);
12481f5207b7SJohn Levon 	add_hook(&__extra_match_condition, CONDITION_HOOK);
12491f5207b7SJohn Levon 	add_hook(&__comparison_match_condition, CONDITION_HOOK);
12505a0e240fSJohn Levon 	add_hook(&set_extra_implied_states, CONDITION_HOOK);
12511f5207b7SJohn Levon 	add_hook(&__stored_condition, CONDITION_HOOK);
12521f5207b7SJohn Levon 	add_hook(&match_end_func, END_FUNC_HOOK);
12531f5207b7SJohn Levon }
1254