@@ -37,6 +37,13 @@ pub struct MutableBody {
3737 span : Span ,
3838}
3939
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+
4047impl MutableBody {
4148 /// Get the basic blocks of this builder.
4249 pub fn blocks ( & self ) -> & [ BasicBlock ] {
@@ -95,12 +102,13 @@ impl MutableBody {
95102 from : Operand ,
96103 pointee_ty : Ty ,
97104 mutability : Mutability ,
98- before : & mut SourceInstruction ,
105+ source : & mut SourceInstruction ,
106+ position : InsertPosition ,
99107 ) -> Local {
100108 assert ! ( from. ty( self . locals( ) ) . unwrap( ) . kind( ) . is_raw_ptr( ) ) ;
101109 let target_ty = Ty :: new_ptr ( pointee_ty, mutability) ;
102110 let rvalue = Rvalue :: Cast ( CastKind :: PtrToPtr , from, target_ty) ;
103- self . new_assignment ( rvalue, before )
111+ self . new_assignment ( rvalue, source , position )
104112 }
105113
106114 /// Add a new assignment for the given binary operation.
@@ -111,21 +119,27 @@ impl MutableBody {
111119 bin_op : BinOp ,
112120 lhs : Operand ,
113121 rhs : Operand ,
114- before : & mut SourceInstruction ,
122+ source : & mut SourceInstruction ,
123+ position : InsertPosition ,
115124 ) -> Local {
116125 let rvalue = Rvalue :: BinaryOp ( bin_op, lhs, rhs) ;
117- self . new_assignment ( rvalue, before )
126+ self . new_assignment ( rvalue, source , position )
118127 }
119128
120129 /// Add a new assignment.
121130 ///
122131 /// 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 ) ;
125139 let ret_ty = rvalue. ty ( & self . locals ) . unwrap ( ) ;
126140 let result = self . new_local ( ret_ty, span, Mutability :: Not ) ;
127141 let stmt = Statement { kind : StatementKind :: Assign ( Place :: from ( result) , rvalue) , span } ;
128- self . insert_stmt ( stmt, before ) ;
142+ self . insert_stmt ( stmt, source , position ) ;
129143 result
130144 }
131145
@@ -139,6 +153,7 @@ impl MutableBody {
139153 tcx : TyCtxt ,
140154 check_type : & CheckType ,
141155 source : & mut SourceInstruction ,
156+ position : InsertPosition ,
142157 value : Local ,
143158 msg : & str ,
144159 ) {
@@ -168,7 +183,7 @@ impl MutableBody {
168183 unwind : UnwindAction :: Terminate ,
169184 } ;
170185 let terminator = Terminator { kind, span } ;
171- self . split_bb ( source, terminator) ;
186+ self . split_bb ( source, position , terminator) ;
172187 }
173188 CheckType :: Panic | CheckType :: NoCore => {
174189 tcx. sess
@@ -182,11 +197,55 @@ impl MutableBody {
182197 }
183198 }
184199
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.
187229 ///
188230 /// 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 ) {
190249 let new_bb_idx = self . blocks . len ( ) ;
191250 let ( idx, bb) = match source {
192251 SourceInstruction :: Statement { idx, bb } => {
@@ -196,9 +255,9 @@ impl MutableBody {
196255 ( orig_idx, orig_bb)
197256 }
198257 SourceInstruction :: Terminator { bb } => {
199- let orig_bb = * bb;
258+ let ( orig_idx , orig_bb) = ( self . blocks [ * bb] . statements . len ( ) , * bb ) ;
200259 * bb = new_bb_idx;
201- ( self . blocks [ orig_bb ] . statements . len ( ) , orig_bb)
260+ ( orig_idx , orig_bb)
202261 }
203262 } ;
204263 let old_term = mem:: replace ( & mut self . blocks [ bb] . terminator , new_term) ;
@@ -208,16 +267,95 @@ impl MutableBody {
208267 self . blocks . push ( new_bb) ;
209268 }
210269
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.
214276 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) ;
217285 }
286+ // Make the terminator at `source` point at the new block,
287+ // the terminator of which is a simple Goto instruction.
218288 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+ }
221359 }
222360 }
223361 }
0 commit comments