Skip to content

Commit 44fd5e8

Browse files
committed
Remove dynamic_cast from hardness collection code paths
Use a `shared_ptr` to retain co-ownership of the hardness collector in `solver_factoryt::solvert` and adjust the `symex_target_equationt` API to `consume a solver_hardnesst`.
1 parent 7553763 commit 44fd5e8

14 files changed

+205
-121
lines changed

src/goto-checker/bmc_util.cpp

+7-3
Original file line numberDiff line numberDiff line change
@@ -147,15 +147,16 @@ void output_graphml(
147147
}
148148
}
149149

150-
void convert_symex_target_equation(
150+
static void convert_symex_target_equation(
151151
symex_target_equationt &equation,
152152
decision_proceduret &decision_procedure,
153+
solver_hardnesst *hardness_collector,
153154
message_handlert &message_handler)
154155
{
155156
messaget msg(message_handler);
156157
msg.status() << "converting SSA" << messaget::eom;
157158

158-
equation.convert(decision_procedure);
159+
equation.convert(decision_procedure, hardness_collector);
159160
}
160161

161162
std::unique_ptr<memory_model_baset>
@@ -370,7 +371,10 @@ std::chrono::duration<double> prepare_property_decider(
370371
<< messaget::eom;
371372

372373
convert_symex_target_equation(
373-
equation, property_decider.get_decision_procedure(), ui_message_handler);
374+
equation,
375+
property_decider.get_decision_procedure(),
376+
property_decider.get_hardness_collector(),
377+
ui_message_handler);
374378
property_decider.update_properties_goals_from_symex_target_equation(
375379
properties);
376380
property_decider.convert_goals();

src/goto-checker/bmc_util.h

-6
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,13 @@ class decision_proceduret;
2525
class goto_symex_property_decidert;
2626
class goto_tracet;
2727
class memory_model_baset;
28-
class message_handlert;
2928
class namespacet;
3029
class optionst;
3130
class symex_bmct;
3231
class symex_target_equationt;
3332
struct trace_optionst;
3433
class ui_message_handlert;
3534

36-
void convert_symex_target_equation(
37-
symex_target_equationt &equation,
38-
decision_proceduret &decision_procedure,
39-
message_handlert &message_handler);
40-
4135
/// Returns a function that checks whether an SSA step is an assertion
4236
/// with \p property_id. Usually used for `build_goto_trace`.
4337
ssa_step_predicatet

src/goto-checker/goto_symex_property_decider.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,14 @@ void goto_symex_property_decidert::add_constraint_from_goals(
100100
exprt goal_disjunction = disjunction(disjuncts);
101101
decision_procedure.set_to_true(goal_disjunction);
102102

103-
with_solver_hardness(decision_procedure, [](solver_hardnesst &hardness) {
103+
if(auto hardness = solver->hardness_collector())
104+
{
104105
// SSA expr and involved steps have already been collected
105106
// in symex_target_equationt::convert_assertions
106107
exprt ssa_expr_unused;
107108
std::vector<goto_programt::const_targett> involved_steps_unused;
108-
hardness.register_assertion_ssas(ssa_expr_unused, involved_steps_unused);
109-
});
109+
hardness->register_assertion_ssas(ssa_expr_unused, involved_steps_unused);
110+
};
110111
}
111112

112113
decision_proceduret::resultt goto_symex_property_decidert::solve()
@@ -125,6 +126,11 @@ boolbvt &goto_symex_property_decidert::get_boolbv_decision_procedure() const
125126
return solver->boolbv_decision_procedure();
126127
}
127128

129+
solver_hardnesst *goto_symex_property_decidert::get_hardness_collector() const
130+
{
131+
return solver->hardness_collector();
132+
}
133+
128134
symex_target_equationt &goto_symex_property_decidert::get_equation() const
129135
{
130136
return equation;

src/goto-checker/goto_symex_property_decider.h

+4
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ class goto_symex_property_decidert
5050
/// Returns the solver instance
5151
boolbvt &get_boolbv_decision_procedure() const;
5252

53+
/// Returns a pointer to the hardness collector or `nullptr` when hardness
54+
/// collection is not set up.
55+
solver_hardnesst *get_hardness_collector() const;
56+
5357
/// Return the equation associated with this instance
5458
symex_target_equationt &get_equation() const;
5559

src/goto-checker/multi_path_symex_checker.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,9 @@ void multi_path_symex_checkert::report()
169169
{
170170
if(options.is_set("write-solver-stats-to"))
171171
{
172-
with_solver_hardness(
173-
property_decider.get_decision_procedure(),
174-
[](solver_hardnesst &hardness) { hardness.produce_report(); });
172+
if(auto hardness = property_decider.get_hardness_collector())
173+
{
174+
hardness->produce_report();
175+
}
175176
}
176177
}

src/goto-checker/single_loop_incremental_symex_checker.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,18 @@ operator()(propertiest &properties)
108108

109109
log.status() << "converting SSA" << messaget::eom;
110110
equation.convert_without_assertions(
111-
property_decider.get_decision_procedure());
111+
property_decider.get_decision_procedure(),
112+
property_decider.get_hardness_collector());
112113

