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