CBMC
goto_inline.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Function Inlining
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
11 
12 #include "goto_inline.h"
13 
14 #include <util/std_expr.h>
15 
16 #include "goto_inline_class.h"
17 #include "goto_model.h"
18 
27  goto_modelt &goto_model,
28  message_handlert &message_handler,
29  bool adjust_function)
30 {
31  const namespacet ns(goto_model.symbol_table);
33  goto_model.goto_functions,
34  ns,
35  message_handler,
36  adjust_function);
37 }
38 
48  goto_functionst &goto_functions,
49  const namespacet &ns,
50  message_handlert &message_handler,
51  bool adjust_function)
52 {
54  goto_functions,
55  ns,
56  message_handler,
57  adjust_function);
58 
60 
61  // find entry point
62  goto_functionst::function_mapt::iterator it=
63  goto_functions.function_map.find(goto_functionst::entry_point());
64 
65  if(it==goto_functions.function_map.end())
66  return;
67 
68  goto_functiont &entry_function = it->second;
70  entry_function.body_available(),
71  "body of entry point function must be available");
72 
73  // gather all calls
74  // we use non-transitive inlining to avoid the goto program
75  // copying that goto_inlinet would do otherwise
76  goto_inlinet::inline_mapt inline_map;
77 
78  for(auto &gf_entry : goto_functions.function_map)
79  {
80  goto_functiont &goto_function = gf_entry.second;
81 
82  if(!goto_function.body_available())
83  continue;
84 
85  goto_inlinet::call_listt &call_list = inline_map[gf_entry.first];
86 
87  goto_programt &goto_program=goto_function.body;
88 
89  Forall_goto_program_instructions(i_it, goto_program)
90  {
91  if(!i_it->is_function_call())
92  continue;
93 
94  call_list.push_back(goto_inlinet::callt(i_it, false));
95  }
96  }
97 
98  goto_inline.goto_inline(
99  goto_functionst::entry_point(), entry_function, inline_map, true);
100 
101  // clean up
102  for(auto &gf_entry : goto_functions.function_map)
103  {
104  if(gf_entry.first != goto_functionst::entry_point())
105  {
106  goto_functiont &goto_function = gf_entry.second;
107  goto_function.body.clear();
108  }
109  }
110 }
111 
123  goto_modelt &goto_model,
124  message_handlert &message_handler,
125  unsigned smallfunc_limit,
126  bool adjust_function)
127 {
128  const namespacet ns(goto_model.symbol_table);
130  goto_model.goto_functions,
131  ns,
132  message_handler,
133  smallfunc_limit,
134  adjust_function);
135 }
136 
150  goto_functionst &goto_functions,
151  const namespacet &ns,
152  message_handlert &message_handler,
153  unsigned smallfunc_limit,
154  bool adjust_function)
155 {
157  goto_functions,
158  ns,
159  message_handler,
160  adjust_function);
161 
163 
164  // gather all calls
165  goto_inlinet::inline_mapt inline_map;
166 
167  for(auto &gf_entry : goto_functions.function_map)
168  {
169  goto_functiont &goto_function = gf_entry.second;
170 
171  if(!goto_function.body_available())
172  continue;
173 
174  if(gf_entry.first == goto_functions.entry_point())
175  {
176  // Don't inline any function calls made from the _start function.
177  // This is so that the convention of __CPROVER_start
178  // calling __CPROVER_initialize is maintained, so these can be
179  // augmented / replaced by later passes.
180  continue;
181  }
182 
183  goto_programt &goto_program=goto_function.body;
184 
185  goto_inlinet::call_listt &call_list = inline_map[gf_entry.first];
186 
187  Forall_goto_program_instructions(i_it, goto_program)
188  {
189  if(!i_it->is_function_call())
190  continue;
191 
192  exprt lhs;
193  exprt function_expr;
194  exprt::operandst arguments;
195  goto_inlinet::get_call(i_it, lhs, function_expr, arguments);
196 
197  if(function_expr.id()!=ID_symbol)
198  // Can't handle pointers to functions
199  continue;
200 
201  const symbol_exprt &symbol_expr=to_symbol_expr(function_expr);
202  const irep_idt id=symbol_expr.get_identifier();
203 
204  goto_functionst::function_mapt::const_iterator called_it =
205  goto_functions.function_map.find(id);
206 
207  if(called_it == goto_functions.function_map.end())
208  // Function not loaded, can't check size
209  continue;
210 
211  // called function
212  const goto_functiont &called_function = called_it->second;
213 
214  if(!called_function.body_available())
215  // The bodies of functions that don't have bodies can't be inlined.
216  continue;
217 
218  if(
219  to_code_type(ns.lookup(id).type).get_inlined() ||
220  called_function.body.instructions.size() <= smallfunc_limit)
221  {
222  PRECONDITION(i_it->is_function_call());
223 
224  call_list.push_back(goto_inlinet::callt(i_it, false));
225  }
226  }
227  }
228 
229  goto_inline.goto_inline(inline_map, false);
230 }
231 
240  goto_modelt &goto_model,
241  const irep_idt function,
242  message_handlert &message_handler,
243  bool adjust_function,
244  bool caching)
245 {
246  const namespacet ns(goto_model.symbol_table);
248  goto_model.goto_functions,
249  function,
250  ns,
251  message_handler,
252  adjust_function,
253  caching);
254 }
255 
265  goto_functionst &goto_functions,
266  const irep_idt function,
267  const namespacet &ns,
268  message_handlert &message_handler,
269  bool adjust_function,
270  bool caching)
271 {
273  goto_functions,
274  ns,
275  message_handler,
276  adjust_function,
277  caching);
278 
279  goto_functionst::function_mapt::iterator f_it=
280  goto_functions.function_map.find(function);
281 
282  if(f_it==goto_functions.function_map.end())
283  return;
284 
285  goto_functionst::goto_functiont &goto_function=f_it->second;
286 
287  if(!goto_function.body_available())
288  return;
289 
290  // gather all calls
291  goto_inlinet::inline_mapt inline_map;
292 
293  goto_inlinet::call_listt &call_list=inline_map[f_it->first];
294 
295  goto_programt &goto_program=goto_function.body;
296 
297  Forall_goto_program_instructions(i_it, goto_program)
298  {
299  if(!i_it->is_function_call())
300  continue;
301 
302  call_list.push_back(goto_inlinet::callt(i_it, true));
303  }
304 
305  goto_inline.goto_inline(function, goto_function, inline_map, true);
306 }
307 
309  goto_modelt &goto_model,
310  const irep_idt function,
311  message_handlert &message_handler,
312  bool adjust_function,
313  bool caching)
314 {
315  const namespacet ns(goto_model.symbol_table);
316 
318  goto_model.goto_functions,
319  ns,
320  message_handler,
321  adjust_function,
322  caching);
323 
324  goto_functionst::function_mapt::iterator f_it=
325  goto_model.goto_functions.function_map.find(function);
326 
327  if(f_it==goto_model.goto_functions.function_map.end())
328  return jsont();
329 
330  goto_functionst::goto_functiont &goto_function=f_it->second;
331 
332  if(!goto_function.body_available())
333  return jsont();
334 
335  // gather all calls
336  goto_inlinet::inline_mapt inline_map;
337 
338  // create empty call list
339  goto_inlinet::call_listt &call_list=inline_map[f_it->first];
340 
341  goto_programt &goto_program=goto_function.body;
342 
343  Forall_goto_program_instructions(i_it, goto_program)
344  {
345  if(!i_it->is_function_call())
346  continue;
347 
348  call_list.push_back(goto_inlinet::callt(i_it, true));
349  }
350 
351  goto_inline.goto_inline(function, goto_function, inline_map, true);
352  goto_model.goto_functions.update();
354 
355  return goto_inline.output_inline_log_json();
356 }
357 
367  goto_functionst &goto_functions,
368  goto_programt &goto_program,
369  const namespacet &ns,
370  message_handlert &message_handler,
371  bool adjust_function,
372  bool caching)
373 {
375  goto_functions, ns, message_handler, adjust_function, caching);
376 
377  // gather all calls found in the program
378  goto_inlinet::call_listt call_list;
379 
380  Forall_goto_program_instructions(i_it, goto_program)
381  {
382  if(!i_it->is_function_call())
383  continue;
384 
385  call_list.push_back(goto_inlinet::callt(i_it, true));
386  }
387 
388  goto_inline.goto_inline(call_list, goto_program, true);
389 }
bool get_inlined() const
Definition: std_types.h:709
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
Base class for all expressions.
Definition: expr.h:56
std::vector< exprt > operandst
Definition: expr.h:58
A collection of goto functions.
void compute_loop_numbers()
function_mapt function_map
::goto_functiont goto_functiont
static irep_idt entry_point()
Get the identifier of the entry point to a goto model.
A goto function, consisting of function body (see body) and parameter identifiers (see parameter_iden...
Definition: goto_function.h:24
goto_programt body
Definition: goto_function.h:26
bool body_available() const
Definition: goto_function.h:35
std::list< callt > call_listt
static void get_call(goto_programt::const_targett target, exprt &lhs, exprt &function, exprt::operandst &arguments)
std::pair< goto_programt::targett, bool > callt
std::map< irep_idt, call_listt > inline_mapt
symbol_tablet symbol_table
Symbol table.
Definition: goto_model.h:31
goto_functionst goto_functions
GOTO functions.
Definition: goto_model.h:34
A generic container class for the GOTO intermediate representation of one function.
Definition: goto_program.h:73
instructionst instructions
The list of instructions in the goto program.
Definition: goto_program.h:622
void clear()
Clear the goto program.
Definition: goto_program.h:820
const irep_idt & id() const
Definition: irep.h:388
Definition: json.h:27
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Definition: namespace.cpp:148
Expression to hold a symbol (variable)
Definition: std_expr.h:131
const irep_idt & get_identifier() const
Definition: std_expr.h:160
void goto_program_inline(goto_functionst &goto_functions, goto_programt &goto_program, const namespacet &ns, message_handlert &message_handler, bool adjust_function, bool caching)
Transitively inline all function calls found in a particular program.
void goto_inline(goto_modelt &goto_model, message_handlert &message_handler, bool adjust_function)
Inline every function call into the entry_point() function.
Definition: goto_inline.cpp:26
void goto_function_inline(goto_modelt &goto_model, const irep_idt function, message_handlert &message_handler, bool adjust_function, bool caching)
Transitively inline all function calls made from a particular function.
void goto_partial_inline(goto_modelt &goto_model, message_handlert &message_handler, unsigned smallfunc_limit, bool adjust_function)
Inline all function calls to functions either marked as "inlined" or smaller than smallfunc_limit (by...
jsont goto_function_inline_and_log(goto_modelt &goto_model, const irep_idt function, message_handlert &message_handler, bool adjust_function, bool caching)
Function Inlining This gives a number of different interfaces to the function inlining functionality ...
Function Inlining This is a class that encapsulates the state and functionality needed to do inline m...
Symbol Table + CFG.
#define Forall_goto_program_instructions(it, program)
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition: invariant.h:534
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
API to expression classes.
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition: std_types.h:788