Skip to content

Commit ee42ac6

Browse files
committed
Linking: perform macro expansion and type updates just once
This reduces the Linux kernel link time by more than 90% as the previous approach would repeatedly attempt renamings and replacements across all hitherto read goto program instructions.
1 parent 895a674 commit ee42ac6

File tree

3 files changed

+81
-58
lines changed

3 files changed

+81
-58
lines changed

src/goto-programs/link_goto_model.cpp

Lines changed: 53 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ Author: Michael Tautschnig, Daniel Kroening
1717
#include <util/rename_symbol.h>
1818

1919
#include <linking/linking_class.h>
20-
#include <util/exception_utils.h>
2120

2221
#include "goto_model.h"
2322

@@ -54,8 +53,7 @@ static bool link_functions(
5453
const symbol_tablet &src_symbol_table,
5554
goto_functionst &src_functions,
5655
const rename_symbolt &rename_symbol,
57-
const std::unordered_set<irep_idt> &weak_symbols,
58-
const replace_symbolt &object_type_updates)
56+
const std::unordered_set<irep_idt> &weak_symbols)
5957
{
6058
namespacet ns(dest_symbol_table);
6159
namespacet src_ns(src_symbol_table);
@@ -109,6 +107,58 @@ static bool link_functions(
109107
}
110108
}
111109

110+
return false;
111+
}
112+
113+
optionalt<replace_symbolt::expr_mapt> link_goto_model(
114+
goto_modelt &dest,
115+
goto_modelt &&src,
116+
message_handlert &message_handler)
117+
{
118+
std::unordered_set<irep_idt> weak_symbols;
119+
120+
for(const auto &symbol_pair : dest.symbol_table.symbols)
121+
{
122+
if(symbol_pair.second.is_weak)
123+
weak_symbols.insert(symbol_pair.first);
124+
}
125+
126+
linkingt linking(dest.symbol_table, src.symbol_table, message_handler);
127+
128+
if(linking.typecheck_main())
129+
{
130+
messaget log{message_handler};
131+
log.error() << "typechecking main failed" << messaget::eom;
132+
return {};
133+
}
134+
135+
if(link_functions(
136+
dest.symbol_table,
137+
dest.goto_functions,
138+
src.symbol_table,
139+
src.goto_functions,
140+
linking.rename_symbol,
141+
weak_symbols))
142+
{
143+
messaget log{message_handler};
144+
log.error() << "linking failed" << messaget::eom;
145+
return {};
146+
}
147+
148+
return linking.object_type_updates.get_expr_map();
149+
}
150+
151+
void finalize_linking(
152+
goto_modelt &dest,
153+
const replace_symbolt::expr_mapt &type_updates)
154+
{
155+
unchecked_replace_symbolt object_type_updates;
156+
object_type_updates.get_expr_map().insert(
157+
type_updates.begin(), type_updates.end());
158+
159+
goto_functionst &dest_functions = dest.goto_functions;
160+
symbol_tablet &dest_symbol_table = dest.symbol_table;
161+
112162
// apply macros
113163
rename_symbolt macro_application;
114164

@@ -157,40 +207,4 @@ static bool link_functions(
157207
}
158208
}
159209
}
160-
161-
return false;
162-
}
163-
164-
void link_goto_model(
165-
goto_modelt &dest,
166-
goto_modelt &src,
167-
message_handlert &message_handler)
168-
{
169-
std::unordered_set<irep_idt> weak_symbols;
170-
171-
for(const auto &symbol_pair : dest.symbol_table.symbols)
172-
{
173-
if(symbol_pair.second.is_weak)
174-
weak_symbols.insert(symbol_pair.first);
175-
}
176-
177-
linkingt linking(dest.symbol_table,
178-
src.symbol_table,
179-
message_handler);
180-
181-
if(linking.typecheck_main())
182-
{
183-
throw invalid_source_file_exceptiont("typechecking main failed");
184-
}
185-
if(link_functions(
186-
dest.symbol_table,
187-
dest.goto_functions,
188-
src.symbol_table,
189-
src.goto_functions,
190-
linking.rename_symbol,
191-
weak_symbols,
192-
linking.object_type_updates))
193-
{
194-
throw invalid_source_file_exceptiont("linking failed");
195-
}
196210
}

