@@ -225,9 +225,10 @@ class constants_evaluator
225225public:
226226 constants_evaluator (
227227 const exprt &e,
228+ const std::vector<abstract_object_pointert> &ops,
228229 const abstract_environmentt &env,
229230 const namespacet &n)
230- : expression(e), environment(env), ns(n)
231+ : expression(e), operands(ops), environment(env), ns(n)
231232 {
232233 }
233234
@@ -244,28 +245,26 @@ class constants_evaluator
244245private:
245246 abstract_object_pointert transform () const
246247 {
247- exprt expr = adjust_expression_for_rounding_mode ();
248- auto operands = expr.operands ();
249- expr.operands ().clear ();
248+ auto expr = adjust_expression_for_rounding_mode ();
250249
251- // Two passes over the expression - one for simplification,
252- // another to check if there are any top subexpressions left
253- for (const exprt &op : operands)
250+ auto operand_is_top = false ;
251+ for (size_t i = 0 ; i != operands.size (); ++i)
254252 {
255- auto lhs_value = eval_constant (op );
253+ auto lhs_value = operands[i]-> to_constant ( );
256254
257255 // do not give up if a sub-expression is not a constant,
258256 // because the whole expression may still be simplified in some cases
259- expr.operands ().push_back (lhs_value.is_nil () ? op : lhs_value);
257+ // (eg multiplication by zero)
258+ if (lhs_value.is_not_nil ())
259+ expr.operands ()[i] = lhs_value;
260+ else
261+ operand_is_top = true ;
260262 }
261263
262- exprt simplified = simplify_expr (expr, ns);
263- for (const exprt &op : simplified.operands ())
264- {
265- auto lhs_value = eval_constant (op);
266- if (lhs_value.is_nil ())
267- return top (simplified.type ());
268- }
264+ auto simplified = simplify_expr (expr, ns);
265+
266+ if (simplified.has_operands () && operand_is_top)
267+ return top (simplified.type ());
269268
270269 // the expression is fully simplified
271270 return std::make_shared<constant_abstract_valuet>(
@@ -274,22 +273,31 @@ class constants_evaluator
274273
275274 abstract_object_pointert try_transform_expr_with_all_rounding_modes () const
276275 {
277- std::vector<abstract_object_pointert> possible_results;
276+ abstract_object_pointert last_result;
277+
278+ auto results_differ = [](
279+ const abstract_object_pointert &prev,
280+ const abstract_object_pointert &cur) {
281+ if (prev == nullptr )
282+ return false ;
283+ return prev->to_constant () != cur->to_constant ();
284+ };
285+
278286 for (auto rounding_mode : all_rounding_modes)
279287 {
280288 auto child_env (environment_with_rounding_mode (rounding_mode));
281- possible_results.push_back (
282- constants_evaluator (expression, child_env, ns)());
283- }
289+ auto child_operands =
290+ reeval_operands (expression.operands (), child_env, ns);
284291
285- auto first = possible_results.front ()->to_constant ();
286- for (auto const &possible_result : possible_results)
287- {
288- auto current = possible_result->to_constant ();
289- if (current.is_nil () || current != first)
292+ auto result =
293+ constants_evaluator (expression, child_operands, child_env, ns)();
294+
295+ if (result->is_top () || results_differ (last_result, result))
290296 return top (expression.type ());
297+ last_result = result;
291298 }
292- return possible_results.front ();
299+
300+ return last_result;
293301 }
294302
295303 abstract_environmentt
@@ -311,12 +319,25 @@ class constants_evaluator
311319 {
312320 exprt adjusted_expr = expression;
313321 adjust_float_expressions (adjusted_expr, ns);
322+
323+ if (adjusted_expr != expression)
324+ operands = reeval_operands (adjusted_expr.operands (), environment, ns);
325+
314326 return adjusted_expr;
315327 }
316328
317- exprt eval_constant (const exprt &op) const
329+ static std::vector<abstract_object_pointert> reeval_operands (
330+ const exprt::operandst &ops,
331+ const abstract_environmentt &env,
332+ const namespacet &ns)
318333 {
319- return environment.eval (op, ns)->to_constant ();
334+ auto reevaled_operands = std::vector<abstract_object_pointert>{};
335+ std::transform (
336+ ops.cbegin (),
337+ ops.end (),
338+ std::back_inserter (reevaled_operands),
339+ [&env, &ns](const exprt &op) { return env.eval (op, ns); });
340+ return reevaled_operands;
320341 }
321342
322343 abstract_object_pointert top (const typet &type) const
@@ -326,11 +347,13 @@ class constants_evaluator
326347
327348 bool rounding_mode_is_not_set () const
328349 {
329- auto rounding_mode = eval_constant (rounding_mode_symbol);
350+ auto rounding_mode =
351+ environment.eval (rounding_mode_symbol, ns)->to_constant ();
330352 return rounding_mode.is_nil ();
331353 }
332354
333355 const exprt &expression;
356+ mutable std::vector<abstract_object_pointert> operands;
334357 const abstract_environmentt &environment;
335358 const namespacet &ns;
336359
@@ -355,7 +378,7 @@ abstract_object_pointert constants_expression_transform(
355378 const abstract_environmentt &environment,
356379 const namespacet &ns)
357380{
358- auto evaluator = constants_evaluator (expr, environment, ns);
381+ auto evaluator = constants_evaluator (expr, operands, environment, ns);
359382 return evaluator ();
360383}
361384
0 commit comments