@@ -37,6 +37,13 @@ pub struct MutableBody {
37
37
span : Span ,
38
38
}
39
39
40
+ /// Denotes whether instrumentation should be inserted before or after the statement.
41
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
42
+ pub enum InsertPosition {
43
+ Before ,
44
+ After ,
45
+ }
46
+
40
47
impl MutableBody {
41
48
/// Get the basic blocks of this builder.
42
49
pub fn blocks ( & self ) -> & [ BasicBlock ] {
@@ -95,12 +102,13 @@ impl MutableBody {
95
102
from : Operand ,
96
103
pointee_ty : Ty ,
97
104
mutability : Mutability ,
98
- before : & mut SourceInstruction ,
105
+ source : & mut SourceInstruction ,
106
+ position : InsertPosition ,
99
107
) -> Local {
100
108
assert ! ( from. ty( self . locals( ) ) . unwrap( ) . kind( ) . is_raw_ptr( ) ) ;
101
109
let target_ty = Ty :: new_ptr ( pointee_ty, mutability) ;
102
110
let rvalue = Rvalue :: Cast ( CastKind :: PtrToPtr , from, target_ty) ;
103
- self . new_assignment ( rvalue, before )
111
+ self . new_assignment ( rvalue, source , position )
104
112
}
105
113
106
114
/// Add a new assignment for the given binary operation.
@@ -111,21 +119,27 @@ impl MutableBody {
111
119
bin_op : BinOp ,
112
120
lhs : Operand ,
113
121
rhs : Operand ,
114
- before : & mut SourceInstruction ,
122
+ source : & mut SourceInstruction ,
123
+ position : InsertPosition ,
115
124
) -> Local {
116
125
let rvalue = Rvalue :: BinaryOp ( bin_op, lhs, rhs) ;
117
- self . new_assignment ( rvalue, before )
126
+ self . new_assignment ( rvalue, source , position )
118
127
}
119
128
120
129
/// Add a new assignment.
121
130
///
122
131
/// Return local where the result is saved.
123
- pub fn new_assignment ( & mut self , rvalue : Rvalue , before : & mut SourceInstruction ) -> Local {
124
- let span = before. span ( & self . blocks ) ;
132
+ pub fn new_assignment (
133
+ & mut self ,
134
+ rvalue : Rvalue ,
135
+ source : & mut SourceInstruction ,
136
+ position : InsertPosition ,
137
+ ) -> Local {
138
+ let span = source. span ( & self . blocks ) ;
125
139
let ret_ty = rvalue. ty ( & self . locals ) . unwrap ( ) ;
126
140
let result = self . new_local ( ret_ty, span, Mutability :: Not ) ;
127
141
let stmt = Statement { kind : StatementKind :: Assign ( Place :: from ( result) , rvalue) , span } ;
128
- self . insert_stmt ( stmt, before ) ;
142
+ self . insert_stmt ( stmt, source , position ) ;
129
143
result
130
144
}
131
145
@@ -139,6 +153,7 @@ impl MutableBody {
139
153
tcx : TyCtxt ,
140
154
check_type : & CheckType ,
141
155
source : & mut SourceInstruction ,
156
+ position : InsertPosition ,
142
157
value : Local ,
143
158
msg : & str ,
144
159
) {
@@ -168,7 +183,7 @@ impl MutableBody {
168
183
unwind : UnwindAction :: Terminate ,
169
184
} ;
170
185
let terminator = Terminator { kind, span } ;
171
- self . split_bb ( source, terminator) ;
186
+ self . split_bb ( source, position , terminator) ;
172
187
}
173
188
CheckType :: Panic | CheckType :: NoCore => {
174
189
tcx. sess
@@ -182,11 +197,55 @@ impl MutableBody {
182
197
}
183
198
}
184
199
185
- /// Split a basic block right before the source location and use the new terminator
186
- /// in the basic block that was split.
200
+ /// Add a new call to the basic block indicated by the given index.
201
+ ///
202
+ /// The new call will have the same span as the source instruction, and the basic block
203
+ /// will be split. The source instruction will be adjusted to point to the first instruction in
204
+ /// the new basic block.
205
+ pub fn add_call (
206
+ & mut self ,
207
+ callee : & Instance ,
208
+ source : & mut SourceInstruction ,
209
+ position : InsertPosition ,
210
+ args : Vec < Operand > ,
211
+ destination : Place ,
212
+ ) {
213
+ let new_bb = self . blocks . len ( ) ;
214
+ let span = source. span ( & self . blocks ) ;
215
+ let callee_op =
216
+ Operand :: Copy ( Place :: from ( self . new_local ( callee. ty ( ) , span, Mutability :: Not ) ) ) ;
217
+ let kind = TerminatorKind :: Call {
218
+ func : callee_op,
219
+ args,
220
+ destination,
221
+ target : Some ( new_bb) ,
222
+ unwind : UnwindAction :: Terminate ,
223
+ } ;
224
+ let terminator = Terminator { kind, span } ;
225
+ self . split_bb ( source, position, terminator) ;
226
+ }
227
+
228
+ /// Split a basic block and use the new terminator in the basic block that was split.
187
229
///
188
230
/// The source is updated to point to the same instruction which is now in the new basic block.
189
- pub fn split_bb ( & mut self , source : & mut SourceInstruction , new_term : Terminator ) {
231
+ pub fn split_bb (
232
+ & mut self ,
233
+ source : & mut SourceInstruction ,
234
+ position : InsertPosition ,
235
+ new_term : Terminator ,
236
+ ) {
237
+ match position {
238
+ InsertPosition :: Before => {
239
+ self . split_bb_before ( source, new_term) ;
240
+ }
241
+ InsertPosition :: After => {
242
+ self . split_bb_after ( source, new_term) ;
243
+ }
244
+ }
245
+ }
246
+
247
+ /// Split a basic block right before the source location.
248
+ fn split_bb_before ( & mut self , source : & mut SourceInstruction , new_term : Terminator ) {
190
249
let new_bb_idx = self . blocks . len ( ) ;
191
250
let ( idx, bb) = match source {
192
251
SourceInstruction :: Statement { idx, bb } => {
@@ -196,9 +255,9 @@ impl MutableBody {
196
255
( orig_idx, orig_bb)
197
256
}
198
257
SourceInstruction :: Terminator { bb } => {
199
- let orig_bb = * bb;
258
+ let ( orig_idx , orig_bb) = ( self . blocks [ * bb] . statements . len ( ) , * bb ) ;
200
259
* bb = new_bb_idx;
201
- ( self . blocks [ orig_bb ] . statements . len ( ) , orig_bb)
260
+ ( orig_idx , orig_bb)
202
261
}
203
262
} ;
204
263
let old_term = mem:: replace ( & mut self . blocks [ bb] . terminator , new_term) ;
@@ -208,16 +267,95 @@ impl MutableBody {
208
267
self . blocks . push ( new_bb) ;
209
268
}
210
269
211
- /// Insert statement before the source instruction and update the source as needed.
212
- pub fn insert_stmt ( & mut self , new_stmt : Statement , before : & mut SourceInstruction ) {
213
- match before {
270
+ /// Split a basic block right after the source location.
271
+ fn split_bb_after ( & mut self , source : & mut SourceInstruction , mut new_term : Terminator ) {
272
+ let new_bb_idx = self . blocks . len ( ) ;
273
+ match source {
274
+ // Split the current block after the statement located at `source`
275
+ // and move the remaining statements into the new one.
214
276
SourceInstruction :: Statement { idx, bb } => {
215
- self . blocks [ * bb] . statements . insert ( * idx, new_stmt) ;
216
- * idx += 1 ;
277
+ let ( orig_idx, orig_bb) = ( * idx, * bb) ;
278
+ * idx = 0 ;
279
+ * bb = new_bb_idx;
280
+ let old_term = mem:: replace ( & mut self . blocks [ orig_bb] . terminator , new_term) ;
281
+ let bb_stmts = & mut self . blocks [ orig_bb] . statements ;
282
+ let remaining = bb_stmts. split_off ( orig_idx + 1 ) ;
283
+ let new_bb = BasicBlock { statements : remaining, terminator : old_term } ;
284
+ self . blocks . push ( new_bb) ;
217
285
}
286
+ // Make the terminator at `source` point at the new block,
287
+ // the terminator of which is a simple Goto instruction.
218
288
SourceInstruction :: Terminator { bb } => {
219
- // Append statements at the end of the basic block.
220
- self . blocks [ * bb] . statements . push ( new_stmt) ;
289
+ let current_terminator = & mut self . blocks . get_mut ( * bb) . unwrap ( ) . terminator ;
290
+ // Kani can only instrument function calls like this.
291
+ match ( & mut current_terminator. kind , & mut new_term. kind ) {
292
+ (
293
+ TerminatorKind :: Call { target : Some ( target_bb) , .. } ,
294
+ TerminatorKind :: Call { target : Some ( new_target_bb) , .. } ,
295
+ ) => {
296
+ // Set the new terminator to point where previous terminator pointed.
297
+ * new_target_bb = * target_bb;
298
+ // Point the current terminator to the new terminator's basic block.
299
+ * target_bb = new_bb_idx;
300
+ // Update the current poisition.
301
+ * bb = new_bb_idx;
302
+ self . blocks . push ( BasicBlock { statements : vec ! [ ] , terminator : new_term } ) ;
303
+ }
304
+ _ => unimplemented ! ( "Kani can only split blocks after calls." ) ,
305
+ } ;
306
+ }
307
+ } ;
308
+ }
309
+
310
+ /// Insert statement before or after the source instruction and update the source as needed.
311
+ pub fn insert_stmt (
312
+ & mut self ,
313
+ new_stmt : Statement ,
314
+ source : & mut SourceInstruction ,
315
+ position : InsertPosition ,
316
+ ) {
317
+ match position {
318
+ InsertPosition :: Before => {
319
+ match source {
320
+ SourceInstruction :: Statement { idx, bb } => {
321
+ self . blocks [ * bb] . statements . insert ( * idx, new_stmt) ;
322
+ * idx += 1 ;
323
+ }
324
+ SourceInstruction :: Terminator { bb } => {
325
+ // Append statements at the end of the basic block.
326
+ self . blocks [ * bb] . statements . push ( new_stmt) ;
327
+ }
328
+ }
329
+ }
330
+ InsertPosition :: After => {
331
+ let new_bb_idx = self . blocks . len ( ) ;
332
+ let span = source. span ( & self . blocks ) ;
333
+ match source {
334
+ SourceInstruction :: Statement { idx, bb } => {
335
+ self . blocks [ * bb] . statements . insert ( * idx + 1 , new_stmt) ;
336
+ * idx += 1 ;
337
+ }
338
+ SourceInstruction :: Terminator { bb } => {
339
+ // Create a new basic block, as we need to append a statement after the terminator.
340
+ let current_terminator = & mut self . blocks . get_mut ( * bb) . unwrap ( ) . terminator ;
341
+ // Kani can only instrument function calls in this way.
342
+ match & mut current_terminator. kind {
343
+ TerminatorKind :: Call { target : Some ( target_bb) , .. } => {
344
+ * source = SourceInstruction :: Statement { idx : 0 , bb : new_bb_idx } ;
345
+ let new_bb = BasicBlock {
346
+ statements : vec ! [ new_stmt] ,
347
+ terminator : Terminator {
348
+ kind : TerminatorKind :: Goto { target : * target_bb } ,
349
+ span,
350
+ } ,
351
+ } ;
352
+ * target_bb = new_bb_idx;
353
+ self . blocks . push ( new_bb) ;
354
+ }
355
+ _ => unimplemented ! ( "Kani can only insert statements after calls." ) ,
356
+ } ;
357
+ }
358
+ }
221
359
}
222
360
}
223
361
}
0 commit comments