src/goto-programs/link_goto_model.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,24 @@ Author: Daniel Kroening, [email protected]
1212
#ifndef CPROVER_GOTO_PROGRAMS_LINK_GOTO_MODEL_H
1313
#define CPROVER_GOTO_PROGRAMS_LINK_GOTO_MODEL_H
1414

15+
#include <util/nodiscard.h>
16+
#include <util/replace_symbol.h>
17+
1518
class goto_modelt;
1619
class message_handlert;
1720

18-
void link_goto_model(
21+
/// Link goto model \p src into goto model \p dest, invalidating \p src in this
22+
/// process. Linking may require updates to object types contained in \p dest,
23+
/// which need to be applied using \ref finalize_linking.
24+
/// \return nullopt if linking fails, else a (possibly empty) collection of
25+
/// replacements to be applied.
26+
NODISCARD optionalt<replace_symbolt::expr_mapt>
27+
link_goto_model(goto_modelt &dest, goto_modelt &&src, message_handlert &);
28+
29+
/// Apply \p type_updates to \p dest, where \p type_updates were constructed
30+
/// from one or more calls to \p link_goto_model.
31+
void finalize_linking(
1932
goto_modelt &dest,
20-
goto_modelt &src,
21-
message_handlert &);
33+
const replace_symbolt::expr_mapt &type_updates);
2234

2335
#endif // CPROVER_GOTO_PROGRAMS_LINK_GOTO_MODEL_H

src/goto-programs/read_goto_binary.cpp

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Module: Read Goto Programs
1515

1616
#include <util/config.h>
1717
#include <util/message.h>
18+
#include <util/replace_symbol.h>
1819
#include <util/tempfile.h>
1920

2021
#ifdef _MSC_VER
@@ -270,8 +271,8 @@ bool is_goto_binary(
270271
/// \param file_name: file name of the goto binary
271272
/// \param dest: the goto model returned
272273
/// \param message_handler: for diagnostics
273-
/// \return true on error, false otherwise
274-
static bool read_object_and_link(
274+
/// \return nullopt on error, type replacements to be applied otherwise
275+
static optionalt<replace_symbolt::expr_mapt> read_object_and_link(
275276
const std::string &file_name,
276277
goto_modelt &dest,
277278
message_handlert &message_handler)
@@ -282,18 +283,9 @@ static bool read_object_and_link(
282283
// we read into a temporary model
283284
auto temp_model = read_goto_binary(file_name, message_handler);
284285
if(!temp_model.has_value())
285-
return true;
286-
287-
try
288-
{
289-
link_goto_model(dest, *temp_model, message_handler);
290-
}
291-
catch(...)
292-
{
293-
return true;
294-
}
286+
return {};
295287

296-
return false;
288+
return link_goto_model(dest, std::move(*temp_model), message_handler);
297289
}
298290

299291
bool read_objects_and_link(
@@ -304,14 +296,19 @@ bool read_objects_and_link(
304296
if(file_names.empty())
305297
return false;
306298

299+
replace_symbolt::expr_mapt object_type_updates;
300+
307301
for(const auto &file_name : file_names)
308302
{
309-
const bool failed = read_object_and_link(file_name, dest, message_handler);
310-
311-
if(failed)
303+
auto updates_opt = read_object_and_link(file_name, dest, message_handler);
304+
if(!updates_opt.has_value())
312305
return true;
306+
307+
object_type_updates.insert(updates_opt->begin(), updates_opt->end());
313308
}
314309

310+
finalize_linking(dest, object_type_updates);
311+
315312
// reading successful, let's update config
316313
config.set_from_symbol_table(dest.symbol_table);
317314

0 commit comments

Comments
 (0)