]>
Commit | Line | Data |
---|---|---|
65f973be | 1 | /* |
11db3170 | 2 | ** Splint - annotation-assisted static program checker |
c59f5181 | 3 | ** Copyright (C) 1994-2003 University of Virginia, |
65f973be | 4 | ** Massachusetts Institute of Technology |
5 | ** | |
6 | ** This program is free software; you can redistribute it and/or modify it | |
7 | ** under the terms of the GNU General Public License as published by the | |
8 | ** Free Software Foundation; either version 2 of the License, or (at your | |
9 | ** option) any later version. | |
10 | ** | |
11 | ** This program is distributed in the hope that it will be useful, but | |
12 | ** WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | ** General Public License for more details. | |
15 | ** | |
16 | ** The GNU General Public License is available from http://www.gnu.org/ or | |
17 | ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | |
18 | ** MA 02111-1307, USA. | |
19 | ** | |
155af98d | 20 | ** For information on splint: info@splint.org |
21 | ** To report a bug: splint-bug@splint.org | |
11db3170 | 22 | ** For more information: http://www.splint.org |
65f973be | 23 | */ |
24 | ||
616915dd | 25 | /* |
26 | * | |
27 | ** constraintResolve.c | |
28 | */ | |
29 | ||
b7b694d6 | 30 | /* #define DEBUGPRINT 1 */ |
616915dd | 31 | |
32 | # include <ctype.h> /* for isdigit */ | |
1b8ae690 | 33 | # include "splintMacros.nf" |
616915dd | 34 | # include "basic.h" |
35 | # include "cgrammar.h" | |
36 | # include "cgrammar_tokens.h" | |
37 | ||
38 | # include "exprChecks.h" | |
616915dd | 39 | # include "exprNodeSList.h" |
616915dd | 40 | |
616915dd | 41 | |
393e573f | 42 | /*@access constraint, exprNode @*/ /*!!! NO! Don't do this so recklessly - design your code more carefully so you don't need to! */ |
43 | ||
28bf4b0b | 44 | static constraint inequalitySubstitute (/*@returned@*/ constraint p_c, constraintList p_p); |
616915dd | 45 | |
616915dd | 46 | |
28bf4b0b | 47 | static bool rangeCheck (arithType p_ar1, /*@observer@*/ constraintExpr p_expr1, arithType p_ar2, /*@observer@*/ constraintExpr p_expr2); |
616915dd | 48 | |
28bf4b0b | 49 | static constraint inequalitySubstituteUnsound (/*@returned@*/ constraint p_c, constraintList p_p); |
616915dd | 50 | |
dc7f6a51 | 51 | static constraint inequalitySubstituteStrong (/*@returned@*/ constraint p_c, constraintList p_p); |
52 | ||
28bf4b0b | 53 | static constraint constraint_searchandreplace (/*@returned@*/ constraint p_c, constraintExpr p_old, constraintExpr p_newExpr); |
bb25bea6 | 54 | |
28bf4b0b | 55 | |
56 | static constraint constraint_addOr (/*@returned@*/ constraint p_orig, /*@observer@*/ constraint p_orConstr); | |
57 | ||
9a48d98c | 58 | static bool constraint_resolveOr (/*@temp@*/constraint p_c, /*@observer@*/ /*@temp@*/ constraintList p_list); |
28bf4b0b | 59 | |
60 | static /*@only@*/ constraintList reflectChangesEnsuresFree1 (/*@only@*/ constraintList p_pre2, constraintList p_post1); | |
616915dd | 61 | |
9a48d98c | 62 | /*@only@*/ constraintList |
63 | constraintList_mergeEnsuresFreeFirst (constraintList list1, constraintList list2) | |
bb25bea6 | 64 | { |
9a48d98c | 65 | constraintList ret = constraintList_mergeEnsures (list1, list2); |
66 | constraintList_free (list1); | |
bb25bea6 | 67 | return ret; |
68 | } | |
616915dd | 69 | |
9a48d98c | 70 | /*@only@*/ constraintList |
71 | constraintList_mergeEnsures (constraintList list1, constraintList list2) | |
616915dd | 72 | { |
73 | constraintList ret; | |
74 | constraintList temp; | |
470b7798 | 75 | |
9a48d98c | 76 | llassert (constraintList_isDefined (list1)); |
77 | llassert (constraintList_isDefined (list2)); | |
90bc41f7 | 78 | |
9a48d98c | 79 | DPRINTF (("constraintList_mergeEnsures: list1 %s list2 %s", |
80 | constraintList_unparse (list1), constraintList_unparse (list2))); | |
616915dd | 81 | |
90bc41f7 | 82 | ret = constraintList_fixConflicts (list1, list2); |
bb25bea6 | 83 | ret = reflectChangesEnsuresFree1 (ret, list2); |
d46ce6a4 | 84 | temp = constraintList_subsumeEnsures (ret, list2); |
9a48d98c | 85 | constraintList_free (ret); |
d46ce6a4 | 86 | |
9a48d98c | 87 | ret = temp; |
d46ce6a4 | 88 | temp = constraintList_subsumeEnsures (list2, ret); |
616915dd | 89 | temp = constraintList_addList (temp, ret); |
9a48d98c | 90 | constraintList_free (ret); |
4ab867d6 | 91 | |
9a48d98c | 92 | DPRINTF (("constraintList_mergeEnsures: returning %s", constraintList_unparse (temp))); |
616915dd | 93 | return temp; |
616915dd | 94 | } |
95 | ||
9a48d98c | 96 | /*@only@*/ constraintList |
97 | constraintList_mergeRequiresFreeFirst (/*@only@*/ constraintList list1, | |
98 | constraintList list2) | |
bb25bea6 | 99 | { |
9a48d98c | 100 | constraintList ret = constraintList_mergeRequires (list1, list2); |
101 | constraintList_free (list1); | |
bb25bea6 | 102 | return ret; |
103 | } | |
104 | ||
9a48d98c | 105 | /*@only@*/ constraintList |
106 | constraintList_mergeRequires (constraintList list1, constraintList list2) | |
470b7798 | 107 | { |
108 | constraintList ret; | |
109 | constraintList temp; | |
110 | ||
9a48d98c | 111 | DPRINTF (("constraintList_mergeRequires: merging %s and %s", |
112 | constraintList_unparse (list1), constraintList_unparse (list2))); | |
470b7798 | 113 | |
9a48d98c | 114 | if (context_getFlag (FLG_REDUNDANTCONSTRAINTS)) |
4a689c7f | 115 | { |
9a48d98c | 116 | ret = constraintList_copy (list1); |
117 | ret = constraintList_addList (ret, list2); | |
4a689c7f | 118 | return ret; |
119 | } | |
9a48d98c | 120 | |
470b7798 | 121 | /* get constraints in list1 not satified by list2 */ |
9a48d98c | 122 | temp = constraintList_reflectChanges (list1, list2); |
123 | DPRINTF (("constraintList_mergeRequires: temp = %s", constraintList_unparse (temp))); | |
124 | ||
125 | /* get constraints in list2 not satified by temp*/ | |
126 | ret = constraintList_reflectChanges (list2, temp); | |
127 | DPRINTF (("constraintList_mergeRequires: ret = %s", constraintList_unparse(ret))); | |
470b7798 | 128 | |
4ab867d6 | 129 | ret = constraintList_addListFree (ret, temp); |
9a48d98c | 130 | DPRINTF (("constraintList_mergeRequires: returning %s", constraintList_unparse(ret))); |
470b7798 | 131 | |
470b7798 | 132 | return ret; |
133 | } | |
616915dd | 134 | |
28bf4b0b | 135 | /* old name mergeResolve renamed for czech naming convention */ |
136 | void exprNode_mergeResolve (exprNode parent, exprNode child1, exprNode child2) | |
616915dd | 137 | { |
d46ce6a4 | 138 | constraintList temp, temp2; |
616915dd | 139 | |
9a48d98c | 140 | DPRINTF((message ("magically merging constraint into parent:%s for", exprNode_unparse (parent)))); |
616915dd | 141 | |
9a48d98c | 142 | DPRINTF((message (" children: %s and %s", exprNode_unparse (child1), exprNode_unparse(child2)))); |
616915dd | 143 | |
9a48d98c | 144 | if (exprNode_isUndefined (parent)) |
a64ebe74 | 145 | { |
9a48d98c | 146 | llassert (exprNode_isDefined (parent)); |
a64ebe74 | 147 | return; |
148 | } | |
149 | ||
150 | ||
9a48d98c | 151 | if (exprNode_isError (child1) || exprNode_isError (child2)) |
d46ce6a4 | 152 | { |
9a48d98c | 153 | if (exprNode_isError (child1) && !exprNode_isError (child2)) |
616915dd | 154 | { |
9a48d98c | 155 | constraintList_free (parent->requiresConstraints); |
616915dd | 156 | parent->requiresConstraints = constraintList_copy (child2->requiresConstraints); |
9a48d98c | 157 | constraintList_free (parent->ensuresConstraints); |
d46ce6a4 | 158 | |
616915dd | 159 | parent->ensuresConstraints = constraintList_copy (child2->ensuresConstraints); |
9a48d98c | 160 | DPRINTF (("Copied child constraints: pre: %s and post: %s", |
161 | constraintList_unparse(child2->requiresConstraints), | |
162 | constraintList_unparse (child2->ensuresConstraints))); | |
616915dd | 163 | return; |
164 | } | |
165 | else | |
166 | { | |
9a48d98c | 167 | llassert (exprNode_isError (child2)); |
616915dd | 168 | return; |
169 | } | |
170 | } | |
171 | ||
9a48d98c | 172 | llassert (!exprNode_isError (child1) && !exprNode_isError (child2)); |
616915dd | 173 | |
9a48d98c | 174 | DPRINTF (("Child constraints are %s %s and %s %s", |
175 | constraintList_unparse (child1->requiresConstraints), | |
176 | constraintList_unparse (child1->ensuresConstraints), | |
177 | constraintList_unparse (child2->requiresConstraints), | |
178 | constraintList_unparse (child2->ensuresConstraints))); | |
616915dd | 179 | |
9a48d98c | 180 | constraintList_free (parent->requiresConstraints); |
181 | parent->requiresConstraints = constraintList_copy (child1->requiresConstraints); | |
182 | ||
183 | if (context_getFlag (FLG_ORCONSTRAINT)) | |
184 | { | |
185 | temp = constraintList_reflectChangesOr (child2->requiresConstraints, child1->ensuresConstraints); | |
186 | } | |
187 | else | |
188 | { | |
189 | temp = constraintList_reflectChanges(child2->requiresConstraints, child1->ensuresConstraints); | |
190 | } | |
191 | ||
192 | temp2 = constraintList_mergeRequires (parent->requiresConstraints, temp); | |
193 | constraintList_free (parent->requiresConstraints); | |
194 | constraintList_free (temp); | |
195 | ||
196 | parent->requiresConstraints = temp2; | |
197 | ||
198 | DPRINTF (("Parent requires constraints are %s ", | |
199 | constraintList_unparse (parent->requiresConstraints))); | |
200 | ||
201 | constraintList_free (parent->ensuresConstraints); | |
202 | ||
203 | parent->ensuresConstraints = constraintList_mergeEnsures (child1->ensuresConstraints, | |
204 | child2->ensuresConstraints); | |
205 | ||
206 | ||
207 | DPRINTF (("Parent constraints are %s and %s ", | |
208 | constraintList_unparse (parent->requiresConstraints), | |
209 | constraintList_unparse (parent->ensuresConstraints))); | |
616915dd | 210 | } |
616915dd | 211 | |
9a48d98c | 212 | /*@only@*/ constraintList |
213 | constraintList_subsumeEnsures (constraintList list1, constraintList list2) | |
616915dd | 214 | { |
9a48d98c | 215 | constraintList ret = constraintList_makeNew (); |
216 | ||
616915dd | 217 | constraintList_elements (list1, el) |
218 | { | |
9a48d98c | 219 | DPRINTF (("Examining %s", constraint_unparse (el))); |
220 | if (!constraintList_resolve (el, list2)) | |
616915dd | 221 | { |
9a48d98c | 222 | constraint temp = constraint_copy (el); |
d46ce6a4 | 223 | ret = constraintList_add (ret, temp); |
616915dd | 224 | } |
225 | else | |
226 | { | |
9a48d98c | 227 | DPRINTF (("Subsuming %s", constraint_unparse (el))); |
616915dd | 228 | } |
229 | } end_constraintList_elements; | |
230 | ||
231 | return ret; | |
232 | } | |
233 | ||
bb25bea6 | 234 | /* tries to resolve constraints in list pre2 using post1 */ |
9a48d98c | 235 | /*@only@*/ constraintList |
236 | constraintList_reflectChangesFreePre (/*@only@*/ constraintList pre2, /*@observer@*/ constraintList post1) | |
bb25bea6 | 237 | { |
9a48d98c | 238 | constraintList ret = constraintList_reflectChanges(pre2, post1); |
bb25bea6 | 239 | constraintList_free (pre2); |
bb25bea6 | 240 | return ret; |
241 | } | |
242 | ||
243 | ||
dc7f6a51 | 244 | |
90bc41f7 | 245 | /* tries to resolve constraints in list pre2 using post1 */ |
9a48d98c | 246 | static /*@only@*/ constraintList |
247 | constraintList_reflectChangesNoOr (/*@observer@*/ /*@temp@*/ constraintList pre2, | |
248 | /*@observer@*/ /*@temp@*/ constraintList post1) | |
616915dd | 249 | { |
9a48d98c | 250 | constraintList ret = constraintList_makeNew (); |
616915dd | 251 | |
9a48d98c | 252 | llassert (!context_getFlag (FLG_ORCONSTRAINT)); |
253 | ||
254 | DPRINTF (("reflectChanges: lists %s and %s", | |
255 | constraintList_unparse (pre2), constraintList_unparse (post1))); | |
616915dd | 256 | |
257 | constraintList_elements (pre2, el) | |
258 | { | |
9a48d98c | 259 | if (!constraintList_resolve (el, post1)) |
616915dd | 260 | { |
9a48d98c | 261 | constraint temp = constraint_substitute (el, post1); |
262 | ||
263 | if (!constraintList_resolve (temp, post1)) | |
616915dd | 264 | { |
b7b694d6 | 265 | /* try inequality substitution |
266 | the inequality substitution may cause us to lose information | |
267 | so we don't want to store the result but we do it anyway | |
268 | */ | |
9a48d98c | 269 | constraint temp2 = constraint_copy (temp); |
920a3797 | 270 | temp2 = inequalitySubstitute (temp2, post1); |
9a48d98c | 271 | |
272 | if (!constraintList_resolve (temp2, post1)) | |
920a3797 | 273 | { |
274 | temp2 = inequalitySubstituteUnsound (temp2, post1); | |
9a48d98c | 275 | if (!constraintList_resolve (temp2, post1)) |
276 | { | |
277 | ret = constraintList_add (ret, temp2); | |
278 | } | |
920a3797 | 279 | else |
9a48d98c | 280 | { |
281 | constraint_free (temp2); | |
282 | } | |
920a3797 | 283 | } |
284 | else | |
285 | { | |
9a48d98c | 286 | constraint_free (temp2); |
920a3797 | 287 | } |
616915dd | 288 | } |
9a48d98c | 289 | constraint_free (temp); |
616915dd | 290 | } |
291 | } end_constraintList_elements; | |
292 | ||
9a48d98c | 293 | DPRINTF (("reflectChanges: returning %s", constraintList_unparse(ret))); |
294 | return ret; | |
616915dd | 295 | } |
296 | ||
dc7f6a51 | 297 | /* tries to resolve constraints in list pre2 using post1 */ |
9a48d98c | 298 | /*@only@*/ constraintList |
299 | constraintList_reflectChanges (/*@observer@*/ constraintList pre2, /*@observer@*/ constraintList post1) | |
dc7f6a51 | 300 | { |
9a48d98c | 301 | if (context_getFlag (FLG_ORCONSTRAINT)) |
302 | { | |
303 | return constraintList_reflectChangesOr (pre2, post1); | |
304 | } | |
dc7f6a51 | 305 | else |
9a48d98c | 306 | { |
307 | return constraintList_reflectChangesNoOr (pre2, post1); | |
308 | } | |
dc7f6a51 | 309 | } |
616915dd | 310 | |
9a48d98c | 311 | static constraint |
312 | constraint_addOr (/*@returned@*/ constraint orig, /*@observer@*/ constraint orConstr) | |
90bc41f7 | 313 | { |
9a48d98c | 314 | constraint c = orig; |
315 | llassert (constraint_isDefined (c)); | |
a64ebe74 | 316 | |
9a48d98c | 317 | DPRINTF (("constraint_addor: oring %s onto %s", |
318 | constraint_unparseOr (orConstr), constraint_unparseOr (orig))); | |
90bc41f7 | 319 | |
320 | while (c->or != NULL) | |
321 | { | |
322 | c = c->or; | |
323 | } | |
a779b61e | 324 | |
9a48d98c | 325 | c->or = constraint_copy (orConstr); |
90bc41f7 | 326 | |
9a48d98c | 327 | DPRINTF (("constraint_addor: returning %s",constraint_unparseOr (orig))); |
90bc41f7 | 328 | return orig; |
329 | } | |
330 | ||
9a48d98c | 331 | static bool constraint_resolveOr (/*@temp@*/ constraint c, /*@observer@*/ /*@temp@*/ constraintList list) |
90bc41f7 | 332 | { |
9a48d98c | 333 | constraint temp = c; |
334 | int numberOr = 0; | |
a64ebe74 | 335 | |
9a48d98c | 336 | llassert (constraint_isDefined(c)); |
337 | DPRINTF (("constraint_resolveOr: constraint %s and list %s", | |
338 | constraint_printOr (c), constraintList_print (list))); | |
a64ebe74 | 339 | |
90bc41f7 | 340 | do |
341 | { | |
9a48d98c | 342 | if (constraintList_resolve (temp, list)) |
343 | { | |
344 | return TRUE; | |
345 | } | |
346 | ||
90bc41f7 | 347 | temp = temp->or; |
a779b61e | 348 | numberOr++; |
349 | llassert(numberOr <= 10); | |
90bc41f7 | 350 | } |
9a48d98c | 351 | while (constraint_isDefined (temp)); |
90bc41f7 | 352 | |
353 | return FALSE; | |
354 | } | |
355 | ||
9a48d98c | 356 | /* This is a "helper" function for doResolveOr */ |
90bc41f7 | 357 | |
bb25bea6 | 358 | static /*@only@*/ constraint doResolve (/*@only@*/ constraint c, constraintList post1, bool * resolved) |
90bc41f7 | 359 | { |
9a48d98c | 360 | llassert (constraint_isDefined (c)); |
a779b61e | 361 | |
9a48d98c | 362 | DPRINTF (("doResolve:: call on constraint c = : %q and constraintList %q", |
363 | constraint_unparseOr (c), constraintList_unparse (post1))); | |
90bc41f7 | 364 | |
9a48d98c | 365 | if (!constraint_resolveOr (c, post1)) |
366 | { | |
367 | constraint temp = constraint_substitute (c, post1); | |
368 | DPRINTF (("doResolve:: after substitute temp is %q", constraint_unparseOr (temp))); | |
d9daf826 | 369 | |
9a48d98c | 370 | if (!constraint_resolveOr (temp, post1)) |
90bc41f7 | 371 | { |
b7b694d6 | 372 | /* try inequality substitution */ |
9a48d98c | 373 | constraint temp2 = constraint_copy (c); |
bb25bea6 | 374 | |
9a48d98c | 375 | /* |
376 | ** the inequality substitution may cause us to lose information | |
377 | ** so we don't want to store the result but we do anyway | |
b7b694d6 | 378 | */ |
9a48d98c | 379 | |
b7b694d6 | 380 | temp2 = inequalitySubstitute (temp2, post1); |
381 | ||
9a48d98c | 382 | if (!constraint_resolveOr (temp2, post1)) |
b7b694d6 | 383 | { |
9a48d98c | 384 | constraint temp3 = constraint_copy(temp2); |
b7b694d6 | 385 | temp3 = inequalitySubstituteStrong (temp3, post1); |
9a48d98c | 386 | |
387 | if (!constraint_resolveOr (temp3, post1)) | |
bb25bea6 | 388 | { |
b7b694d6 | 389 | temp2 = inequalitySubstituteUnsound (temp2, post1); |
9a48d98c | 390 | |
391 | if (!constraint_resolveOr (temp2, post1)) | |
dc7f6a51 | 392 | { |
9a48d98c | 393 | if (!constraint_same (temp, temp2)) |
d9daf826 | 394 | { |
395 | /* drl added 8/28/2002*/ | |
396 | /*make sure that the information from | |
397 | a post condition like i = i + 1 is transfered | |
398 | */ | |
399 | constraint tempSub; | |
400 | tempSub = constraint_substitute (temp2, post1); | |
401 | ||
9a48d98c | 402 | DPRINTF (("doResolve: adding %s", constraint_unparseOr (tempSub))); |
403 | DPRINTF (("doResolve: not adding %s", constraint_unparseOr (temp2))); | |
404 | ||
d9daf826 | 405 | temp = constraint_addOr (temp, tempSub); |
9a48d98c | 406 | constraint_free (tempSub); |
d9daf826 | 407 | } |
9a48d98c | 408 | |
409 | if (!constraint_same (temp, temp3) && !constraint_same (temp3, temp2)) | |
d9daf826 | 410 | { |
9a48d98c | 411 | /* drl added 8/28/2002*/ |
412 | /* make sure that the information from | |
413 | a post condition like i = i + 1 is transfered | |
d9daf826 | 414 | */ |
415 | constraint tempSub; | |
416 | ||
417 | tempSub = constraint_substitute (temp3, post1); | |
418 | ||
9a48d98c | 419 | DPRINTF (("doResolve: adding %s", constraint_unparseOr (tempSub))); |
420 | DPRINTF (("doResolve: not adding %s", constraint_unparseOr(temp3))); | |
d9daf826 | 421 | |
422 | temp = constraint_addOr (temp, tempSub); | |
d9daf826 | 423 | constraint_free(tempSub); |
424 | } | |
9a48d98c | 425 | |
b7b694d6 | 426 | *resolved = FALSE; |
427 | ||
9a48d98c | 428 | constraint_free (temp2); |
429 | constraint_free (temp3); | |
430 | constraint_free (c); | |
b7b694d6 | 431 | |
432 | return temp; | |
bb25bea6 | 433 | } |
9a48d98c | 434 | |
435 | constraint_free (temp2); | |
436 | constraint_free (temp3); | |
bb25bea6 | 437 | } |
dc7f6a51 | 438 | else |
439 | { | |
9a48d98c | 440 | constraint_free (temp2); |
441 | constraint_free (temp3); | |
b7b694d6 | 442 | } |
90bc41f7 | 443 | } |
b7b694d6 | 444 | else |
445 | { | |
9a48d98c | 446 | constraint_free (temp2); |
b7b694d6 | 447 | } |
448 | ||
90bc41f7 | 449 | } |
9a48d98c | 450 | constraint_free (temp); |
b7b694d6 | 451 | } |
9a48d98c | 452 | |
453 | constraint_free (c); | |
454 | /*@i523@*/ /*drl bee: pbr*/ *resolved = TRUE; | |
b7b694d6 | 455 | return NULL; |
90bc41f7 | 456 | } |
457 | ||
9a48d98c | 458 | static /*@only@*/ constraint |
459 | doResolveOr (/*@observer@*/ /*@temp@*/ constraint c, constraintList post1, /*@out@*/ bool *resolved) | |
90bc41f7 | 460 | { |
461 | constraint ret; | |
462 | constraint next; | |
463 | constraint curr; | |
a779b61e | 464 | |
9a48d98c | 465 | DPRINTF (("doResolveOr: constraint %s and list %s", |
466 | constraint_unparseOr (c), constraintList_unparse (post1))); | |
90bc41f7 | 467 | |
9a48d98c | 468 | /*@i523@*/ /*drl bee: pbr*/ *resolved = FALSE; |
469 | ||
470 | llassert (constraint_isDefined (c)); | |
471 | ret = constraint_copy (c); | |
a779b61e | 472 | |
9a48d98c | 473 | llassert (constraint_isDefined (ret)); |
a64ebe74 | 474 | |
9a48d98c | 475 | if (constraintList_isEmpty (post1)) |
a779b61e | 476 | { |
477 | return ret; | |
478 | } | |
479 | ||
90bc41f7 | 480 | next = ret->or; |
481 | ret->or = NULL; | |
482 | ||
483 | ret = doResolve (ret, post1, resolved); | |
9a48d98c | 484 | |
bb25bea6 | 485 | if (*resolved) |
486 | { | |
2934b455 | 487 | if (next != NULL) |
9a48d98c | 488 | { |
489 | constraint_free (next); | |
490 | } | |
920a3797 | 491 | |
9a48d98c | 492 | /* we don't need to free ret when resolved is false because ret is null*/ |
493 | llassert (ret == NULL); | |
a779b61e | 494 | return NULL; |
bb25bea6 | 495 | } |
a779b61e | 496 | |
84c9ffbf | 497 | while (next != NULL) |
90bc41f7 | 498 | { |
499 | curr = next; | |
500 | next = curr->or; | |
501 | curr->or = NULL; | |
9a48d98c | 502 | |
90bc41f7 | 503 | curr = doResolve (curr, post1, resolved); |
a779b61e | 504 | |
9a48d98c | 505 | /*@i423@*/ /*drl bee: pbr*/ if (*resolved) |
bb25bea6 | 506 | { |
4ab867d6 | 507 | /* curr is null so we don't try to free it*/ |
9a48d98c | 508 | llassert (curr == NULL); |
4ab867d6 | 509 | |
2934b455 | 510 | if (next != NULL) |
9a48d98c | 511 | { |
512 | constraint_free (next); | |
513 | } | |
920a3797 | 514 | |
9a48d98c | 515 | constraint_free (ret); |
920a3797 | 516 | return NULL; |
bb25bea6 | 517 | } |
90bc41f7 | 518 | ret = constraint_addOr (ret, curr); |
4ab867d6 | 519 | constraint_free(curr); |
90bc41f7 | 520 | } |
90bc41f7 | 521 | return ret; |
522 | } | |
523 | ||
90bc41f7 | 524 | /* tries to resolve constraints in list pr2 using post1 */ |
9a48d98c | 525 | /*@only@*/ constraintList |
526 | constraintList_reflectChangesOr (constraintList pre2, constraintList post1) | |
90bc41f7 | 527 | { |
528 | bool resolved; | |
529 | constraintList ret; | |
530 | constraint temp; | |
c3e695ff | 531 | ret = constraintList_makeNew(); |
9a48d98c | 532 | |
533 | DPRINTF (("constraintList_reflectChangesOr: lists %s and %s", | |
534 | constraintList_unparse (pre2), constraintList_unparse (post1))); | |
90bc41f7 | 535 | |
536 | constraintList_elements (pre2, el) | |
537 | { | |
538 | temp = doResolveOr (el, post1, &resolved); | |
9a48d98c | 539 | |
90bc41f7 | 540 | if (!resolved) |
541 | { | |
542 | ret = constraintList_add(ret, temp); | |
543 | } | |
920a3797 | 544 | else |
545 | { | |
9a48d98c | 546 | /* we don't need to free temp when |
547 | resolved is false because temp is null */ | |
548 | llassert (temp == NULL); | |
920a3797 | 549 | } |
90bc41f7 | 550 | } end_constraintList_elements; |
9a48d98c | 551 | |
552 | DPRINTF (("constraintList_reflectChangesOr: returning %s", constraintList_unparse (ret))); | |
553 | return ret; | |
90bc41f7 | 554 | } |
a779b61e | 555 | |
9a48d98c | 556 | static /*@only@*/ constraintList |
557 | reflectChangesEnsures (/*@observer@*/ constraintList pre2, constraintList post1) | |
616915dd | 558 | { |
9a48d98c | 559 | constraintList ret = constraintList_makeNew (); |
560 | ||
616915dd | 561 | constraintList_elements (pre2, el) |
562 | { | |
9a48d98c | 563 | if (!constraintList_resolve (el, post1)) |
616915dd | 564 | { |
9a48d98c | 565 | constraint temp = constraint_substitute (el, post1); |
616915dd | 566 | llassert (temp != NULL); |
9a48d98c | 567 | |
568 | if (!constraintList_resolve (temp, post1)) | |
569 | { | |
570 | ret = constraintList_add (ret, temp); | |
571 | } | |
920a3797 | 572 | else |
9a48d98c | 573 | { |
574 | constraint_free (temp); | |
575 | } | |
616915dd | 576 | } |
577 | else | |
578 | { | |
9a48d98c | 579 | DPRINTF (("Resolved away %s ", constraint_unparse(el))); |
616915dd | 580 | } |
581 | } end_constraintList_elements; | |
9a48d98c | 582 | |
583 | return ret; | |
616915dd | 584 | } |
585 | ||
586 | ||
9a48d98c | 587 | static /*@only@*/ constraintList |
588 | reflectChangesEnsuresFree1 (/*@only@*/ constraintList pre2, constraintList post1) | |
bb25bea6 | 589 | { |
9a48d98c | 590 | constraintList ret = reflectChangesEnsures (pre2, post1); |
bb25bea6 | 591 | constraintList_free(pre2); |
bb25bea6 | 592 | return ret; |
593 | } | |
594 | ||
595 | ||
596 | static bool constraint_conflict (constraint c1, constraint c2) | |
616915dd | 597 | { |
9a48d98c | 598 | llassert (constraint_isDefined (c1)); |
599 | llassert (constraint_isDefined (c2)); | |
a64ebe74 | 600 | |
9a48d98c | 601 | if (constraintExpr_similar (c1->lexpr, c2->lexpr)) |
616915dd | 602 | { |
9a48d98c | 603 | if (c1->ar == EQ && (c1->ar == c2->ar)) |
604 | { | |
605 | DPRINTF (("%s conflicts with %s ", constraint_unparse (c1), constraint_unparse(c2))); | |
606 | return TRUE; | |
607 | } | |
616915dd | 608 | } |
9a48d98c | 609 | |
610 | /* | |
611 | ** This is a slight kludge to prevent circular constraints like | |
612 | ** strlen(str) == maxRead(s) + strlen(str); | |
b7b694d6 | 613 | */ |
a779b61e | 614 | |
9a48d98c | 615 | if (c1->ar == EQ && (c1->ar == c2->ar)) |
616 | { | |
617 | if (constraintExpr_search (c1->lexpr, c2->expr)) | |
618 | { | |
619 | if (constraintExpr_isTerm (c1->lexpr)) | |
a779b61e | 620 | { |
9a48d98c | 621 | constraintTerm term = constraintExpr_getTerm (c1->lexpr); |
a779b61e | 622 | |
9a48d98c | 623 | if (constraintTerm_isExprNode (term)) |
a779b61e | 624 | { |
9a48d98c | 625 | DPRINTF (("%s conflicts with %s ", constraint_unparse (c1), |
626 | constraint_unparse (c2))); | |
a779b61e | 627 | return TRUE; |
628 | } | |
629 | } | |
a779b61e | 630 | } |
9a48d98c | 631 | } |
616915dd | 632 | |
9a48d98c | 633 | if (constraint_tooDeep (c1) || constraint_tooDeep (c2)) |
634 | { | |
635 | DPRINTF (("%s conflicts with %s (constraint is too deep)", | |
636 | constraint_unparse (c1), constraint_unparse (c2))); | |
637 | return TRUE; | |
638 | } | |
639 | ||
640 | DPRINTF (("%s doesn't conflict with %s", | |
641 | constraint_unparse (c1), constraint_unparse (c2))); | |
616915dd | 642 | return FALSE; |
616915dd | 643 | } |
644 | ||
9a48d98c | 645 | static void |
646 | constraint_fixConflict (/*@temp@*/ constraint good, | |
647 | /*@temp@*/ /*@observer@*/ constraint conflicting) | |
648 | /*@modifies good@*/ | |
616915dd | 649 | { |
9a48d98c | 650 | llassert (constraint_isDefined (conflicting)); |
a64ebe74 | 651 | |
9a48d98c | 652 | if (conflicting->ar ==EQ) |
616915dd | 653 | { |
9a48d98c | 654 | llassert (constraint_isDefined (good)); |
616915dd | 655 | good->expr = constraintExpr_searchandreplace (good->expr, conflicting->lexpr, conflicting->expr); |
d46ce6a4 | 656 | good = constraint_simplify (good); |
616915dd | 657 | } |
616915dd | 658 | } |
659 | ||
bb25bea6 | 660 | static bool conflict (constraint c, constraintList list) |
616915dd | 661 | { |
90bc41f7 | 662 | constraintList_elements (list, el) |
616915dd | 663 | { |
9a48d98c | 664 | if (constraint_conflict (el, c)) |
616915dd | 665 | { |
666 | constraint_fixConflict (el, c); | |
667 | return TRUE; | |
668 | } | |
669 | } end_constraintList_elements; | |
9a48d98c | 670 | |
671 | return FALSE; | |
616915dd | 672 | } |
673 | ||
b7b694d6 | 674 | /* |
9a48d98c | 675 | ** Check if constraint in list1 conflicts with constraints in List2. If so we |
676 | ** remove form list1 and change list2. | |
b7b694d6 | 677 | */ |
678 | ||
84c9ffbf | 679 | constraintList constraintList_fixConflicts (constraintList list1, constraintList list2) |
616915dd | 680 | { |
9a48d98c | 681 | constraintList ret = constraintList_makeNew (); |
682 | llassert (constraintList_isDefined (list1)); | |
683 | ||
616915dd | 684 | constraintList_elements (list1, el) |
685 | { | |
9a48d98c | 686 | if (!conflict (el, list2)) |
616915dd | 687 | { |
9a48d98c | 688 | constraint temp = constraint_copy (el); |
d46ce6a4 | 689 | ret = constraintList_add (ret, temp); |
616915dd | 690 | } |
691 | } end_constraintList_elements; | |
9a48d98c | 692 | |
693 | return ret; | |
616915dd | 694 | } |
695 | ||
9a48d98c | 696 | /* Returns true if constraint post satifies constraint pre */ |
bb25bea6 | 697 | static bool satifies (constraint pre, constraint post) |
616915dd | 698 | { |
9a48d98c | 699 | llassert (constraint_isDefined (pre)); |
700 | llassert (constraint_isDefined (post)); | |
a64ebe74 | 701 | |
9a48d98c | 702 | if (constraint_isAlwaysTrue (pre)) |
703 | { | |
704 | return TRUE; | |
705 | } | |
616915dd | 706 | |
9a48d98c | 707 | if (!constraintExpr_similar (pre->lexpr, post->lexpr)) |
616915dd | 708 | { |
9a48d98c | 709 | return TRUE; |
616915dd | 710 | } |
9a48d98c | 711 | |
712 | if (!constraintExpr_similar (pre->lexpr, post->lexpr)) | |
616915dd | 713 | { |
616915dd | 714 | return FALSE; |
715 | } | |
9a48d98c | 716 | |
717 | llassertretval (!constraintExpr_isUndefined (post->expr), FALSE); | |
616915dd | 718 | return rangeCheck (pre->ar, pre->expr, post->ar, post->expr); |
719 | } | |
720 | ||
9a48d98c | 721 | bool |
722 | constraintList_resolve (/*@observer@*/ constraint c, | |
723 | /*@observer@*/ constraintList p) | |
bb25bea6 | 724 | { |
725 | constraintList_elements (p, el) | |
726 | { | |
9a48d98c | 727 | if (satifies (c, el)) |
bb25bea6 | 728 | { |
9a48d98c | 729 | DPRINTF (("%s satifies %s", constraint_unparse (el), constraint_unparse(c))); |
bb25bea6 | 730 | return TRUE; |
731 | } | |
9a48d98c | 732 | DPRINTF (("%s does not satify %s", constraint_unparse (el), constraint_unparse (c))); |
733 | } end_constraintList_elements; | |
734 | ||
735 | DPRINTF (("no constraints satisfy %s", constraint_unparse (c))); | |
bb25bea6 | 736 | return FALSE; |
737 | } | |
738 | ||
739 | static bool arithType_canResolve (arithType ar1, arithType ar2) | |
616915dd | 740 | { |
741 | switch (ar1) | |
742 | { | |
743 | case GTE: | |
744 | case GT: | |
9a48d98c | 745 | if ((ar2 == GT) || (ar2 == GTE) || (ar2 == EQ)) |
616915dd | 746 | { |
747 | return TRUE; | |
748 | } | |
749 | break; | |
750 | ||
751 | case EQ: | |
752 | if (ar2 == EQ) | |
753 | return TRUE; | |
754 | break; | |
755 | ||
756 | case LT: | |
757 | case LTE: | |
9a48d98c | 758 | if ((ar2 == LT) || (ar2 == LTE) || (ar2 == EQ)) |
616915dd | 759 | return TRUE; |
84c9ffbf | 760 | break; |
616915dd | 761 | default: |
762 | return FALSE; | |
763 | } | |
764 | return FALSE; | |
765 | } | |
766 | ||
9a48d98c | 767 | /* Checks for the case expr2 == sizeof buf1 and buf1 is a fixed array*/ |
e5f31c00 | 768 | static bool sizeofBufComp(constraintExpr buf1, constraintExpr expr2) |
769 | { | |
770 | constraintTerm ct; | |
771 | exprNode e, t; | |
772 | sRef s1, s2; | |
a64ebe74 | 773 | |
9a48d98c | 774 | llassert (constraintExpr_isDefined (buf1) && constraintExpr_isDefined (expr2)); |
a64ebe74 | 775 | |
9a48d98c | 776 | /*@i6343 rewrite this to not need access, or move to constraintExpr module */ |
e5f31c00 | 777 | /*@access constraintExpr@*/ |
778 | ||
9a48d98c | 779 | if ((expr2->kind != term) && (buf1->kind != term)) |
780 | { | |
781 | return FALSE; | |
782 | } | |
e5f31c00 | 783 | |
784 | ct = constraintExprData_termGetTerm(expr2->data); | |
9a48d98c | 785 | |
786 | if (!constraintTerm_isExprNode(ct)) | |
787 | { | |
788 | return FALSE; | |
789 | } | |
e5f31c00 | 790 | |
9a48d98c | 791 | e = constraintTerm_getExprNode (ct); |
792 | ||
793 | llassert (exprNode_isDefined(e)); | |
794 | ||
795 | if (!exprNode_isDefined (e)) | |
796 | { | |
797 | return FALSE; | |
798 | } | |
a64ebe74 | 799 | |
e5f31c00 | 800 | if (e->kind != XPR_SIZEOF) |
9a48d98c | 801 | { |
802 | return FALSE; | |
803 | } | |
e5f31c00 | 804 | |
805 | t = exprData_getSingle (e->edata); | |
e5f31c00 | 806 | |
9a48d98c | 807 | s1 = exprNode_getSref (t); |
808 | s2 = constraintTerm_getsRef(constraintExprData_termGetTerm(buf1->data)); | |
e5f31c00 | 809 | |
810 | /*@i223@*/ /*this may be the wronge thing to test for */ | |
9a48d98c | 811 | if (sRef_similarRelaxed(s1, s2) || sRef_sameName (s1, s2)) |
e5f31c00 | 812 | { |
e5508969 | 813 | /*@i22*/ /* get rid of this test of now */ |
9a48d98c | 814 | /* if (ctype_isFixedArray (sRef_getType (s2))) */ |
e5f31c00 | 815 | return TRUE; |
816 | } | |
817 | return FALSE; | |
818 | } | |
819 | ||
820 | /* look for the special case of | |
821 | maxSet(buf) >= sizeof(buf) - 1 | |
822 | */ | |
823 | ||
824 | /*@i223@*/ /*need to add some type checking */ | |
332e22fa | 825 | |
e5f31c00 | 826 | static bool sizeOfMaxSet( /*@observer@*/ /*@temp@*/ constraint c) |
827 | { | |
828 | constraintExpr l, r, buf1, buf2, con; | |
9a48d98c | 829 | |
830 | DPRINTF (("sizeOfMaxSet: checking %s ", constraint_unparse (c))); | |
831 | llassert (constraint_isDefined (c)); | |
e5f31c00 | 832 | |
e5f31c00 | 833 | l = c->lexpr; |
834 | r = c->expr; | |
9a48d98c | 835 | |
836 | if (!((c->ar == EQ) || (c->ar == GTE) || (c->ar == LTE))) | |
837 | { | |
838 | return FALSE; | |
839 | } | |
e5f31c00 | 840 | |
9a48d98c | 841 | llassert (constraintExpr_isDefined (l)); |
842 | llassert (constraintExpr_isDefined (r)); | |
e5f31c00 | 843 | |
9a48d98c | 844 | /* Check if the constraintExpr is MaxSet(buf) */ |
a64ebe74 | 845 | |
e5f31c00 | 846 | if (l->kind == unaryExpr) |
847 | { | |
848 | if (constraintExprData_unaryExprGetOp(l->data) == MAXSET) | |
849 | { | |
850 | buf1 = constraintExprData_unaryExprGetExpr(l->data); | |
851 | } | |
852 | else | |
9a48d98c | 853 | { |
854 | return FALSE; | |
855 | } | |
e5f31c00 | 856 | } |
857 | else | |
9a48d98c | 858 | { |
859 | return FALSE; | |
860 | } | |
e5f31c00 | 861 | |
862 | if (r->kind != binaryexpr) | |
9a48d98c | 863 | { |
864 | return FALSE; | |
865 | } | |
e5f31c00 | 866 | |
9a48d98c | 867 | buf2 = constraintExprData_binaryExprGetExpr1 (r->data); |
868 | con = constraintExprData_binaryExprGetExpr2 (r->data); | |
e5f31c00 | 869 | |
9a48d98c | 870 | if (constraintExprData_binaryExprGetOp (r->data) == BINARYOP_MINUS) |
e5f31c00 | 871 | { |
9a48d98c | 872 | if (constraintExpr_canGetValue (con)) |
e5f31c00 | 873 | { |
9a48d98c | 874 | long i = constraintExpr_getValue (con); |
875 | ||
e5f31c00 | 876 | if (i != 1) |
877 | { | |
878 | return FALSE; | |
879 | } | |
880 | } | |
881 | else | |
9a48d98c | 882 | { |
883 | return FALSE; | |
884 | } | |
e5f31c00 | 885 | } |
886 | ||
9a48d98c | 887 | if (constraintExprData_binaryExprGetOp (r->data) == BINARYOP_PLUS) |
e5f31c00 | 888 | { |
9a48d98c | 889 | if (constraintExpr_canGetValue (con)) |
e5f31c00 | 890 | { |
9a48d98c | 891 | long i = constraintExpr_getValue (con); |
e5f31c00 | 892 | |
e5f31c00 | 893 | if (i != -1) |
894 | { | |
895 | return FALSE; | |
896 | } | |
897 | } | |
898 | else | |
9a48d98c | 899 | { |
900 | return FALSE; | |
901 | } | |
e5f31c00 | 902 | } |
9a48d98c | 903 | |
904 | return (sizeofBufComp (buf1, buf2)); | |
e5f31c00 | 905 | } |
9a48d98c | 906 | /*@i8423@*/ |
e5f31c00 | 907 | /*@noaccess constraintExpr@*/ |
908 | ||
90bc41f7 | 909 | /* We look for constraint which are tautologies */ |
910 | ||
28bf4b0b | 911 | bool constraint_isAlwaysTrue (/*@observer@*/ /*@temp@*/ constraint c) |
616915dd | 912 | { |
913 | constraintExpr l, r; | |
15b3d2b2 | 914 | bool rHasConstant; |
915 | int rConstant; | |
a64ebe74 | 916 | |
9a48d98c | 917 | llassert (constraint_isDefined (c)); |
9280addf | 918 | |
616915dd | 919 | l = c->lexpr; |
920 | r = c->expr; | |
90bc41f7 | 921 | |
9a48d98c | 922 | DPRINTF((message("constraint_IsAlwaysTrue:examining %s", constraint_unparse(c)))); |
e5f31c00 | 923 | |
9a48d98c | 924 | if (sizeOfMaxSet(c)) |
e5f31c00 | 925 | return TRUE; |
926 | ||
9a48d98c | 927 | if (constraintExpr_canGetValue(l) && constraintExpr_canGetValue(r)) |
616915dd | 928 | { |
929 | int cmp; | |
930 | cmp = constraintExpr_compare (l, r); | |
931 | switch (c->ar) | |
932 | { | |
933 | case EQ: | |
934 | return (cmp == 0); | |
935 | case GT: | |
936 | return (cmp > 0); | |
937 | case GTE: | |
938 | return (cmp >= 0); | |
939 | case LTE: | |
940 | return (cmp <= 0); | |
941 | case LT: | |
942 | return (cmp < 0); | |
943 | ||
944 | default: | |
9280addf | 945 | BADEXIT; |
84c9ffbf | 946 | /*@notreached@*/ |
9280addf | 947 | break; |
948 | } | |
949 | } | |
950 | ||
9a48d98c | 951 | if (constraintExpr_similar (l,r)) |
9280addf | 952 | { |
953 | switch (c->ar) | |
954 | { | |
955 | case EQ: | |
956 | case GTE: | |
957 | case LTE: | |
958 | return TRUE; | |
959 | ||
960 | case GT: | |
961 | case LT: | |
962 | break; | |
963 | default: | |
964 | BADEXIT; | |
84c9ffbf | 965 | /*@notreached@*/ |
616915dd | 966 | break; |
967 | } | |
968 | } | |
9280addf | 969 | |
970 | l = constraintExpr_copy (c->lexpr); | |
971 | r = constraintExpr_copy (c->expr); | |
972 | ||
9280addf | 973 | r = constraintExpr_propagateConstants (r, &rHasConstant, &rConstant); |
974 | ||
9a48d98c | 975 | if (constraintExpr_similar (l,r) && (rHasConstant)) |
9280addf | 976 | { |
9a48d98c | 977 | DPRINTF((message("constraint_IsAlwaysTrue: after removing constants %s and %s are similar", constraintExpr_unparse(l), constraintExpr_unparse(r)))); |
978 | DPRINTF((message("constraint_IsAlwaysTrue: rconstant is %d", rConstant))); | |
bb25bea6 | 979 | |
980 | constraintExpr_free(l); | |
981 | constraintExpr_free(r); | |
982 | ||
90bc41f7 | 983 | switch (c->ar) |
9280addf | 984 | { |
90bc41f7 | 985 | case EQ: |
986 | return (rConstant == 0); | |
987 | case LT: | |
988 | return (rConstant > 0); | |
989 | case LTE: | |
990 | return (rConstant >= 0); | |
991 | case GTE: | |
992 | return (rConstant <= 0); | |
993 | case GT: | |
994 | return (rConstant < 0); | |
995 | ||
996 | default: | |
997 | BADEXIT; | |
84c9ffbf | 998 | /*@notreached@*/ |
90bc41f7 | 999 | break; |
9280addf | 1000 | } |
9280addf | 1001 | } |
90bc41f7 | 1002 | else |
1003 | { | |
bb25bea6 | 1004 | constraintExpr_free(l); |
1005 | constraintExpr_free(r); | |
9a48d98c | 1006 | DPRINTF((message("Constraint %s is not always true", constraint_unparse(c)))); |
90bc41f7 | 1007 | return FALSE; |
1008 | } | |
9280addf | 1009 | |
1010 | BADEXIT; | |
616915dd | 1011 | } |
1012 | ||
bb25bea6 | 1013 | static bool rangeCheck (arithType ar1, /*@observer@*/ constraintExpr expr1, arithType ar2, /*@observer@*/ constraintExpr expr2) |
616915dd | 1014 | |
1015 | { | |
9a48d98c | 1016 | DPRINTF ((message ("Doing Range CHECK %s and %s", constraintExpr_unparse(expr1), constraintExpr_unparse(expr2)))); |
616915dd | 1017 | |
9a48d98c | 1018 | if (! arithType_canResolve (ar1, ar2)) |
616915dd | 1019 | return FALSE; |
1020 | ||
1021 | switch (ar1) | |
1022 | { | |
1023 | case GTE: | |
9a48d98c | 1024 | if (constraintExpr_similar (expr1, expr2)) |
2681ee39 | 1025 | return TRUE; |
1026 | /*@fallthrough@*/ | |
1027 | case GT: | |
616915dd | 1028 | if (! (constraintExpr_canGetValue (expr1) && |
9a48d98c | 1029 | constraintExpr_canGetValue (expr2))) |
2681ee39 | 1030 | { |
1031 | constraintExpr e1, e2; | |
1032 | bool p1, p2; | |
1033 | int const1, const2; | |
1034 | ||
1035 | e1 = constraintExpr_copy(expr1); | |
1036 | e2 = constraintExpr_copy(expr2); | |
1037 | ||
1038 | e1 = constraintExpr_propagateConstants (e1, &p1, &const1); | |
1039 | ||
1040 | e2 = constraintExpr_propagateConstants (e2, &p2, &const2); | |
1041 | ||
1042 | if (p1 || p2) | |
1043 | { | |
1044 | if (!p1) | |
1045 | const1 = 0; | |
1046 | ||
1047 | if (!p2) | |
1048 | const2 = 0; | |
1049 | ||
1050 | if (const1 <= const2) | |
9a48d98c | 1051 | if (constraintExpr_similar (e1, e2)) |
2681ee39 | 1052 | { |
1053 | constraintExpr_free(e1); | |
1054 | constraintExpr_free(e2); | |
1055 | return TRUE; | |
1056 | } | |
1057 | } | |
bb7c2085 | 1058 | DPRINTF(("Can't Get value")); |
2681ee39 | 1059 | |
1060 | constraintExpr_free(e1); | |
1061 | constraintExpr_free(e2); | |
1062 | return FALSE; | |
1063 | } | |
1064 | ||
1065 | if (constraintExpr_compare (expr2, expr1) >= 0) | |
1066 | return TRUE; | |
616915dd | 1067 | |
1068 | return FALSE; | |
2681ee39 | 1069 | case EQ: |
9a48d98c | 1070 | if (constraintExpr_similar (expr1, expr2)) |
2681ee39 | 1071 | return TRUE; |
1072 | ||
1073 | return FALSE; | |
1074 | case LTE: | |
9a48d98c | 1075 | if (constraintExpr_similar (expr1, expr2)) |
2681ee39 | 1076 | return TRUE; |
1077 | /*@fallthrough@*/ | |
1078 | case LT: | |
1079 | if (! (constraintExpr_canGetValue (expr1) && | |
9a48d98c | 1080 | constraintExpr_canGetValue (expr2))) |
2681ee39 | 1081 | { |
1082 | constraintExpr e1, e2; | |
1083 | bool p1, p2; | |
1084 | int const1, const2; | |
1085 | ||
1086 | e1 = constraintExpr_copy(expr1); | |
1087 | e2 = constraintExpr_copy(expr2); | |
1088 | ||
1089 | e1 = constraintExpr_propagateConstants (e1, &p1, &const1); | |
1090 | ||
1091 | e2 = constraintExpr_propagateConstants (e2, &p2, &const2); | |
1092 | ||
1093 | if (p1 || p2) | |
1094 | { | |
1095 | if (!p1) | |
1096 | const1 = 0; | |
1097 | ||
1098 | if (!p2) | |
1099 | const2 = 0; | |
1100 | ||
1101 | if (const1 >= const2) | |
9a48d98c | 1102 | if (constraintExpr_similar (e1, e2)) |
2681ee39 | 1103 | { |
1104 | constraintExpr_free(e1); | |
1105 | constraintExpr_free(e2); | |
1106 | return TRUE; | |
1107 | } | |
1108 | } | |
1109 | constraintExpr_free(e1); | |
1110 | constraintExpr_free(e2); | |
1111 | ||
bb7c2085 | 1112 | DPRINTF(("Can't Get value")); |
2681ee39 | 1113 | return FALSE; |
1114 | } | |
1115 | ||
1116 | if (constraintExpr_compare (expr2, expr1) <= 0) | |
1117 | return TRUE; | |
1118 | ||
1119 | return FALSE; | |
1120 | ||
1121 | default: | |
9a48d98c | 1122 | llcontbug((message("Unhandled case in switch: %q", arithType_print(ar1)))); |
2681ee39 | 1123 | } |
616915dd | 1124 | BADEXIT; |
616915dd | 1125 | } |
1126 | ||
28bf4b0b | 1127 | static constraint constraint_searchandreplace (/*@returned@*/ constraint c, constraintExpr old, constraintExpr newExpr) |
616915dd | 1128 | { |
9a48d98c | 1129 | llassert (constraint_isDefined (c)); |
1130 | DPRINTF (("Doing replace for lexpr")); | |
a64ebe74 | 1131 | |
28bf4b0b | 1132 | c->lexpr = constraintExpr_searchandreplace (c->lexpr, old, newExpr); |
9a48d98c | 1133 | DPRINTF (("Doing replace for expr")); |
28bf4b0b | 1134 | c->expr = constraintExpr_searchandreplace (c->expr, old, newExpr); |
616915dd | 1135 | return c; |
1136 | } | |
1137 | ||
84c9ffbf | 1138 | bool constraint_search (constraint c, constraintExpr old) /*@*/ |
616915dd | 1139 | { |
9a48d98c | 1140 | bool ret = FALSE; |
a64ebe74 | 1141 | |
9a48d98c | 1142 | llassert (constraint_isDefined (c)); |
a64ebe74 | 1143 | |
616915dd | 1144 | ret = constraintExpr_search (c->lexpr, old); |
1145 | ret = ret || constraintExpr_search (c->expr, old); | |
1146 | return ret; | |
1147 | } | |
1148 | ||
b7b694d6 | 1149 | /* adjust file locs and stuff */ |
bb25bea6 | 1150 | static constraint constraint_adjust (/*@returned@*/ constraint substitute, /*@observer@*/ constraint old) |
616915dd | 1151 | { |
1152 | fileloc loc1, loc2, loc3; | |
1153 | ||
9a48d98c | 1154 | DPRINTF (("Start adjust on %s and %s", constraint_unparse (substitute), |
1155 | constraint_unparse (old))); | |
616915dd | 1156 | |
9a48d98c | 1157 | llassert (constraint_isDefined (substitute)); |
1158 | llassert (constraint_isDefined (old)); | |
a64ebe74 | 1159 | |
616915dd | 1160 | loc1 = constraint_getFileloc (old); |
616915dd | 1161 | loc2 = constraintExpr_getFileloc (substitute->lexpr); |
616915dd | 1162 | loc3 = constraintExpr_getFileloc (substitute->expr); |
616915dd | 1163 | |
b7b694d6 | 1164 | /* special case of an equality that "contains itself" */ |
9a48d98c | 1165 | if (constraintExpr_search (substitute->expr, substitute->lexpr)) |
1166 | { | |
616915dd | 1167 | if (fileloc_closer (loc1, loc3, loc2)) |
9a48d98c | 1168 | { |
1169 | constraintExpr temp; | |
1170 | DPRINTF (("Doing adjust on %s", constraint_unparse(substitute))); | |
1171 | temp = substitute->lexpr; | |
1172 | substitute->lexpr = substitute->expr; | |
1173 | substitute->expr = temp; | |
1174 | substitute = constraint_simplify(substitute); | |
1175 | } | |
1176 | } | |
1177 | ||
bb25bea6 | 1178 | fileloc_free (loc1); |
1179 | fileloc_free (loc2); | |
1180 | fileloc_free (loc3); | |
616915dd | 1181 | return substitute; |
616915dd | 1182 | } |
1183 | ||
9a48d98c | 1184 | /* |
1185 | ** If function preforms substitutes based on inequality | |
1186 | ** It uses the rule x >= y && b < y ===> x >= b + 1 | |
1187 | ** warning this is sound but throws out information. | |
1188 | */ | |
dc7f6a51 | 1189 | |
9a48d98c | 1190 | constraint inequalitySubstitute (/*@returned@*/ constraint c, constraintList p) |
616915dd | 1191 | { |
9a48d98c | 1192 | llassert (constraint_isDefined (c)); |
1193 | ||
616915dd | 1194 | if (c->ar != GTE) |
9a48d98c | 1195 | { |
1196 | return c; | |
1197 | } | |
616915dd | 1198 | |
1199 | constraintList_elements (p, el) | |
1200 | { | |
9a48d98c | 1201 | llassert (constraint_isDefined (el)); |
a64ebe74 | 1202 | |
9a48d98c | 1203 | if ((el->ar == LT )) |
1204 | /* if (!constraint_conflict (c, el) ) */ /*@i523 explain this! */ | |
1205 | { | |
1206 | constraintExpr temp2; | |
1207 | ||
1208 | /*@i22*/ | |
1209 | ||
1210 | if (constraintExpr_same (el->expr, c->expr)) | |
1211 | { | |
1212 | DPRINTF (("inequalitySubstitute Replacing %q in %q with %q", | |
1213 | constraintExpr_print (c->expr), | |
1214 | constraint_unparse (c), | |
1215 | constraintExpr_print (el->expr))); | |
1216 | temp2 = constraintExpr_copy (el->lexpr); | |
1217 | constraintExpr_free(c->expr); | |
1218 | c->expr = constraintExpr_makeIncConstraintExpr (temp2); | |
1219 | } | |
1220 | } | |
1221 | } end_constraintList_elements; | |
1222 | ||
1223 | c = constraint_simplify (c); | |
616915dd | 1224 | return c; |
1225 | } | |
1226 | ||
dc7f6a51 | 1227 | /* drl7x 7/26/001 |
1228 | ||
1229 | THis function is like inequalitySubstitute but it adds the rule | |
1230 | added the rules x >= y && y <= b ===> x >= b | |
1231 | x >= y && y < b ===> x >= b + 1 | |
1232 | ||
1233 | This is sound but sonce it throws out additional information it should only one used | |
1234 | if we're oring constraints. | |
1235 | */ | |
1236 | ||
9a48d98c | 1237 | static constraint inequalitySubstituteStrong (/*@returned@*/ constraint c, constraintList p) |
dc7f6a51 | 1238 | { |
9a48d98c | 1239 | DPRINTF (("inequalitySubstituteStrong examining substituting for %q", constraint_unparse(c))); |
1240 | llassert (constraint_isDefined (c)); | |
dc7f6a51 | 1241 | |
9a48d98c | 1242 | if (!constraint_isDefined (c)) |
1243 | { | |
1244 | return c; | |
1245 | } | |
a64ebe74 | 1246 | |
dc7f6a51 | 1247 | if (c->ar != GTE) |
9a48d98c | 1248 | { |
1249 | return c; | |
1250 | } | |
dc7f6a51 | 1251 | |
9a48d98c | 1252 | DPRINTF (("inequalitySubstituteStrong examining substituting for %q with %q", |
1253 | constraint_unparse (c), constraintList_unparse (p))); | |
1254 | ||
dc7f6a51 | 1255 | constraintList_elements (p, el) |
1256 | { | |
9a48d98c | 1257 | DPRINTF (("inequalitySubstituteStrong examining substituting %s on %s", |
1258 | constraint_unparse (el), constraint_unparse (c))); | |
dc7f6a51 | 1259 | |
9a48d98c | 1260 | llassert (constraint_isDefined (el)); |
1261 | ||
1262 | if ((el->ar == LT ) || (el->ar == LTE)) | |
b7b694d6 | 1263 | /* if (!constraint_conflict (c, el) ) */ /*@i523@*/ |
9a48d98c | 1264 | { |
1265 | constraintExpr temp2; | |
1266 | ||
1267 | /*@i22*/ | |
1268 | if (constraintExpr_same (el->lexpr, c->expr)) | |
1269 | { | |
1270 | DPRINTF (("inequalitySubstitute Replacing %s in %s with %s", | |
1271 | constraintExpr_print (c->expr), | |
1272 | constraint_unparse (c), | |
1273 | constraintExpr_print (el->expr))); | |
dc7f6a51 | 1274 | |
9a48d98c | 1275 | temp2 = constraintExpr_copy (el->expr); |
1276 | constraintExpr_free (c->expr); | |
1277 | ||
1278 | if ((el->ar == LTE)) | |
1279 | { | |
1280 | c->expr = temp2; | |
1281 | } | |
1282 | else | |
1283 | { | |
1284 | c->expr = constraintExpr_makeIncConstraintExpr (temp2); | |
1285 | } | |
1286 | } | |
1287 | ||
1288 | } | |
1289 | } end_constraintList_elements; | |
1290 | ||
dc7f6a51 | 1291 | c = constraint_simplify(c); |
1292 | return c; | |
1293 | } | |
1294 | ||
1295 | ||
90bc41f7 | 1296 | /* This function performs substitutions based on the rule: |
1297 | for a constraint of the form expr1 >= expr2; a < b => | |
1298 | a = b -1 for all a in expr1. This will work in most cases. | |
1299 | ||
1300 | Like inequalitySubstitute we're throwing away some information | |
1301 | */ | |
1302 | ||
9a48d98c | 1303 | static constraint inequalitySubstituteUnsound (/*@returned@*/ constraint c, constraintList p) |
90bc41f7 | 1304 | { |
9a48d98c | 1305 | DPRINTF (("Doing inequalitySubstituteUnsound")); |
1306 | llassert (constraint_isDefined (c)); | |
90bc41f7 | 1307 | |
1308 | if (c->ar != GTE) | |
9a48d98c | 1309 | { |
1310 | return c; | |
1311 | } | |
90bc41f7 | 1312 | |
1313 | constraintList_elements (p, el) | |
1314 | { | |
9a48d98c | 1315 | llassert (constraint_isDefined (el)); |
1316 | ||
1317 | DPRINTF (("inequalitySubstituteUnsound examining substituting %s on %s", | |
1318 | constraint_unparse (el), constraint_unparse (c))); | |
1319 | if (( el->ar == LTE) || (el->ar == LT)) | |
1320 | /* if (!constraint_conflict (c, el) ) */ /*@i532@*/ | |
1321 | { | |
1322 | constraintExpr temp2 = constraintExpr_copy (el->expr); | |
1323 | ||
1324 | if (el->ar == LT) | |
1325 | { | |
1326 | temp2 = constraintExpr_makeDecConstraintExpr (temp2); | |
1327 | } | |
1328 | ||
1329 | DPRINTF (("Replacing %s in %s with %s", | |
1330 | constraintExpr_print (el->lexpr), | |
1331 | constraintExpr_print (c->lexpr), | |
1332 | constraintExpr_print (temp2))); | |
1333 | ||
1334 | c->lexpr = constraintExpr_searchandreplace (c->lexpr, el->lexpr, temp2); | |
1335 | constraintExpr_free(temp2); | |
1336 | } | |
1337 | } end_constraintList_elements; | |
1338 | ||
1339 | c = constraint_simplify (c); | |
90bc41f7 | 1340 | return c; |
1341 | } | |
1342 | ||
28bf4b0b | 1343 | /*@only@*/ constraint constraint_substitute (/*@observer@*/ /*@temp@*/ constraint c, constraintList p) |
616915dd | 1344 | { |
9a48d98c | 1345 | constraint ret = constraint_copy (c); |
1346 | ||
616915dd | 1347 | constraintList_elements (p, el) |
1348 | { | |
9a48d98c | 1349 | llassert (constraint_isDefined (el)); |
1350 | if (el->ar == EQ) | |
1351 | { | |
1352 | if (!constraint_conflict (ret, el)) | |
1353 | { | |
1354 | constraint temp = constraint_copy (el); | |
1355 | temp = constraint_adjust (temp, ret); | |
1356 | ||
1357 | llassert (constraint_isDefined (temp)); | |
1358 | ||
1359 | DPRINTF (("constraint_substitute :: Substituting in %s using %s", | |
1360 | constraint_unparse (ret), constraint_unparse (temp))); | |
1361 | ||
1362 | ret = constraint_searchandreplace (ret, temp->lexpr, temp->expr); | |
1363 | ||
1364 | DPRINTF (("constraint_substitute :: The new constraint is %s", constraint_unparse (ret))); | |
1365 | constraint_free (temp); | |
1366 | } | |
1367 | } | |
1368 | } end_constraintList_elements; | |
1369 | ||
1370 | ret = constraint_simplify (ret); | |
1371 | DPRINTF (("constraint_substitute :: The final new constraint is %s", constraint_unparse (ret))); | |
90bc41f7 | 1372 | return ret; |
616915dd | 1373 | } |
1374 | ||
9a48d98c | 1375 | /*@only@*/ constraintList |
1376 | constraintList_substituteFreeTarget (/*@only@*/ constraintList target, | |
1377 | /*@observer@*/ constraintList subList) | |
bb25bea6 | 1378 | { |
9a48d98c | 1379 | constraintList ret = constraintList_substitute (target, subList); |
1380 | constraintList_free(target); | |
1381 | return ret; | |
bb25bea6 | 1382 | } |
1383 | ||
c3e695ff | 1384 | /* we try to do substitutions on each constraint in target using the constraint in sublist*/ |
1385 | ||
9a48d98c | 1386 | /*@only@*/ constraintList |
1387 | constraintList_substitute (constraintList target, /*@observer@*/ constraintList subList) | |
c3e695ff | 1388 | { |
9a48d98c | 1389 | constraintList ret = constraintList_makeNew(); |
c3e695ff | 1390 | |
1391 | constraintList_elements(target, el) | |
9a48d98c | 1392 | { |
1393 | constraint temp = constraint_substitute (el, subList); | |
1394 | /*@i3232@*/ /* drl possible problem : warning make sure that a side effect is not expected */ | |
1395 | ret = constraintList_add (ret, temp); | |
1396 | } end_constraintList_elements; | |
84c9ffbf | 1397 | |
bb25bea6 | 1398 | return ret; |
c3e695ff | 1399 | } |
616915dd | 1400 | |
28bf4b0b | 1401 | static constraint constraint_solve (/*@returned@*/ constraint c) |
616915dd | 1402 | { |
9a48d98c | 1403 | llassert (constraint_isDefined (c)); |
1404 | DPRINTF (("Solving %s", constraint_unparse (c))); | |
616915dd | 1405 | c->expr = constraintExpr_solveBinaryExpr (c->lexpr, c->expr); |
9a48d98c | 1406 | DPRINTF (("Solved and got %s", constraint_unparse (c))); |
616915dd | 1407 | return c; |
1408 | } | |
1409 | ||
1410 | static arithType flipAr (arithType ar) | |
1411 | { | |
1412 | switch (ar) | |
1413 | { | |
9a48d98c | 1414 | case LT: return GT; |
1415 | case LTE: return GTE; | |
1416 | case EQ: return EQ; | |
1417 | case GT: return LT; | |
1418 | case GTE: return LTE; | |
1419 | default: llcontbuglit ("unexpected value: case not handled"); | |
616915dd | 1420 | } |
1421 | BADEXIT; | |
1422 | } | |
1423 | ||
9a48d98c | 1424 | static constraint constraint_swapLeftRight (/*@returned@*/ constraint c) |
616915dd | 1425 | { |
1426 | constraintExpr temp; | |
a64ebe74 | 1427 | |
9a48d98c | 1428 | llassert (constraint_isDefined (c)); |
a64ebe74 | 1429 | |
616915dd | 1430 | c->ar = flipAr (c->ar); |
1431 | temp = c->lexpr; | |
1432 | c->lexpr = c->expr; | |
1433 | c->expr = temp; | |
9a48d98c | 1434 | DPRINTF (("Swaped left and right sides of constraint")); |
616915dd | 1435 | return c; |
1436 | } | |
1437 | ||
9a48d98c | 1438 | constraint constraint_simplify (/*@returned@*/ constraint c) |
616915dd | 1439 | { |
9a48d98c | 1440 | llassert (constraint_isDefined (c)); |
1441 | DPRINTF (("constraint_simplify on %q ", constraint_unparse (c))); | |
a779b61e | 1442 | |
1443 | if (constraint_tooDeep(c)) | |
1444 | { | |
9a48d98c | 1445 | DPRINTF (("constraint_simplify: constraint to complex aborting %q", constraint_unparse (c))); |
a779b61e | 1446 | return c; |
a779b61e | 1447 | } |
1448 | ||
616915dd | 1449 | c->lexpr = constraintExpr_simplify (c->lexpr); |
1450 | c->expr = constraintExpr_simplify (c->expr); | |
616915dd | 1451 | |
9a48d98c | 1452 | if (constraintExpr_isBinaryExpr (c->lexpr)) |
c3e695ff | 1453 | { |
1454 | c = constraint_solve (c); | |
c3e695ff | 1455 | c->lexpr = constraintExpr_simplify (c->lexpr); |
1456 | c->expr = constraintExpr_simplify (c->expr); | |
1457 | } | |
1458 | ||
9a48d98c | 1459 | if (constraintExpr_isLit(c->lexpr) && (!constraintExpr_isLit(c->expr))) |
616915dd | 1460 | { |
9a48d98c | 1461 | c = constraint_swapLeftRight (c); |
1462 | /* I don't think this will be an infinite loop */ | |
1463 | c = constraint_simplify (c); | |
616915dd | 1464 | } |
a779b61e | 1465 | |
9a48d98c | 1466 | DPRINTF (("constraint_simplify returning %q", constraint_unparse (c))); |
616915dd | 1467 | return c; |
1468 | } | |
1469 | ||
9a48d98c | 1470 | /* returns true if fileloc for term1 is closer to file for term2 than term3*/ |
616915dd | 1471 | |
9a48d98c | 1472 | bool fileloc_closer (fileloc loc1, fileloc loc2, fileloc loc3) |
616915dd | 1473 | { |
9a48d98c | 1474 | if (!fileloc_isDefined (loc1)) |
c3e695ff | 1475 | return FALSE; |
9a48d98c | 1476 | |
1477 | if (!fileloc_isDefined (loc2)) | |
c3e695ff | 1478 | return FALSE; |
1479 | ||
9a48d98c | 1480 | if (!fileloc_isDefined (loc3)) |
c3e695ff | 1481 | return TRUE; |
c3e695ff | 1482 | |
9a48d98c | 1483 | if (fileloc_equal (loc2, loc3)) |
c3e695ff | 1484 | return FALSE; |
9a48d98c | 1485 | |
1486 | if (fileloc_equal (loc1, loc2)) | |
c3e695ff | 1487 | return TRUE; |
9a48d98c | 1488 | |
1489 | if (fileloc_equal (loc1, loc3)) | |
c3e695ff | 1490 | return FALSE; |
9a48d98c | 1491 | |
1492 | if (fileloc_lessthan (loc1, loc2)) | |
1493 | { | |
1494 | if (fileloc_lessthan (loc2, loc3)) | |
1495 | { | |
1496 | llassert (fileloc_lessthan (loc1, loc3)); | |
1497 | return TRUE; | |
1498 | } | |
1499 | else | |
1500 | { | |
1501 | return FALSE; | |
1502 | } | |
1503 | } | |
1504 | ||
1505 | if (!fileloc_lessthan (loc1, loc2)) | |
1506 | { | |
1507 | if (!fileloc_lessthan (loc2, loc3)) | |
1508 | { | |
1509 | llassert (!fileloc_lessthan (loc1, loc3)); | |
1510 | return TRUE; | |
1511 | } | |
1512 | else | |
1513 | { | |
1514 | return FALSE; | |
1515 | } | |
1516 | } | |
1517 | ||
1518 | llassert(FALSE); | |
1519 | return FALSE; | |
616915dd | 1520 | } |
1521 | ||
1522 |