2 * sparse/smatch_constraints.c
4 * Copyright (C) 2010 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
11 * smatch_constraints.c is for tracking how variables are related
17 * This is stored in a field in the smatch_extra dinfo.
19 * Normally the way that variables become related is through a
20 * condition and you say: add_constraint_expr(left, '<', right);
21 * The other way it can happen is if you have an assignment:
22 * set_equiv(left, right);
24 * One two variables "a" and "b" are related if then if we find
25 * that "a" is greater than 0 we need to update "b".
27 * When a variable gets modified all the old relationships are
28 * deleted. remove_contraints(expr);
30 * Also we need an is_true_constraint(left, '<', right) and
31 * is_false_constraint (left, '<', right). This is used by
37 #include "smatch_slist.h"
38 #include "smatch_extra.h"
40 ALLOCATOR(relation
, "related variables");
42 static struct relation
*alloc_relation(int op
, const char *name
, struct symbol
*sym
)
46 tmp
= __alloc_relation(0);
48 tmp
->name
= alloc_string(name
);
53 struct related_list
*clone_related_list(struct related_list
*related
)
56 struct related_list
*to_list
= NULL
;
58 FOR_EACH_PTR(related
, rel
) {
59 add_ptr_list(&to_list
, rel
);
60 } END_FOR_EACH_PTR(rel
);
65 struct relation
*get_common_relationship(struct data_info
*dinfo
, int op
,
66 const char *name
, struct symbol
*sym
)
71 // Find the common x < y and x <= y
72 FOR_EACH_PTR(dinfo
->related
, tmp
) {
73 if (tmp
->op
< op
|| tmp
->sym
< sym
|| strcmp(tmp
->name
, name
) < 0)
75 if (tmp
->op
== op
&& tmp
->sym
== sym
&& !strcmp(tmp
->name
, name
))
78 } END_FOR_EACH_PTR(tmp
);
82 void add_related(struct smatch_state
*state
, int op
, const char *name
, struct symbol
*sym
)
84 struct data_info
*dinfo
;
88 dinfo
= get_dinfo(state
);
89 FOR_EACH_PTR(dinfo
->related
, tmp
) {
90 if (tmp
->op
< op
|| tmp
->sym
< sym
|| strcmp(tmp
->name
, name
) < 0)
92 if (tmp
->op
== op
&& tmp
->sym
== sym
&& !strcmp(tmp
->name
, name
))
94 new = alloc_relation(op
, name
, sym
);
95 INSERT_CURRENT(new, tmp
);
97 } END_FOR_EACH_PTR(tmp
);
98 new = alloc_relation(op
, name
, sym
);
99 add_ptr_list(&dinfo
->related
, new);
102 void del_related(struct smatch_state
*state
, int op
, const char *name
, struct symbol
*sym
)
104 struct data_info
*dinfo
;
105 struct relation
*tmp
;
107 dinfo
= get_dinfo(state
);
108 FOR_EACH_PTR(dinfo
->related
, tmp
) {
109 if (tmp
->sym
< sym
|| strcmp(tmp
->name
, name
) < 0)
111 if (tmp
->sym
== sym
&& !strcmp(tmp
->name
, name
)) {
112 DELETE_CURRENT_PTR(tmp
);
116 } END_FOR_EACH_PTR(tmp
);
119 void add_equiv(struct smatch_state
*state
, const char *name
, struct symbol
*sym
)
121 add_related(state
, SPECIAL_EQUAL
, name
, sym
);
124 static void del_equiv(struct smatch_state
*state
, const char *name
, struct symbol
*sym
)
126 del_related(state
, SPECIAL_EQUAL
, name
, sym
);
129 void remove_from_equiv(const char *name
, struct symbol
*sym
)
131 struct sm_state
*orig_sm
;
132 struct relation
*rel
;
133 struct smatch_state
*state
;
134 struct related_list
*to_update
;
136 // FIXME equiv => related
137 orig_sm
= get_sm_state(SMATCH_EXTRA
, name
, sym
);
138 if (!orig_sm
|| !get_dinfo(orig_sm
->state
)->related
)
141 state
= clone_extra_state(orig_sm
->state
);
142 del_equiv(state
, name
, sym
);
143 to_update
= get_dinfo(state
)->related
;
144 if (ptr_list_size((struct ptr_list
*)get_dinfo(state
)->related
) == 1)
145 get_dinfo(state
)->related
= NULL
;
147 FOR_EACH_PTR(to_update
, rel
) {
148 struct sm_state
*new_sm
;
150 new_sm
= clone_sm(orig_sm
);
151 new_sm
->name
= rel
->name
;
152 new_sm
->sym
= rel
->sym
;
153 new_sm
->state
= state
;
155 } END_FOR_EACH_PTR(rel
);
158 void remove_from_equiv_expr(struct expression
*expr
)
163 name
= get_variable_from_expr(expr
, &sym
);
166 remove_from_equiv(name
, sym
);
171 void add_constrain_expr(struct expression
*left
, int op
, struct expression
*right
)
176 void set_equiv_state_expr(int id
, struct expression
*expr
, struct smatch_state
*state
)
178 struct relation
*rel
;
179 struct smatch_state
*extra_state
;
181 extra_state
= get_state_expr(SMATCH_EXTRA
, expr
);
186 FOR_EACH_PTR(get_dinfo(extra_state
)->related
, rel
) {
187 if (rel
->op
!= SPECIAL_EQUAL
)
189 set_state(id
, rel
->name
, rel
->sym
, state
);
190 } END_FOR_EACH_PTR(rel
);