@@ -88,16 +88,20 @@ impl MutableBody {
88
88
89
89
pub fn new_str_operand ( & mut self , msg : & str , span : Span ) -> Operand {
90
90
let literal = MirConst :: from_str ( msg) ;
91
- Operand :: Constant ( ConstOperand { span , user_ty : None , const_ : literal } )
91
+ self . new_const_operand ( literal , span )
92
92
}
93
93
94
- pub fn new_const_operand ( & mut self , val : u128 , uint_ty : UintTy , span : Span ) -> Operand {
94
+ pub fn new_uint_operand ( & mut self , val : u128 , uint_ty : UintTy , span : Span ) -> Operand {
95
95
let literal = MirConst :: try_from_uint ( val, uint_ty) . unwrap ( ) ;
96
+ self . new_const_operand ( literal, span)
97
+ }
98
+
99
+ fn new_const_operand ( & mut self , literal : MirConst , span : Span ) -> Operand {
96
100
Operand :: Constant ( ConstOperand { span, user_ty : None , const_ : literal } )
97
101
}
98
102
99
103
/// Create a raw pointer of `*mut type` and return a new local where that value is stored.
100
- pub fn new_cast_ptr (
104
+ pub fn insert_ptr_cast (
101
105
& mut self ,
102
106
from : Operand ,
103
107
pointee_ty : Ty ,
@@ -108,13 +112,13 @@ impl MutableBody {
108
112
assert ! ( from. ty( self . locals( ) ) . unwrap( ) . kind( ) . is_raw_ptr( ) ) ;
109
113
let target_ty = Ty :: new_ptr ( pointee_ty, mutability) ;
110
114
let rvalue = Rvalue :: Cast ( CastKind :: PtrToPtr , from, target_ty) ;
111
- self . new_assignment ( rvalue, source, position)
115
+ self . insert_assignment ( rvalue, source, position)
112
116
}
113
117
114
118
/// Add a new assignment for the given binary operation.
115
119
///
116
120
/// Return the local where the result is saved.
117
- pub fn new_binary_op (
121
+ pub fn insert_binary_op (
118
122
& mut self ,
119
123
bin_op : BinOp ,
120
124
lhs : Operand ,
@@ -123,13 +127,13 @@ impl MutableBody {
123
127
position : InsertPosition ,
124
128
) -> Local {
125
129
let rvalue = Rvalue :: BinaryOp ( bin_op, lhs, rhs) ;
126
- self . new_assignment ( rvalue, source, position)
130
+ self . insert_assignment ( rvalue, source, position)
127
131
}
128
132
129
133
/// Add a new assignment.
130
134
///
131
- /// Return local where the result is saved.
132
- pub fn new_assignment (
135
+ /// Return the local where the result is saved.
136
+ pub fn insert_assignment (
133
137
& mut self ,
134
138
rvalue : Rvalue ,
135
139
source : & mut SourceInstruction ,
@@ -146,9 +150,10 @@ impl MutableBody {
146
150
/// Add a new assert to the basic block indicated by the given index.
147
151
///
148
152
/// The new assertion will have the same span as the source instruction, and the basic block
149
- /// will be split. The source instruction will be adjusted to point to the first instruction in
150
- /// the new basic block.
151
- pub fn add_check (
153
+ /// will be split. If `InsertPosition` is `InsertPosition::Before`, `source` will point to the
154
+ /// same instruction as before. If `InsertPosition` is `InsertPosition::After`, `source` will
155
+ /// point to the new terminator.
156
+ pub fn insert_check (
152
157
& mut self ,
153
158
tcx : TyCtxt ,
154
159
check_type : & CheckType ,
@@ -183,7 +188,7 @@ impl MutableBody {
183
188
unwind : UnwindAction :: Terminate ,
184
189
} ;
185
190
let terminator = Terminator { kind, span } ;
186
- self . split_bb ( source, position, terminator) ;
191
+ self . insert_terminator ( source, position, terminator) ;
187
192
}
188
193
CheckType :: Panic | CheckType :: NoCore => {
189
194
tcx. sess
@@ -199,10 +204,11 @@ impl MutableBody {
199
204
200
205
/// Add a new call to the basic block indicated by the given index.
201
206
///
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 (
207
+ /// The new call will have the same span as the source instruction, and the basic block will be
208
+ /// split. If `InsertPosition` is `InsertPosition::Before`, `source` will point to the same
209
+ /// instruction as before. If `InsertPosition` is `InsertPosition::After`, `source` will point
210
+ /// to the new terminator.
211
+ pub fn insert_call (
206
212
& mut self ,
207
213
callee : & Instance ,
208
214
source : & mut SourceInstruction ,
@@ -222,13 +228,14 @@ impl MutableBody {
222
228
unwind : UnwindAction :: Terminate ,
223
229
} ;
224
230
let terminator = Terminator { kind, span } ;
225
- self . split_bb ( source, position, terminator) ;
231
+ self . insert_terminator ( source, position, terminator) ;
226
232
}
227
233
228
- /// Split a basic block and use the new terminator in the basic block that was split.
229
- ///
230
- /// The source is updated to point to the same instruction which is now in the new basic block.
231
- pub fn split_bb (
234
+ /// Split a basic block and use the new terminator in the basic block that was split. If
235
+ /// `InsertPosition` is `InsertPosition::Before`, `source` will point to the same instruction as
236
+ /// before. If `InsertPosition` is `InsertPosition::After`, `source` will point to the new
237
+ /// terminator.
238
+ fn split_bb (
232
239
& mut self ,
233
240
source : & mut SourceInstruction ,
234
241
position : InsertPosition ,
@@ -245,6 +252,7 @@ impl MutableBody {
245
252
}
246
253
247
254
/// Split a basic block right before the source location.
255
+ /// `source` will point to the same instruction as before after the function is done.
248
256
fn split_bb_before ( & mut self , source : & mut SourceInstruction , new_term : Terminator ) {
249
257
let new_bb_idx = self . blocks . len ( ) ;
250
258
let ( idx, bb) = match source {
@@ -268,46 +276,77 @@ impl MutableBody {
268
276
}
269
277
270
278
/// Split a basic block right after the source location.
279
+ /// `source` will point to the new terminator after the function is done.
271
280
fn split_bb_after ( & mut self , source : & mut SourceInstruction , mut new_term : Terminator ) {
272
281
let new_bb_idx = self . blocks . len ( ) ;
273
282
match source {
274
283
// Split the current block after the statement located at `source`
275
284
// and move the remaining statements into the new one.
276
285
SourceInstruction :: Statement { idx, bb } => {
277
286
let ( orig_idx, orig_bb) = ( * idx, * bb) ;
278
- * idx = 0 ;
279
- * bb = new_bb_idx;
280
287
let old_term = mem:: replace ( & mut self . blocks [ orig_bb] . terminator , new_term) ;
281
288
let bb_stmts = & mut self . blocks [ orig_bb] . statements ;
282
289
let remaining = bb_stmts. split_off ( orig_idx + 1 ) ;
283
290
let new_bb = BasicBlock { statements : remaining, terminator : old_term } ;
284
291
self . blocks . push ( new_bb) ;
292
+ // Update the source to point at the terminator.
293
+ * source = SourceInstruction :: Terminator { bb : orig_bb } ;
285
294
}
286
295
// Make the terminator at `source` point at the new block,
287
296
// the terminator of which is a simple Goto instruction.
288
297
SourceInstruction :: Terminator { bb } => {
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
- } ;
298
+ let current_term = & mut self . blocks . get_mut ( * bb) . unwrap ( ) . terminator ;
299
+ let target_bb = get_mut_target_ref ( current_term) ;
300
+ let new_target_bb = get_mut_target_ref ( & mut new_term) ;
301
+ // Set the new terminator to point where previous terminator pointed.
302
+ * new_target_bb = * target_bb;
303
+ // Point the current terminator to the new terminator's basic block.
304
+ * target_bb = new_bb_idx;
305
+ // Update the source to point at the terminator.
306
+ * bb = new_bb_idx;
307
+ self . blocks . push ( BasicBlock { statements : vec ! [ ] , terminator : new_term } ) ;
306
308
}
307
309
} ;
308
310
}
309
311
310
- /// Insert statement before or after the source instruction and update the source as needed.
312
+ /// Insert basic block before or after the source instruction and update `source` accordingly. If
313
+ /// `InsertPosition` is `InsertPosition::Before`, `source` will point to the same instruction as
314
+ /// before. If `InsertPosition` is `InsertPosition::After`, `source` will point to the
315
+ /// terminator of the newly inserted basic block.
316
+ pub fn insert_bb (
317
+ & mut self ,
318
+ mut bb : BasicBlock ,
319
+ source : & mut SourceInstruction ,
320
+ position : InsertPosition ,
321
+ ) {
322
+ // Splitting adds 1 block, so the added block index is len + 1;
323
+ let split_bb_idx = self . blocks ( ) . len ( ) ;
324
+ let inserted_bb_idx = self . blocks ( ) . len ( ) + 1 ;
325
+ // Update the terminator of the basic block to point at the remaining part of the split
326
+ // basic block.
327
+ let target = get_mut_target_ref ( & mut bb. terminator ) ;
328
+ * target = split_bb_idx;
329
+ let new_term = Terminator {
330
+ kind : TerminatorKind :: Goto { target : inserted_bb_idx } ,
331
+ span : source. span ( & self . blocks ) ,
332
+ } ;
333
+ self . split_bb ( source, position, new_term) ;
334
+ self . blocks . push ( bb) ;
335
+ }
336
+
337
+ pub fn insert_terminator (
338
+ & mut self ,
339
+ source : & mut SourceInstruction ,
340
+ position : InsertPosition ,
341
+ terminator : Terminator ,
342
+ ) {
343
+ self . split_bb ( source, position, terminator) ;
344
+ }
345
+
346
+ /// Insert statement before or after the source instruction and update the source as needed. If
347
+ /// `InsertPosition` is `InsertPosition::Before`, `source` will point to the same instruction as
348
+ /// before. If `InsertPosition` is `InsertPosition::After`, `source` will point to the
349
+ /// newly inserted statement.
311
350
pub fn insert_stmt (
312
351
& mut self ,
313
352
new_stmt : Statement ,
@@ -338,22 +377,18 @@ impl MutableBody {
338
377
SourceInstruction :: Terminator { bb } => {
339
378
// Create a new basic block, as we need to append a statement after the terminator.
340
379
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." ) ,
380
+ // Update target of the terminator.
381
+ let target_bb = get_mut_target_ref ( current_terminator) ;
382
+ * source = SourceInstruction :: Statement { idx : 0 , bb : new_bb_idx } ;
383
+ let new_bb = BasicBlock {
384
+ statements : vec ! [ new_stmt] ,
385
+ terminator : Terminator {
386
+ kind : TerminatorKind :: Goto { target : * target_bb } ,
387
+ span,
388
+ } ,
356
389
} ;
390
+ * target_bb = new_bb_idx;
391
+ self . blocks . push ( new_bb) ;
357
392
}
358
393
}
359
394
}
@@ -574,3 +609,15 @@ pub trait MutMirVisitor {
574
609
}
575
610
}
576
611
}
612
+
613
+ fn get_mut_target_ref ( terminator : & mut Terminator ) -> & mut BasicBlockIdx {
614
+ match & mut terminator. kind {
615
+ TerminatorKind :: Assert { target, .. }
616
+ | TerminatorKind :: Drop { target, .. }
617
+ | TerminatorKind :: Goto { target }
618
+ | TerminatorKind :: Call { target : Some ( target) , .. } => target,
619
+ _ => unimplemented ! (
620
+ "Kani can only insert instructions after terminators that have a `target` field."
621
+ ) ,
622
+ }
623
+ }
0 commit comments