@@ -10,6 +10,7 @@ use vir::{
10
10
common:: position:: Positioned ,
11
11
low:: {
12
12
ast:: { expression:: * , ty:: * } ,
13
+ operations:: ty:: Typed ,
13
14
* ,
14
15
} ,
15
16
} ;
@@ -19,24 +20,27 @@ lazy_static! {
19
20
static ref TWO_PARAM_RE : Regex = Regex :: new( r"Map<([^>]+)\s*,\s*([^>]+)>" ) . unwrap( ) ;
20
21
}
21
22
22
- const SMT_PREAMBLE : & str = include_str ! ( "theories/Preamble.smt2" ) ;
23
+ const NO_Z3_PREAMBLE : & str = include_str ! ( "theories/Preamble.smt2" ) ;
24
+ const Z3_PREAMBLE : & str = include_str ! ( "theories/PreambleZ3.smt2" ) ;
23
25
24
26
pub struct SMTLib {
25
27
sort_decls : Vec < String > ,
26
28
func_decls : Vec < String > ,
27
29
code : Vec < String > ,
28
30
methods : HashMap < String , MethodDecl > ,
29
31
blocks : HashMap < String , BasicBlock > ,
32
+ using_z3 : bool ,
30
33
}
31
34
32
35
impl SMTLib {
33
- pub fn new ( ) -> Self {
36
+ pub fn new ( using_z3 : bool ) -> Self {
34
37
Self {
35
38
sort_decls : Vec :: new ( ) ,
36
39
func_decls : Vec :: new ( ) ,
37
40
code : Vec :: new ( ) ,
38
41
methods : HashMap :: new ( ) ,
39
42
blocks : Default :: default ( ) ,
43
+ using_z3,
40
44
}
41
45
}
42
46
fn add_sort_decl ( & mut self , sort_decl : String ) {
@@ -191,7 +195,11 @@ impl SMTLib {
191
195
impl ToString for SMTLib {
192
196
fn to_string ( & self ) -> String {
193
197
let mut result = String :: new ( ) ;
194
- result. push_str ( SMT_PREAMBLE ) ;
198
+ result. push_str ( if self . using_z3 {
199
+ Z3_PREAMBLE
200
+ } else {
201
+ NO_Z3_PREAMBLE
202
+ } ) ;
195
203
result. push_str ( "\n \n " ) ;
196
204
result. push_str ( & self . sort_decls . join ( "\n " ) ) ;
197
205
result. push_str ( "\n \n " ) ;
@@ -343,7 +351,7 @@ impl SMTTranslatable for DomainAxiomDecl {
343
351
smt. add_assert ( format ! ( "; {}" , comment) ) ;
344
352
}
345
353
346
- smt. add_assert ( self . body . to_smt ( ) ) ;
354
+ smt. add_code ( format ! ( "(assert {}) ; {}" , self . body. to_smt( ) , self . name ) ) ;
347
355
}
348
356
}
349
357
@@ -430,29 +438,80 @@ impl SMTTranslatable for Expression {
430
438
Expression :: Constant ( constant) => match & constant. value {
431
439
ConstantValue :: Bool ( bool) => bool. to_string ( ) ,
432
440
ConstantValue :: Int ( i64) => i64. to_string ( ) ,
441
+ ConstantValue :: Float32 ( u32) => {
442
+ let bits = u32. to_le_bytes ( ) ;
443
+ let bits = bits
444
+ . iter ( )
445
+ . rev ( )
446
+ . map ( |b| format ! ( "{:08b}" , b) )
447
+ . collect :: < Vec < _ > > ( )
448
+ . join ( "" ) ;
449
+ format ! (
450
+ "(fp #b{} #b{} #b{})" ,
451
+ & bits. chars( ) . next( ) . unwrap( ) ,
452
+ & bits[ 1 ..=8 ] ,
453
+ & bits[ 9 ..=31 ]
454
+ )
455
+ }
456
+ ConstantValue :: Float64 ( u64) => {
457
+ let bits = u64. to_le_bytes ( ) ;
458
+ let bits = bits
459
+ . iter ( )
460
+ . rev ( )
461
+ . map ( |b| format ! ( "{:08b}" , b) )
462
+ . collect :: < Vec < _ > > ( )
463
+ . join ( "" ) ;
464
+ format ! (
465
+ "(fp #b{} #b{} #b{})" ,
466
+ & bits. chars( ) . next( ) . unwrap( ) ,
467
+ & bits[ 1 ..=11 ] ,
468
+ & bits[ 12 ..=63 ]
469
+ )
470
+ }
433
471
ConstantValue :: BigInt ( s) => s. clone ( ) ,
434
472
} ,
435
- Expression :: MagicWand ( _) => unimplemented ! ( "Magic wands are not supported" ) ,
473
+ Expression :: MagicWand ( wand) => {
474
+ warn ! ( "MagicWand not supported: {}" , wand) ;
475
+ format ! ( "(=> {} {})" , wand. left. to_smt( ) , wand. right. to_smt( ) )
476
+ }
436
477
Expression :: PredicateAccessPredicate ( _access) => {
437
- // TODO: access predicates for predicates
438
- warn ! ( "PredicateAccessPredicate not supported" ) ;
439
- "" . to_string ( )
478
+ warn ! ( "PredicateAccessPredicate not supported: {}" , _access) ;
479
+ format ! (
480
+ "({} {})" ,
481
+ _access. name,
482
+ _access
483
+ . arguments
484
+ . iter( )
485
+ . map( |x| x. to_smt( ) )
486
+ . collect:: <Vec <_>>( )
487
+ . join( " " )
488
+ )
440
489
}
441
490
Expression :: FieldAccessPredicate ( _) => unimplemented ! ( ) ,
442
491
Expression :: Unfolding ( _) => unimplemented ! ( ) ,
443
492
Expression :: UnaryOp ( unary_op) => {
493
+ let op_smt = if unary_op. argument . get_type ( ) . is_float ( ) {
494
+ FloatUnaryOpKind ( unary_op. op_kind ) . to_smt ( )
495
+ } else {
496
+ IntUnaryOpKind ( unary_op. op_kind ) . to_smt ( )
497
+ } ;
498
+
499
+ format ! ( "({} {})" , op_smt, unary_op. argument. to_smt( ) )
500
+ }
501
+ Expression :: BinaryOp ( binary_op) => {
502
+ let op_smt = if let Type :: Float ( fsize) = binary_op. left . get_type ( ) {
503
+ FloatBinaryOpKind ( binary_op. op_kind , * fsize) . to_smt ( )
504
+ } else {
505
+ IntBinaryOpKind ( binary_op. op_kind ) . to_smt ( )
506
+ } ;
507
+
444
508
format ! (
445
- "({} {})" ,
446
- unary_op. op_kind. to_smt( ) ,
447
- unary_op. argument. to_smt( )
509
+ "({} {} {})" ,
510
+ op_smt,
511
+ binary_op. left. to_smt( ) ,
512
+ binary_op. right. to_smt( )
448
513
)
449
514
}
450
- Expression :: BinaryOp ( binary_op) => format ! (
451
- "({} {} {})" ,
452
- binary_op. op_kind. to_smt( ) ,
453
- binary_op. left. to_smt( ) ,
454
- binary_op. right. to_smt( )
455
- ) ,
456
515
Expression :: PermBinaryOp ( perm_binary_op) => format ! (
457
516
"({} {} {})" ,
458
517
perm_binary_op. op_kind. to_smt( ) ,
@@ -481,15 +540,26 @@ impl SMTTranslatable for Expression {
481
540
) ;
482
541
quant. push_str ( ") " ) ;
483
542
484
- if quantifier. triggers . is_empty ( ) {
543
+ let triggers: Vec < _ > = quantifier
544
+ . triggers
545
+ . iter ( )
546
+ . filter ( |t| {
547
+ !t. terms
548
+ . iter ( )
549
+ . any ( |t| matches ! ( t, Expression :: PredicateAccessPredicate ( _) ) )
550
+ // TODO: Support triggers with predicate access predicates?
551
+ } )
552
+ . collect ( ) ;
553
+
554
+ if triggers. is_empty ( ) {
485
555
quant. push_str ( & quantifier. body . to_smt ( ) ) ;
486
556
quant. push_str ( ")" ) ;
487
557
} else {
488
558
// triggers are :pattern
489
559
quant. push_str ( "(!" ) ;
490
560
quant. push_str ( & quantifier. body . to_smt ( ) ) ;
491
561
492
- for trigger in & quantifier . triggers {
562
+ for trigger in & triggers {
493
563
quant. push_str ( " :pattern (" ) ;
494
564
495
565
quant. push_str (
@@ -521,9 +591,12 @@ impl SMTTranslatable for Expression {
521
591
}
522
592
}
523
593
524
- impl SMTTranslatable for BinaryOpKind {
594
+ struct IntBinaryOpKind ( BinaryOpKind ) ;
595
+ struct FloatBinaryOpKind ( BinaryOpKind , Float ) ;
596
+
597
+ impl SMTTranslatable for IntBinaryOpKind {
525
598
fn to_smt ( & self ) -> String {
526
- match self {
599
+ match self . 0 {
527
600
BinaryOpKind :: EqCmp => "=" ,
528
601
BinaryOpKind :: NeCmp => "distinct" ,
529
602
BinaryOpKind :: GtCmp => ">" ,
@@ -543,6 +616,28 @@ impl SMTTranslatable for BinaryOpKind {
543
616
}
544
617
}
545
618
619
+ impl SMTTranslatable for FloatBinaryOpKind {
620
+ fn to_smt ( & self ) -> String {
621
+ match ( self . 0 , self . 1 ) {
622
+ // BinaryOpKind::EqCmp => "fp.eq", // TODO: = in axioms, fp.eq in arithmetic?
623
+ ( BinaryOpKind :: EqCmp , _) => "=" ,
624
+ ( BinaryOpKind :: NeCmp , Float :: F32 ) => "fp.neq32" , // Not in SMT-LIB 2.6 standard, part of static preamble
625
+ ( BinaryOpKind :: NeCmp , Float :: F64 ) => "fp.neq64" , // Not in SMT-LIB 2.6 standard, part of static preamble
626
+ ( BinaryOpKind :: GtCmp , _) => "fp.gt" ,
627
+ ( BinaryOpKind :: GeCmp , _) => "fp.geq" ,
628
+ ( BinaryOpKind :: LtCmp , _) => "fp.lt" ,
629
+ ( BinaryOpKind :: LeCmp , _) => "fp.leq" ,
630
+ ( BinaryOpKind :: Add , _) => "fp.add roundNearestTiesToAway" ,
631
+ ( BinaryOpKind :: Sub , _) => "fp.sub roundNearestTiesToAway" ,
632
+ ( BinaryOpKind :: Mul , _) => "fp.mul roundNearestTiesToAway" ,
633
+ ( BinaryOpKind :: Div , _) => "fp.div roundNearestTiesToAway" ,
634
+ ( BinaryOpKind :: Mod , _) => "fp.rem" ,
635
+ ( other, _) => unreachable ! ( "FP {}" , other) ,
636
+ }
637
+ . to_string ( )
638
+ }
639
+ }
640
+
546
641
impl SMTTranslatable for PermBinaryOpKind {
547
642
fn to_smt ( & self ) -> String {
548
643
match self {
@@ -555,16 +650,29 @@ impl SMTTranslatable for PermBinaryOpKind {
555
650
}
556
651
}
557
652
558
- impl SMTTranslatable for UnaryOpKind {
653
+ struct IntUnaryOpKind ( UnaryOpKind ) ;
654
+ struct FloatUnaryOpKind ( UnaryOpKind ) ;
655
+
656
+ impl SMTTranslatable for IntUnaryOpKind {
559
657
fn to_smt ( & self ) -> String {
560
- match self {
658
+ match self . 0 {
561
659
UnaryOpKind :: Not => "not" ,
562
660
UnaryOpKind :: Minus => "-" ,
563
661
}
564
662
. to_string ( )
565
663
}
566
664
}
567
665
666
+ impl SMTTranslatable for FloatUnaryOpKind {
667
+ fn to_smt ( & self ) -> String {
668
+ match self . 0 {
669
+ UnaryOpKind :: Not => unreachable ! ( "FP not" ) ,
670
+ UnaryOpKind :: Minus => "fp.neg" ,
671
+ }
672
+ . to_string ( )
673
+ }
674
+ }
675
+
568
676
impl SMTTranslatable for ContainerOp {
569
677
fn to_smt ( & self ) -> String {
570
678
match & self . kind {
0 commit comments