113114
property_decider.update_properties_goals_from_symex_target_equation(
114115
properties);
115116

116117
// We convert the assertions in a new context.
117118
property_decider.get_decision_procedure().push();
118119
equation.convert_assertions(
119-
property_decider.get_decision_procedure(), false);
120+
property_decider.get_decision_procedure(),
121+
property_decider.get_hardness_collector(),
122+
false);
120123
property_decider.convert_goals();
121124

122125
current_equation_converted = true;

src/goto-checker/solver_factory.cpp

+51-24
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ Author: Daniel Kroening, Peter Schrammel
1919
#include <util/unicode.h>
2020
#include <util/version.h>
2121

22-
#include <goto-symex/solver_hardness.h>
2322
#include <solvers/flattening/bv_dimacs.h>
2423
#include <solvers/prop/prop.h>
2524
#include <solvers/prop/solver_resource_limits.h>
@@ -71,6 +70,16 @@ solver_factoryt::solvert::solvert(
7170
{
7271
}
7372

73+
solver_factoryt::solvert::solvert(
74+
std::unique_ptr<boolbvt> p1,
75+
std::unique_ptr<propt> p2,
76+
std::shared_ptr<solver_hardnesst> p3)
77+
: hardness_ptr(std::move(p3)),
78+
prop_ptr(std::move(p2)),
79+
decision_procedure_is_boolbvt_ptr(std::move(p1))
80+
{
81+
}
82+
7483
stack_decision_proceduret &solver_factoryt::solvert::decision_procedure() const
7584
{
7685
PRECONDITION(
@@ -88,6 +97,11 @@ boolbvt &solver_factoryt::solvert::boolbv_decision_procedure() const
8897
return *decision_procedure_is_boolbvt_ptr;
8998
}
9099

100+
solver_hardnesst *solver_factoryt::solvert::hardness_collector() const
101+
{
102+
return hardness_ptr.get();
103+
}
104+
91105
void solver_factoryt::set_decision_procedure_time_limit(
92106
solver_resource_limitst &decision_procedure)
93107
{
@@ -168,8 +182,9 @@ static void emit_solver_warning(
168182
template <typename SatcheckT>
169183
static typename std::enable_if<
170184
!std::is_base_of<hardness_collectort, SatcheckT>::value,
171-
std::unique_ptr<SatcheckT>>::type
172-
make_satcheck_prop(message_handlert &message_handler, const optionst &options)
185+
std::pair<std::unique_ptr<SatcheckT>, std::shared_ptr<solver_hardnesst>>>::
186+
type
187+
make_satcheck_prop(message_handlert &message_handler, const optionst &options)
173188
{
174189
auto satcheck = std::make_unique<SatcheckT>(message_handler);
175190
if(options.is_set("write-solver-stats-to"))
@@ -179,27 +194,29 @@ make_satcheck_prop(message_handlert &message_handler, const optionst &options)
179194
<< "Configured solver does not support --write-solver-stats-to. "
180195
<< "Solver stats will not be written." << messaget::eom;
181196
}
182-
return satcheck;
197+
return {std::move(satcheck), nullptr};
183198
}
184199

185200
template <typename SatcheckT>
186201
static typename std::enable_if<
187202
std::is_base_of<hardness_collectort, SatcheckT>::value,
188-
std::unique_ptr<SatcheckT>>::type
189-
make_satcheck_prop(message_handlert &message_handler, const optionst &options)
203+
std::pair<std::unique_ptr<SatcheckT>, std::shared_ptr<solver_hardnesst>>>::
204+
type
205+
make_satcheck_prop(message_handlert &message_handler, const optionst &options)
190206
{
191207
auto satcheck = std::make_unique<SatcheckT>(message_handler);
192-
if(options.is_set("write-solver-stats-to"))
193-
{
194-
std::unique_ptr<solver_hardnesst> solver_hardness =
195-
std::make_unique<solver_hardnesst>();
196-
solver_hardness->set_outfile(options.get_option("write-solver-stats-to"));
197-
satcheck->solver_hardness = std::move(solver_hardness);
198-
}
199-
return satcheck;
208+
if(!options.is_set("write-solver-stats-to"))
209+
return {std::move(satcheck), nullptr};
210+
211+
std::shared_ptr<solver_hardnesst> solver_hardness =
212+
std::make_shared<solver_hardnesst>();
213+
solver_hardness->set_outfile(options.get_option("write-solver-stats-to"));
214+
satcheck->solver_hardness = solver_hardness;
215+
216+
return {std::move(satcheck), std::move(solver_hardness)};
200217
}
201218

202-
static std::unique_ptr<propt>
219+
static std::pair<std::unique_ptr<propt>, std::shared_ptr<solver_hardnesst>>
203220
get_sat_solver(message_handlert &message_handler, const optionst &options)
204221
{
205222
const bool no_simplifier = options.get_bool_option("beautify") ||
@@ -326,12 +343,15 @@ get_sat_solver(message_handlert &message_handler, const optionst &options)
326343

327344
std::unique_ptr<solver_factoryt::solvert> solver_factoryt::get_default()
328345
{
329-
auto sat_solver = get_sat_solver(message_handler, options);
346+
auto sat_solver_and_hardness_opt = get_sat_solver(message_handler, options);
330347

331348
bool get_array_constraints =
332349
options.get_bool_option("show-array-constraints");
333350
auto bv_pointers = std::make_unique<bv_pointerst>(
334-
ns, *sat_solver, message_handler, get_array_constraints);
351+
ns,
352+
*sat_solver_and_hardness_opt.first,
353+
message_handler,
354+
get_array_constraints);
335355

336356
if(options.get_option("arrays-uf") == "never")
337357
bv_pointers->unbounded_array = bv_pointerst::unbounded_arrayt::U_NONE;
@@ -341,7 +361,10 @@ std::unique_ptr<solver_factoryt::solvert> solver_factoryt::get_default()
341361
set_decision_procedure_time_limit(*bv_pointers);
342362

343363
std::unique_ptr<boolbvt> boolbv = std::move(bv_pointers);
344-
return std::make_unique<solvert>(std::move(boolbv), std::move(sat_solver));
364+
return std::make_unique<solvert>(
365+
std::move(boolbv),
366+
std::move(sat_solver_and_hardness_opt.first),
367+
std::move(sat_solver_and_hardness_opt.second));
345368
}
346369

347370
std::unique_ptr<solver_factoryt::solvert> solver_factoryt::get_dimacs()
@@ -376,11 +399,11 @@ std::unique_ptr<solver_factoryt::solvert> solver_factoryt::get_external_sat()
376399

377400
std::unique_ptr<solver_factoryt::solvert> solver_factoryt::get_bv_refinement()
378401
{
379-
std::unique_ptr<propt> prop = get_sat_solver(message_handler, options);
402+
auto prop_and_hardness_opt = get_sat_solver(message_handler, options);
380403

381404
bv_refinementt::infot info;
382405
info.ns = &ns;
383-
info.prop = prop.get();
406+
info.prop = prop_and_hardness_opt.first.get();
384407
info.output_xml = output_xml_in_refinement;
385408

386409
// we allow setting some parameters
@@ -396,7 +419,9 @@ std::unique_ptr<solver_factoryt::solvert> solver_factoryt::get_bv_refinement()
396419
std::make_unique<bv_refinementt>(info);
397420
set_decision_procedure_time_limit(*decision_procedure);
398421
return std::make_unique<solvert>(
399-
std::move(decision_procedure), std::move(prop));
422+
std::move(decision_procedure),
423+
std::move(prop_and_hardness_opt.first),
424+
std::move(prop_and_hardness_opt.second));
400425
}
401426

402427
/// the string refinement adds to the bit vector refinement specifications for
@@ -407,8 +432,8 @@ solver_factoryt::get_string_refinement()
407432
{
408433
string_refinementt::infot info;
409434
info.ns = &ns;
410-
auto prop = get_sat_solver(message_handler, options);
411-
info.prop = prop.get();
435+
auto prop_and_hardness_opt = get_sat_solver(message_handler, options);
436+
info.prop = prop_and_hardness_opt.first.get();
412437
info.refinement_bound = DEFAULT_MAX_NB_REFINEMENT;
413438
info.output_xml = output_xml_in_refinement;
414439
if(options.get_bool_option("max-node-refinement"))
@@ -422,7 +447,9 @@ solver_factoryt::get_string_refinement()
422447
std::make_unique<string_refinementt>(info);
423448
set_decision_procedure_time_limit(*decision_procedure);
424449
return std::make_unique<solvert>(
425-
std::move(decision_procedure), std::move(prop));
450+
std::move(decision_procedure),
451+
std::move(prop_and_hardness_opt.first),
452+
std::move(prop_and_hardness_opt.second));
426453
}
427454

428455
std::unique_ptr<std::ofstream> open_outfile_and_check(

src/goto-checker/solver_factory.h

+7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Author: Daniel Kroening, Peter Schrammel
1212
#ifndef CPROVER_GOTO_CHECKER_SOLVER_FACTORY_H
1313
#define CPROVER_GOTO_CHECKER_SOLVER_FACTORY_H
1414

15+
#include <goto-symex/solver_hardness.h> // IWYU pragma: keep
1516
#include <solvers/flattening/boolbv.h>
1617
#include <solvers/smt2/smt2_dec.h>
1718

@@ -46,11 +47,17 @@ class solver_factoryt final
4647
std::unique_ptr<stack_decision_proceduret> p1,
4748
std::unique_ptr<std::ofstream> p2);
4849
solvert(std::unique_ptr<boolbvt> p1, std::unique_ptr<propt> p2);
50+
solvert(
51+
std::unique_ptr<boolbvt> p1,
52+
std::unique_ptr<propt> p2,
53+
std::shared_ptr<solver_hardnesst> p3);
4954

5055
stack_decision_proceduret &decision_procedure() const;
5156
boolbvt &boolbv_decision_procedure() const;
57+
solver_hardnesst *hardness_collector() const;
5258

5359
private:
60+
std::shared_ptr<solver_hardnesst> hardness_ptr;
5461
// the objects are deleted in the opposite order they appear below
5562
std::unique_ptr<std::ofstream> ofstream_ptr;
5663
std::unique_ptr<propt> prop_ptr;

src/goto-instrument/accelerate/scratch_program.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ bool scratch_programt::check_sat(bool do_slice, guard_managert &guard_manager)
6363
return false;
6464
}
6565

