@@ -224,6 +224,76 @@ static exprt n_Xes(mp_integer n, exprt op)
224
224
return n_Xes (n - 1 , X_exprt{std::move (op)});
225
225
}
226
226
227
+ // Returns a set of match conditions (given as LTL formula)
228
+ struct ltl_sequence_matcht
229
+ {
230
+ ltl_sequence_matcht (exprt __cond, mp_integer __length)
231
+ : cond(std::move(__cond)), length(std::move(__length))
232
+ {
233
+ }
234
+
235
+ exprt cond; // LTL
236
+ mp_integer length; // match_end - match_start
237
+ };
238
+
239
+ std::vector<ltl_sequence_matcht> LTL_sequence_matches (const exprt &sequence)
240
+ {
241
+ if (!is_SVA_sequence_operator (sequence))
242
+ {
243
+ // atomic proposition
244
+ return {{sequence, 0 }};
245
+ }
246
+ else if (sequence.id () == ID_sva_sequence_concatenation)
247
+ {
248
+ auto &concatenation = to_sva_sequence_concatenation_expr (sequence);
249
+ auto matches_lhs = LTL_sequence_matches (concatenation.lhs ());
250
+ auto matches_rhs = LTL_sequence_matches (concatenation.rhs ());
251
+
252
+ if (matches_lhs.empty () || matches_rhs.empty ())
253
+ return {};
254
+
255
+ std::vector<ltl_sequence_matcht> result;
256
+ // cross product
257
+ for (auto &match_lhs : matches_lhs)
258
+ for (auto &match_rhs : matches_rhs)
259
+ {
260
+ auto rhs_delayed = n_Xes (match_lhs.length , match_rhs.cond );
261
+ result.emplace_back (
262
+ and_exprt{match_lhs.cond , rhs_delayed},
263
+ match_lhs.length + match_rhs.length );
264
+ }
265
+ return result;
266
+ }
267
+ else if (sequence.id () == ID_sva_cycle_delay)
268
+ {
269
+ auto &delay = to_sva_cycle_delay_expr (sequence);
270
+ auto matches = LTL_sequence_matches (delay.op ());
271
+ auto from_int = numeric_cast_v<mp_integer>(delay.from ());
272
+
273
+ if (matches.empty ())
274
+ return {};
275
+
276
+ if (delay.to ().is_nil ())
277
+ {
278
+ for (auto &match : matches)
279
+ {
280
+ // delay as instructed
281
+ match.length += from_int;
282
+ match.cond = n_Xes (from_int, match.cond );
283
+ }
284
+ return matches;
285
+ }
286
+ else
287
+ return {};
288
+ }
289
+ else
290
+ {
291
+ return {}; // unsupported
292
+ }
293
+ }
294
+
295
+ // / takes an SVA property as input, and returns an equivalent LTL property,
296
+ // / or otherwise {}.
227
297
std::optional<exprt> SVA_to_LTL (exprt expr)
228
298
{
229
299
// Some SVA is directly mappable to LTL
@@ -317,25 +387,89 @@ std::optional<exprt> SVA_to_LTL(exprt expr)
317
387
else
318
388
return {};
319
389
}
320
- else if (expr.id () == ID_sva_overlapped_implication)
390
+ else if (
391
+ expr.id () == ID_sva_overlapped_implication ||
392
+ expr.id () == ID_sva_non_overlapped_implication)
321
393
{
322
- auto &implication = to_sva_overlapped_implication_expr (expr);
323
- auto rec_lhs = SVA_to_LTL (implication.lhs ());
324
- auto rec_rhs = SVA_to_LTL (implication.rhs ());
325
- if (rec_lhs.has_value () && rec_rhs.has_value ())
326
- return implies_exprt{rec_lhs.value (), rec_rhs.value ()};
327
- else
394
+ auto &implication = to_sva_implication_base_expr (expr);
395
+ auto matches = LTL_sequence_matches (implication.sequence ());
396
+
397
+ if (matches.empty ())
398
+ return {};
399
+
400
+ // All matches must be followed
401
+ // by the property being true
402
+ exprt::operandst conjuncts;
403
+
404
+ auto property_rec = SVA_to_LTL (implication.property ());
405
+
406
+ if (!property_rec.has_value ())
328
407
return {};
408
+
409
+ for (auto &match : matches)
410
+ {
411
+ auto delay =
412
+ match.length + (expr.id () == ID_sva_non_overlapped_implication ? 1 : 0 );
413
+ auto delayed_property = n_Xes (delay, property_rec.value ());
414
+ conjuncts.push_back (implies_exprt{match.cond , delayed_property});
415
+ }
416
+
417
+ return conjunction (conjuncts);
329
418
}
330
- else if (expr.id () == ID_sva_non_overlapped_implication)
419
+ else if (
420
+ expr.id () == ID_sva_nonoverlapped_followed_by ||
421
+ expr.id () == ID_sva_overlapped_followed_by)
331
422
{
332
- auto &implication = to_sva_non_overlapped_implication_expr (expr);
333
- auto rec_lhs = SVA_to_LTL (implication.lhs ());
334
- auto rec_rhs = SVA_to_LTL (implication.rhs ());
335
- if (rec_lhs.has_value () && rec_rhs.has_value ())
336
- return implies_exprt{rec_lhs.value (), X_exprt{rec_rhs.value ()}};
337
- else
423
+ auto &followed_by = to_sva_followed_by_expr (expr);
424
+ auto matches = LTL_sequence_matches (followed_by.sequence ());
425
+
426
+ if (matches.empty ())
427
+ return {};
428
+
429
+ // There must be at least one match that is followed
430
+ // by the property being true
431
+ exprt::operandst disjuncts;
432
+
433
+ auto property_rec = SVA_to_LTL (followed_by.property ());
434
+
435
+ if (!property_rec.has_value ())
338
436
return {};
437
+
438
+ for (auto &match : matches)
439
+ {
440
+ auto delay =
441
+ match.length + (expr.id () == ID_sva_nonoverlapped_followed_by ? 1 : 0 );
442
+ auto delayed_property = n_Xes (delay, property_rec.value ());
443
+ disjuncts.push_back (and_exprt{match.cond , delayed_property});
444
+ }
445
+
446
+ return disjunction (disjuncts);
447
+ }
448
+ else if (expr.id () == ID_sva_sequence_property)
449
+ {
450
+ // should have been turned into sva_implicit_weak or sva_implicit_strong
451
+ PRECONDITION (false );
452
+ }
453
+ else if (
454
+ expr.id () == ID_sva_weak || expr.id () == ID_sva_strong ||
455
+ expr.id () == ID_sva_implicit_weak || expr.id () == ID_sva_implicit_strong)
456
+ {
457
+ auto &sequence = to_sva_sequence_property_expr_base (expr).sequence ();
458
+
459
+ // evaluates to true if there's at least one match of the sequence
460
+ auto matches = LTL_sequence_matches (sequence);
461
+
462
+ if (matches.empty ())
463
+ return {};
464
+
465
+ exprt::operandst disjuncts;
466
+
467
+ for (auto &match : matches)
468
+ {
469
+ disjuncts.push_back (match.cond );
470
+ }
471
+
472
+ return disjunction (disjuncts);
339
473
}
340
474
else if (!has_temporal_operator (expr))
341
475
{
0 commit comments