@@ -225,9 +225,10 @@ class constants_evaluator
225
225
public:
226
226
constants_evaluator (
227
227
const exprt &e,
228
+ const std::vector<abstract_object_pointert> &ops,
228
229
const abstract_environmentt &env,
229
230
const namespacet &n)
230
- : expression(e), environment(env), ns(n)
231
+ : expression(e), operands(ops), environment(env), ns(n)
231
232
{
232
233
}
233
234
@@ -244,28 +245,26 @@ class constants_evaluator
244
245
private:
245
246
abstract_object_pointert transform () const
246
247
{
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 ();
250
249
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)
254
252
{
255
- auto lhs_value = eval_constant (op );
253
+ auto lhs_value = operands[i]-> to_constant ( );
256
254
257
255
// do not give up if a sub-expression is not a constant,
258
256
// 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 ;
260
262
}
261
263
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 ());
269
268
270
269
// the expression is fully simplified
271
270
return std::make_shared<constant_abstract_valuet>(
@@ -274,22 +273,31 @@ class constants_evaluator
274
273
275
274
abstract_object_pointert try_transform_expr_with_all_rounding_modes () const
276
275
{
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
+
278
286
for (auto rounding_mode : all_rounding_modes)
279
287
{
280
288
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);
284
291
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))
290
296
return top (expression.type ());
297
+ last_result = result;
291
298
}
292
- return possible_results.front ();
299
+
300
+ return last_result;
293
301
}
294
302
295
303
abstract_environmentt
@@ -311,12 +319,25 @@ class constants_evaluator
311
319
{
312
320
exprt adjusted_expr = expression;
313
321
adjust_float_expressions (adjusted_expr, ns);
322
+
323
+ if (adjusted_expr != expression)
324
+ operands = reeval_operands (adjusted_expr.operands (), environment, ns);
325
+
314
326
return adjusted_expr;
315
327
}
316
328
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)
318
333
{
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;
320
341
}
321
342
322
343
abstract_object_pointert top (const typet &type) const
@@ -326,11 +347,13 @@ class constants_evaluator
326
347
327
348
bool rounding_mode_is_not_set () const
328
349
{
329
- auto rounding_mode = eval_constant (rounding_mode_symbol);
350
+ auto rounding_mode =
351
+ environment.eval (rounding_mode_symbol, ns)->to_constant ();
330
352
return rounding_mode.is_nil ();
331
353
}
332
354
333
355
const exprt &expression;
356
+ mutable std::vector<abstract_object_pointert> operands;
334
357
const abstract_environmentt &environment;
335
358
const namespacet &ns;
336
359
@@ -355,7 +378,7 @@ abstract_object_pointert constants_expression_transform(
355
378
const abstract_environmentt &environment,
356
379
const namespacet &ns)
357
380
{
358
- auto evaluator = constants_evaluator (expr, environment, ns);
381
+ auto evaluator = constants_evaluator (expr, operands, environment, ns);
359
382
return evaluator ();
360
383
}
361
384
0 commit comments