66-
equation.convert(*checker);
66+
equation.convert(*checker, nullptr);
6767

6868
#ifdef DEBUG
6969
std::cout << "Finished symex, invoking decision procedure.\n";

src/goto-symex/solver_hardness.h

+2-25
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,15 @@ Author: Diffblue Ltd.
99
#ifndef CPROVER_SOLVERS_SOLVER_HARDNESS_H
1010
#define CPROVER_SOLVERS_SOLVER_HARDNESS_H
1111

12+
#include <goto-programs/goto_program.h>
13+
1214
#include <solvers/hardness_collector.h>
13-
#include <solvers/prop/prop_conv_solver.h>
1415

1516
#include <string>
1617
#include <unordered_map>
1718
#include <unordered_set>
1819
#include <vector>
1920

20-
#include <goto-programs/goto_program.h>
21-
2221
/// A structure that facilitates collecting the complexity statistics from a
2322
/// decision procedure. The idea is to associate some solver complexity metric
2423
/// with each line-of-code, GOTO instruction, and SSA step. The motivation is to
@@ -158,26 +157,4 @@ struct hash<solver_hardnesst::hardness_ssa_keyt>
158157
};
159158
} // namespace std
160159

161-
static inline void with_solver_hardness(
162-
decision_proceduret &maybe_hardness_collector,
163-
std::function<void(solver_hardnesst &hardness)> handler)
164-
{
165-
// FIXME I am wondering if there is a way to do this that is a bit less
166-
// dynamically typed.
167-
if(
168-
auto prop_conv_solver =
169-
dynamic_cast<prop_conv_solvert *>(&maybe_hardness_collector))
170-
{
171-
if(auto hardness_collector = prop_conv_solver->get_hardness_collector())
172-
{
173-
if(hardness_collector->solver_hardness)
174-
{
175-
auto &solver_hardness = static_cast<solver_hardnesst &>(
176-
*(hardness_collector->solver_hardness));
177-
handler(solver_hardness);
178-
}
179-
}
180-
}
181-
}
182-
183160
#endif // CPROVER_SOLVERS_SOLVER_HARDNESS_H

0 commit comments

Comments
 (0)