1
- use super :: theory_provider:: * ;
2
- use crate :: native_backend:: fol:: * ;
1
+ use super :: {
2
+ fol:: { vir_to_fol, FolStatement } ,
3
+ theory_provider:: * ,
4
+ } ;
3
5
use lazy_static:: lazy_static;
4
6
use log:: warn;
5
7
use regex:: Regex ;
6
- use std:: collections:: HashMap ;
8
+ use std:: collections:: { HashMap , HashSet } ;
7
9
use vir:: {
8
10
common:: position:: Positioned ,
9
11
low:: {
@@ -24,6 +26,7 @@ pub struct SMTLib {
24
26
func_decls : Vec < String > ,
25
27
code : Vec < String > ,
26
28
methods : HashMap < String , MethodDecl > ,
29
+ blocks : HashMap < String , BasicBlock > ,
27
30
}
28
31
29
32
impl SMTLib {
@@ -33,6 +36,7 @@ impl SMTLib {
33
36
func_decls : Vec :: new ( ) ,
34
37
code : Vec :: new ( ) ,
35
38
methods : HashMap :: new ( ) ,
39
+ blocks : Default :: default ( ) ,
36
40
}
37
41
}
38
42
fn add_sort_decl ( & mut self , sort_decl : String ) {
@@ -48,8 +52,66 @@ impl SMTLib {
48
52
fn add_code ( & mut self , text : String ) {
49
53
self . code . push ( text) ;
50
54
}
51
- fn add_code_lines ( & mut self , texts : impl Iterator < Item = String > ) {
52
- self . code . extend ( texts) ;
55
+ fn follow ( & mut self , block_label : & String , precond : Option < & Expression > ) {
56
+ let block = self
57
+ . blocks
58
+ . get ( block_label)
59
+ . expect ( "Block not found" )
60
+ . clone ( ) ;
61
+
62
+ if block. statements . is_empty ( ) {
63
+ return ;
64
+ }
65
+
66
+ self . add_code ( format ! ( "; Basic block: {}" , block. label) ) ;
67
+ self . add_code ( "(push)" . to_string ( ) ) ;
68
+
69
+ // assume precond if any
70
+ if let Some ( precond) = precond {
71
+ self . add_code ( "; Branch precond:" . to_string ( ) ) ;
72
+ self . add_code ( format ! ( "(assert {})" , precond. to_smt( ) ) ) ;
73
+ }
74
+
75
+ // verify body
76
+ let predicates = vir_to_fol ( & block. statements , & self . methods ) ;
77
+
78
+ for predicate in predicates. into_iter ( ) {
79
+ match predicate {
80
+ FolStatement :: Comment ( comment) => self . add_code ( format ! ( "; {}" , comment) ) ,
81
+ FolStatement :: Assume ( expression) => {
82
+ // assert predicate
83
+ self . add_code ( format ! ( "(assert {})" , expression. to_smt( ) ) ) ;
84
+ }
85
+ FolStatement :: Assert ( expression) => {
86
+ // negate predicate
87
+ let position = expression. position ( ) ;
88
+ let negated = Expression :: UnaryOp ( UnaryOp {
89
+ op_kind : UnaryOpKind :: Not ,
90
+ argument : Box :: new ( expression) ,
91
+ position,
92
+ } ) ;
93
+ // assert negated predicate
94
+ self . add_code ( "(push)" . to_string ( ) ) ;
95
+ self . add_code ( format ! ( "(assert {})" , negated. to_smt( ) ) ) ;
96
+ self . add_code ( "(check-sat)" . to_string ( ) ) ;
97
+ self . add_code ( "(pop)" . to_string ( ) ) ;
98
+ }
99
+ FolStatement :: Choice ( _, _) => unimplemented ! ( "Choice" ) ,
100
+ }
101
+ }
102
+
103
+ // process successor
104
+ match & block. successor {
105
+ Successor :: Goto ( label) => {
106
+ self . follow ( & label. name , None ) ;
107
+ }
108
+ Successor :: GotoSwitch ( mapping) => mapping. iter ( ) . for_each ( |( expr, label) | {
109
+ self . follow ( & label. name , Some ( expr) ) ;
110
+ } ) ,
111
+ Successor :: Return => { }
112
+ }
113
+
114
+ self . add_code ( format ! ( "(pop); End basic block: {}" , block. label) ) ;
53
115
}
54
116
}
55
117
@@ -117,12 +179,19 @@ impl ToString for SMTLib {
117
179
}
118
180
119
181
result. push_str ( & main) ;
182
+
183
+ // strip all lines containing "$marker"
184
+ // TODO: SSO form for marker variables?
120
185
result
186
+ . lines ( )
187
+ . filter ( |line| !line. contains ( "$marker" ) )
188
+ . collect :: < Vec < _ > > ( )
189
+ . join ( "\n " )
121
190
}
122
191
}
123
192
124
193
pub trait SMTTranslatable {
125
- fn build_smt ( & self , smt : & mut SMTLib ) {
194
+ fn build_smt ( & self , _ : & mut SMTLib ) {
126
195
unimplemented ! ( )
127
196
}
128
197
fn to_smt ( & self ) -> String {
@@ -230,7 +299,37 @@ impl SMTTranslatable for ProcedureDecl {
230
299
self . locals . iter ( ) . for_each ( |l| l. build_smt ( smt) ) ;
231
300
232
301
// process basic blocks
233
- self . basic_blocks . iter ( ) . for_each ( |b| b. build_smt ( smt) ) ;
302
+ smt. blocks . clear ( ) ;
303
+
304
+ self . basic_blocks . iter ( ) . for_each ( |b| {
305
+ smt. blocks . insert ( b. label . name . clone ( ) , b. clone ( ) ) ; // TODO: Inefficient copy
306
+ } ) ;
307
+
308
+ // find a starting block
309
+ let mut start_blocks = smt. blocks . keys ( ) . collect :: < HashSet < _ > > ( ) ;
310
+
311
+ for ( _, block) in & smt. blocks {
312
+ match & block. successor {
313
+ Successor :: Goto ( label) => {
314
+ start_blocks. remove ( & label. name ) ;
315
+ }
316
+ Successor :: GotoSwitch ( labels) => {
317
+ labels. iter ( ) . for_each ( |( _, l) | {
318
+ start_blocks. remove ( & l. name ) ;
319
+ } ) ;
320
+ }
321
+ Successor :: Return => { }
322
+ }
323
+ }
324
+
325
+ assert ! (
326
+ start_blocks. len( ) == 1 ,
327
+ "Expected exactly one start block, found {}" ,
328
+ start_blocks. len( )
329
+ ) ;
330
+
331
+ let start = start_blocks. drain ( ) . next ( ) . unwrap ( ) . clone ( ) ;
332
+ smt. follow ( & start, None ) ;
234
333
235
334
smt. add_code ( "(pop)" . to_string ( ) ) ;
236
335
}
@@ -246,51 +345,6 @@ impl SMTTranslatable for VariableDecl {
246
345
}
247
346
}
248
347
249
- impl SMTTranslatable for BasicBlock {
250
- fn build_smt ( & self , smt : & mut SMTLib ) {
251
- if self . statements . is_empty ( ) {
252
- return ;
253
- }
254
-
255
- let mut code = Vec :: new ( ) ;
256
-
257
- code. push ( format ! ( "; Basic block: {}" , self . label) ) ;
258
- code. push ( "(push)" . to_string ( ) ) ;
259
-
260
- // verify body
261
- let predicates = vir_statements_to_predicates ( & self . statements , & smt. methods ) ;
262
-
263
- let mut assertions = 0 ;
264
- for predicate in predicates. into_iter ( ) {
265
- match predicate {
266
- SMTGenTarget :: Predicate ( expression) => {
267
- // negate predicate
268
- let position = expression. position ( ) ;
269
- let negated = Expression :: UnaryOp ( UnaryOp {
270
- op_kind : UnaryOpKind :: Not ,
271
- argument : Box :: new ( expression) ,
272
- position,
273
- } ) ;
274
- // assert negated predicate
275
- code. push ( format ! ( "(assert {})" , negated. to_smt( ) ) ) ;
276
- assertions += 1 ;
277
- }
278
- SMTGenTarget :: Comment ( comment) => code. push ( format ! ( "; {}" , comment) ) ,
279
- }
280
- }
281
-
282
- // check if the negated predicates are satisfiable
283
- // TODO: each in its own scope?
284
- if assertions > 0 {
285
- code. push ( "(check-sat)" . to_string ( ) ) ;
286
- code. push ( "(pop)" . to_string ( ) ) ;
287
- smt. add_code_lines ( code. into_iter ( ) ) ;
288
- }
289
-
290
- // TODO: Goto
291
- }
292
- }
293
-
294
348
/* #endregion */
295
349
296
350
impl SMTTranslatable for Expression {
0 commit comments