|
18 | 18 |
|
19 | 19 | from pyk.cterm import CTerm |
20 | 20 | from pyk.kast.inner import KApply, KRewrite, KSequence, KSort, KToken, KVariable, Subst |
| 21 | +from pyk.kast.att import Atts as AttKeys |
| 22 | +from pyk.kast.att import AttEntry, KAtt |
21 | 23 | from pyk.kast.outer import KFlatModule, KImport, KRule |
22 | 24 | from pyk.kast.prelude.ml import mlAnd, mlEqualsTrue |
23 | 25 | from pyk.proof.reachability import APRProof |
@@ -277,70 +279,80 @@ def generate_summary_rules( |
277 | 279 | return rules |
278 | 280 |
|
279 | 281 |
|
| 282 | +_EXEC_TERMINATOR_CALL = '#execTerminatorCall(_,_,_,_,_,_,_)_KMIR-CONTROL-FLOW_KItem_Ty_MonoItemKind_Operands_Place_MaybeBasicBlockIdx_UnwindAction_Span' |
| 283 | +_SET_LOCAL_VALUE = '#setLocalValue(_,_)_RT-DATA_KItem_Place_Evaluation' |
| 284 | +_CONTINUE_AT = '#continueAt(_)_KMIR-CONTROL-FLOW_KItem_MaybeBasicBlockIdx' |
| 285 | +_GET_FUNCTION_NAME = 'getFunctionName(_)_KMIR-CONTROL-FLOW_String_MonoItemKind' |
| 286 | +_EQ_STRING = '_==String__STRING-COMMON_Bool_String_String' |
| 287 | + |
| 288 | + |
280 | 289 | def _build_summary_rule( |
281 | 290 | callee_name: str, |
282 | 291 | path: CoverPath, |
283 | 292 | path_idx: int, |
284 | 293 | init_cterm: CTerm, |
285 | 294 | ) -> KRule | None: |
286 | | - """Build one K rule for a single execution path.""" |
| 295 | + """Build one K rule for a single execution path. |
| 296 | +
|
| 297 | + Uses cterm_build_rule to construct a properly-structured rule from |
| 298 | + init CTerm (at function call) → final CTerm (after return). |
| 299 | + The init CTerm's K_CELL is #execTerminatorCall(...) and the final |
| 300 | + CTerm's K_CELL is #setLocalValue(DEST, RET) ~> #continueAt(TARGET). |
| 301 | + """ |
| 302 | + from pyk.cterm.cterm import cterm_build_rule |
| 303 | + |
287 | 304 | if path.return_value is None: |
288 | 305 | _LOGGER.warning(f'CSE: no return value for {callee_name} path {path_idx}, skipping') |
289 | 306 | return None |
290 | 307 |
|
291 | | - # Variables for the rule LHS pattern |
292 | | - func_var = KVariable('FUNC', sort=KSort('MonoItemKind')) |
293 | | - args_var = KVariable('ARGS', sort=KSort('Operands')) |
294 | | - dest_var = KVariable('DEST', sort=KSort('Place')) |
295 | | - target_var = KVariable('TARGET', sort=KSort('MaybeBasicBlockIdx')) |
296 | | - unwind_var = KVariable('_UNWIND', sort=KSort('UnwindAction')) |
297 | | - span_var = KVariable('_SPAN', sort=KSort('Span')) |
298 | | - ty_var = KVariable('_TY', sort=KSort('Ty')) |
299 | | - |
300 | | - # LHS: #execTerminatorCall(_, FUNC, ARGS, DEST, TARGET, _UNWIND, _SPAN) |
301 | | - lhs_k = KApply( |
302 | | - '#execTerminatorCall', |
303 | | - [ty_var, func_var, args_var, dest_var, target_var, unwind_var, span_var], |
304 | | - ) |
305 | | - |
306 | | - # RHS: #setLocalValue(DEST, RET_VALUE) ~> #execBlockIdx(TARGET) |
307 | | - rhs_k = KSequence( |
308 | | - [ |
309 | | - KApply('#setLocalValue', [dest_var, path.return_value]), |
310 | | - KApply('#execBlockIdx', [target_var]), |
311 | | - ] |
312 | | - ) |
| 308 | + # Variables for the rule |
| 309 | + func_var = KVariable('CSE_FUNC') |
| 310 | + dest_var = KVariable('CSE_DEST') |
| 311 | + target_var = KVariable('CSE_TARGET') |
| 312 | + cont_var = KVariable('CSE_CONT') |
| 313 | + |
| 314 | + # Build init CTerm: same as init_cterm but with K_CELL = #execTerminatorCall ~> CONT |
| 315 | + lhs_k = KSequence([ |
| 316 | + KApply(_EXEC_TERMINATOR_CALL, [ |
| 317 | + KVariable('CSE_TY'), func_var, KVariable('CSE_ARGS'), |
| 318 | + dest_var, target_var, KVariable('CSE_UNWIND'), KVariable('CSE_SPAN'), |
| 319 | + ]), |
| 320 | + cont_var, |
| 321 | + ]) |
313 | 322 |
|
314 | | - # Build the rule body as a <k> cell rewrite |
315 | | - body = KApply('<generatedTop>', [ |
316 | | - KApply('<kmir>', [ |
317 | | - KRewrite(lhs_k, rhs_k), # <k> cell rewrite — simplified, will need full config |
318 | | - ]) |
| 323 | + # Build final CTerm: same config but K_CELL = #setLocalValue(DEST, RET) ~> #continueAt(TARGET) |
| 324 | + rhs_k = KSequence([ |
| 325 | + KApply(_SET_LOCAL_VALUE, [dest_var, path.return_value]), |
| 326 | + KApply(_CONTINUE_AT, [target_var]), |
319 | 327 | ]) |
320 | 328 |
|
321 | | - # For now, build requires clause with function name match |
322 | | - func_name_check = KApply( |
323 | | - '_==String_', |
324 | | - [ |
325 | | - KApply('getFunctionName', [func_var]), |
326 | | - KToken(f'"{callee_name}"', KSort('String')), |
327 | | - ], |
328 | | - ) |
| 329 | + # Use the init_cterm config as the base, replace K_CELL |
| 330 | + from pyk.kast.manip import set_cell |
| 331 | + |
| 332 | + init_config = set_cell(init_cterm.config, 'K_CELL', lhs_k) |
| 333 | + final_config = set_cell(init_cterm.config, 'K_CELL', rhs_k) |
| 334 | + |
| 335 | + # Build requires: getFunctionName(FUNC) ==String "callee_name" andBool path constraints |
| 336 | + func_name_check = KApply(_EQ_STRING, [ |
| 337 | + KApply(_GET_FUNCTION_NAME, [func_var]), |
| 338 | + KToken(f'"{callee_name}"', KSort('String')), |
| 339 | + ]) |
329 | 340 |
|
330 | | - # Combine function name check with path constraints |
331 | | - requires_clauses = [func_name_check] |
332 | | - requires_clauses.extend(path.constraints) |
| 341 | + constraints: list[KInner] = [mlEqualsTrue(func_name_check)] |
| 342 | + constraints.extend(path.constraints) |
333 | 343 |
|
334 | | - requires = mlEqualsTrue(mlAnd(requires_clauses)) if len(requires_clauses) > 1 else mlEqualsTrue(requires_clauses[0]) |
| 344 | + init_cterm_rule = CTerm(init_config, tuple(constraints)) |
| 345 | + final_cterm_rule = CTerm(final_config) |
335 | 346 |
|
336 | 347 | rule_label = f'cse-summary-{_sanitize_name(callee_name)}-path-{path_idx}' |
337 | 348 |
|
338 | | - return KRule( |
339 | | - body=body, |
340 | | - requires=requires, |
341 | | - ensures=KToken('true', KSort('Bool')), |
342 | | - att={'priority': '30', 'label': rule_label}, |
| 349 | + rule, _subst = cterm_build_rule( |
| 350 | + rule_label, |
| 351 | + init_cterm_rule, |
| 352 | + final_cterm_rule, |
| 353 | + priority=30, |
343 | 354 | ) |
| 355 | + return rule |
344 | 356 |
|
345 | 357 |
|
346 | 358 | def _sanitize_name(name: str) -> str: |
|
0 commit comments