Skip to content

Commit 761facf

Browse files
Merge pull request #7550 from remi-delmas-3000/inline-program
Add new function to inline a list of calls in a goto_program
2 parents 3d8cbbb + d7e2e5d commit 761facf

File tree

6 files changed

+135
-0
lines changed

6 files changed

+135
-0
lines changed

src/goto-programs/goto_inline.cpp

+33
Original file line numberDiff line numberDiff line change
@@ -354,3 +354,36 @@ jsont goto_function_inline_and_log(
354354

355355
return goto_inline.output_inline_log_json();
356356
}
357+
358+
/// Transitively inline all function calls found in a particular program.
359+
/// Caller is responsible for calling update(), compute_loop_numbers(), etc.
360+
/// \param goto_functions: The function map to use to find function bodies.
361+
/// \param goto_program: The program whose calls to inline.
362+
/// \param ns: Namespace used by goto_inlinet.
363+
/// \param message_handler: Message handler used by goto_inlinet.
364+
/// \param adjust_function: Replace location in inlined function with call site.
365+
/// \param caching: Tell goto_inlinet to cache.
366+
void goto_program_inline(
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+
{
374+
goto_inlinet goto_inline(
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+
}

src/goto-programs/goto_inline.h

+9
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Author: Daniel Kroening, [email protected]
1818

1919
class goto_functionst;
2020
class goto_modelt;
21+
class goto_programt;
2122
class message_handlert;
2223
class namespacet;
2324

@@ -74,4 +75,12 @@ jsont goto_function_inline_and_log(
7475
bool adjust_function=false,
7576
bool caching=true);
7677

78+
void goto_program_inline(
79+
goto_functionst &goto_functions,
80+
goto_programt &goto_program,
81+
const namespacet &ns,
82+
message_handlert &message_handler,
83+
bool adjust_function = false,
84+
bool caching = true);
85+
7786
#endif // CPROVER_GOTO_PROGRAMS_GOTO_INLINE_H

src/goto-programs/goto_inline_class.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,21 @@ void goto_inlinet::goto_inline(
488488
force_full);
489489
}
490490

491+
void goto_inlinet::goto_inline(
492+
const goto_inlinet::call_listt &call_list,
493+
goto_programt &goto_program,
494+
const bool force_full)
495+
{
496+
recursion_set.clear();
497+
for(const auto &call : call_list)
498+
{
499+
// each top level call in the program gets its own fresh inline map
500+
const inline_mapt inline_map;
501+
expand_function_call(
502+
goto_program, inline_map, call.second, force_full, call.first);
503+
}
504+
}
505+
491506
void goto_inlinet::goto_inline_nontransitive(
492507
const irep_idt identifier,
493508
goto_functiont &goto_function,

src/goto-programs/goto_inline_class.h

+10
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,16 @@ class goto_inlinet
6969
const inline_mapt &inline_map,
7070
const bool force_full=false);
7171

72+
/// \brief Inline specified calls in a given program.
73+
/// \param call_list : calls to inline in the `goto_program`.
74+
/// \param goto_program : goto program to inline `calls_list` in.
75+
/// \param force_full : true to break recursion with a SKIP,
76+
/// false means detecting recursion is an error.
77+
void goto_inline(
78+
const goto_inlinet::call_listt &call_list,
79+
goto_programt &goto_program,
80+
const bool force_full = false);
81+
7282
// handle all functions
7383
void goto_inline(
7484
const inline_mapt &inline_map,

unit/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ SRC += analyses/ai/ai.cpp \
6666
goto-programs/goto_program_declaration.cpp \
6767
goto-programs/goto_program_function_call.cpp \
6868
goto-programs/goto_program_goto_target.cpp \
69+
goto-programs/goto_program_goto_program_inline.cpp \
6970
goto-programs/goto_program_symbol_type_table_consistency.cpp \
7071
goto-programs/goto_program_table_consistency.cpp \
7172
goto-programs/goto_program_validate.cpp \
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*******************************************************************\
2+
3+
Module: Inline calls in program unit tests
4+
5+
Author: Remi Delmas
6+
7+
\*******************************************************************/
8+
9+
#include <util/message.h>
10+
11+
#include <goto-programs/goto_inline.h>
12+
13+
#include <testing-utils/get_goto_model_from_c.h>
14+
#include <testing-utils/use_catch.h>
15+
16+
TEST_CASE("Goto program inline", "[core][goto-programs][goto_program_inline]")
17+
{
18+
const std::string code = R"(
19+
int x;
20+
int y;
21+
void f() { y = 0; }
22+
void g() { x = 0; f(); }
23+
void h() { g(); }
24+
void main() { h(); }
25+
)";
26+
27+
goto_modelt goto_model = get_goto_model_from_c(code);
28+
29+
auto &function = goto_model.goto_functions.function_map.at("h");
30+
31+
null_message_handlert message_handler;
32+
goto_program_inline(
33+
goto_model.goto_functions,
34+
function.body,
35+
namespacet(goto_model.symbol_table),
36+
message_handler);
37+
38+
static int assign_count = 0;
39+
for_each_instruction_if(
40+
function,
41+
[&](goto_programt::const_targett it) {
42+
return it->is_function_call() || it->is_assign();
43+
},
44+
[&](goto_programt::const_targett it) {
45+
if(it->is_function_call())
46+
{
47+
// there are no calls left
48+
FAIL();
49+
}
50+
51+
if(it->is_assign())
52+
{
53+
// the two assignments were inlined
54+
const auto &lhs = it->assign_lhs();
55+
if(assign_count == 0)
56+
{
57+
REQUIRE(to_symbol_expr(lhs).get_identifier() == "x");
58+
}
59+
else if(assign_count == 1)
60+
{
61+
REQUIRE(to_symbol_expr(lhs).get_identifier() == "y");
62+
}
63+
assign_count++;
64+
}
65+
});
66+
REQUIRE(assign_count == 2);
67+
}

0 commit comments

Comments
 (0)