ESBMC
Efficient SMT-based Context-Bounded Model Checker
Loading...
Searching...
No Matches
irep2_dispatch.h
Go to the documentation of this file.
1#pragma once
2// Generic switch-dispatch helpers for irep2's flat node layout, plus
3// the per-field operations they invoke.
4//
5// Include AFTER irep2_expr.h: this depends on the full definitions of
6// every concrete kind. Do NOT pull this into irep2.h or irep2_expr.h.
7//
8// Each concrete kind exposes a `static constexpr auto fields` tuple of
9// member pointers covering its user-visible fields, plus a static
10// `field_names` array naming them in tuple order. The generic_*<K>
11// helpers below walk that tuple via std::apply to implement cmp/lt/
12// tostring/get_sub_expr/foreach_operand uniformly (crc and clone are built
13// on the same `fields` tuple in irep2_crc.cpp and irep2_expr.cpp /
14// irep2_type.cpp). The
15// switch-on-id dispatchers on expr2t / type2t pick the right helper
16// per kind from the X-macro manifests (`expr_kinds.inc`,
17// `type_kinds.inc`).
18
19#include <cassert>
20#include <tuple>
21#include <type_traits>
22#include <util/arith/fixedbv.h>
23#include <util/base/i2string.h>
25#include <util/irep/migrate.h>
26#include <irep2/irep2_type.h>
27#include <irep2/irep2_expr.h>
28#include <irep2/irep2_utils.h>
29
30// ============================================================================
31// Per-field operations the generic dispatchers invoke on every K::fields
32// entry: pretty-printing, structural cmp/lt, crc/hash ingestion, and
33// sub-expression / delegate iteration. Primary templates cover trivially
34// comparable field types; explicit overloads handle BigInt,
35// std::vector<...>, and null-safe expr2tc/type2tc dispatch.
36// ============================================================================
37
38std::string type_to_string(const bool &thebool, int);
39std::string type_to_string(const sideeffect_allockind &data, int);
40std::string type_to_string(const unsigned int &theval, int);
41std::string type_to_string(const constant_string_kindt &theval, int);
42std::string type_to_string(const pointer_ref_kindt &theval, int);
43std::string type_to_string(const printf_kindt &theval, int);
44std::string type_to_string(const symbol_renaming_level &theval, int);
45std::string type_to_string(const BigInt &theint, int);
46std::string type_to_string(const fixedbvt &theval, int);
47std::string type_to_string(const ieee_floatt &theval, int);
48std::string type_to_string(const std::vector<expr2tc> &theval, int indent);
49std::string type_to_string(const std::vector<type2tc> &theval, int indent);
50std::string type_to_string(const std::vector<irep_idt> &theval, int indent);
51std::string type_to_string(const expr2tc &theval, int indent);
52std::string type_to_string(const type2tc &theval, int indent);
53std::string type_to_string(const irep_idt &theval, int);
54
55// Structural equality on operator==.
56template <class T>
57inline bool do_type_cmp(const T &side1, const T &side2)
58{
59 return side1 == side2;
60}
61
62// Trinary -1/0/1 ordering on operator<.
63template <class T>
64inline int do_type_lt(const T &side1, const T &side2)
65{
66 if (side1 < side2)
67 return -1;
68 if (side2 < side1)
69 return 1;
70 return 0;
71}
72
73// Explicit overloads for the field types whose semantics differ.
74
75// ieee_floatt's own == and < compare IEEE values, under which -0.0 equals +0.0.
76// irep2 needs literal identity: the packed bits, which do_type_crc() hashes.
77inline bool do_type_cmp(const ieee_floatt &side1, const ieee_floatt &side2)
78{
79 // generic_cmp/generic_lt compare the type, which is derived from spec, first.
80 assert(side1.spec == side2.spec);
81 return side1.pack() == side2.pack();
82}
83
84inline int do_type_lt(const ieee_floatt &side1, const ieee_floatt &side2)
85{
86 assert(side1.spec == side2.spec);
87 return side1.pack().compare(side2.pack());
88}
89
90int do_type_lt(const BigInt &side1, const BigInt &side2);
91int do_type_lt(
92 const std::vector<expr2tc> &side1,
93 const std::vector<expr2tc> &side2);
94int do_type_lt(
95 const std::vector<type2tc> &side1,
96 const std::vector<type2tc> &side2);
97int do_type_lt(const expr2tc &side1, const expr2tc &side2);
98int do_type_lt(const type2tc &side1, const type2tc &side2);
99
100template <typename T>
102 const T &thething,
103 unsigned int idx,
104 std::string (&names)[esbmct::num_type_fields],
105 list_of_memberst &vec,
106 unsigned int indent)
107{
108 vec.push_back(member_entryt(names[idx], type_to_string(thething, indent)));
109}
110
111template <class T>
112bool do_get_sub_expr(const T &, size_t, size_t &, const expr2tc *&)
113{
114 return false;
115}
116
117template <>
119 const expr2tc &item,
120 size_t idx,
121 size_t &it,
122 const expr2tc *&ptr);
123
124template <>
126 const std::vector<expr2tc> &item,
127 size_t idx,
128 size_t &it,
129 const expr2tc *&ptr);
130
131template <class T>
133{
134 return 0;
135}
136
137template <>
139
140template <>
142 const std::vector<expr2tc> &item);
143
144// Field-dispatch for expr2t::foreach_operand. Primary template is a no-op;
145// the specialisations below match expr2tc and std::vector<expr2tc> fields.
146template <typename T, typename U>
148{
149}
150
151template <>
153 const expr2tc &ref,
155
156template <>
158 expr2tc &ref,
160
161template <>
163 const std::vector<expr2tc> &ref,
165
166template <>
168 std::vector<expr2tc> &ref,
170
171// Same shape as call_expr_delegate, but for type2t::foreach_subtype.
172template <typename T, typename U>
174{
175}
176
177template <>
179 const type2tc &ref,
181
182template <>
184 type2tc &ref,
186
187template <>
189 const std::vector<type2tc>,
191 const std::vector<type2tc> &ref,
193
194template <>
196 std::vector<type2tc> &ref,
198
199// ============================================================================
200// generic_*<K>: switch-dispatch helpers that walk K::fields.
201// ============================================================================
202
203namespace esbmct
204{
205// --------------------------------------------------------------------------
206// generic_cmp: structural equality over K::fields.
207// Precondition: a.expr_id == o.expr_id (checked at the switch boundary).
208//
209// Also acts as the canonical instantiation site for the per-kind
210// `assert_kind_invariants<K>()` static_assert chain: every expr dispatcher
211// case lands here, so adding a new kind without a valid `fields` tuple
212// fails to compile at the dispatcher, not silently at cmp/crc/hash time.
213// --------------------------------------------------------------------------
214template <class K>
215bool generic_cmp(const K &a, const expr2t &o)
216{
217 static_assert(assert_kind_invariants<K>());
218 const K &b = static_cast<const K &>(o);
219 bool eq = true;
220 std::apply(
221 [&](auto... mp) { ((eq = eq && do_type_cmp(a.*mp, b.*mp)), ...); },
222 K::fields);
223 return eq;
224}
225
226// --------------------------------------------------------------------------
227// generic_lt: trinary ordering over K::fields.
228// Precondition: a.expr_id == o.expr_id.
229// --------------------------------------------------------------------------
230template <class K>
231int generic_lt(const K &a, const expr2t &o)
232{
233 const K &b = static_cast<const K &>(o);
234 int r = 0;
235 std::apply(
236 [&](auto... mp) {
237 ((r == 0 ? (void)(r = do_type_lt(a.*mp, b.*mp)) : (void)0), ...);
238 },
239 K::fields);
240 return r;
241}
242
243// --------------------------------------------------------------------------
244// generic_tostring: build the pretty-print member list from K::fields.
245// K::field_names[i] names the i-th user field (0-based). When K is an expr
246// kind, any type2tc slot in K::fields is skipped — the type is shown by
247// the pretty-print banner above the member list, not as a named field.
248// --------------------------------------------------------------------------
249template <class K>
250list_of_memberst generic_tostring(const K &a, unsigned int indent)
251{
253 unsigned int idx = 0;
254 std::apply(
255 [&](auto... mp) {
256 (..., ([&]() {
257 using FieldT = std::remove_cvref_t<decltype(a.*mp)>;
258 if constexpr (
259 std::is_same_v<FieldT, type2tc> && std::is_base_of_v<expr2t, K>)
260 (void)indent; // skip — shown by the type banner
261 else
262 do_type2string(a.*mp, idx++, K::field_names, vec, indent);
263 }()));
264 },
265 K::fields);
266 return vec;
267}
268
269// --------------------------------------------------------------------------
270// generic_get_sub_expr: return pointer to the idx-th expr2tc child.
271// --------------------------------------------------------------------------
272template <class K>
273const expr2tc *generic_get_sub_expr(const K &a, size_t idx)
274{
275 const expr2tc *result = nullptr;
276 size_t cur = 0;
277 std::apply(
278 [&](auto... mp) {
279 (void)(... || do_get_sub_expr(a.*mp, idx, cur, result));
280 },
281 K::fields);
282 return result;
283}
284
285// --------------------------------------------------------------------------
286// generic_get_num_sub_exprs: count all expr2tc children in K::fields.
287// --------------------------------------------------------------------------
288template <class K>
290{
291 size_t total = 0;
292 std::apply(
293 [&](auto... mp) { (void)((total += do_count_sub_exprs(a.*mp)), ...); },
294 K::fields);
295 return total;
296}
297
298// --------------------------------------------------------------------------
299// generic_foreach_operand_impl_const: const delegate iteration.
300// --------------------------------------------------------------------------
301template <class K>
303 const K &a,
305{
306 std::apply(
307 [&](auto... mp) { (call_expr_delegate(a.*mp, f), ...); }, K::fields);
308}
309
310// --------------------------------------------------------------------------
311// generic_foreach_operand_impl: non-const delegate iteration.
312// --------------------------------------------------------------------------
313template <class K>
315{
316 std::apply(
317 [&](auto... mp) { (call_expr_delegate(a.*mp, f), ...); }, K::fields);
318}
319
320// --------------------------------------------------------------------------
321// Type-side generic helpers. Identical shape to the expr-side ones above
322// but typed against type2t and folding type_id (instead of expr_id) into
323// crc/hash. Type kinds' `fields` tuples list only user-visible fields —
324// type_id is mixed in here at the head of crc/hash and is short-circuited
325// by the outer switch boundary for cmp/lt.
326// --------------------------------------------------------------------------
327
328template <class K>
329bool generic_cmp_type(const K &a, const type2t &o)
330{
331 // Canonical instantiation site for the per-kind invariant chain on the
332 // type side; see generic_cmp() above for rationale.
333 static_assert(assert_kind_invariants<K>());
334 const K &b = static_cast<const K &>(o);
335 bool eq = true;
336 std::apply(
337 [&](auto... mp) { ((eq = eq && do_type_cmp(a.*mp, b.*mp)), ...); },
338 K::fields);
339 return eq;
340}
341
342template <class K>
343int generic_lt_type(const K &a, const type2t &o)
344{
345 const K &b = static_cast<const K &>(o);
346 int r = 0;
347 std::apply(
348 [&](auto... mp) {
349 ((r == 0 ? (void)(r = do_type_lt(a.*mp, b.*mp)) : (void)0), ...);
350 },
351 K::fields);
352 return r;
353}
354
355template <class K>
356list_of_memberst generic_tostring_type(const K &a, unsigned int indent)
357{
359 unsigned int idx = 0;
360 std::apply(
361 [&](auto... mp) {
362 (..., ([&]() {
363 do_type2string(a.*mp, idx++, K::field_names, vec, indent);
364 }()));
365 },
366 K::fields);
367 return vec;
368}
369
370template <class K>
372 const K &a,
374{
375 std::apply(
376 [&](auto... mp) { (call_type_delegate(a.*mp, f), ...); }, K::fields);
377}
378
379template <class K>
381{
382 std::apply(
383 [&](auto... mp) { (call_type_delegate(a.*mp, f), ...); }, K::fields);
384}
385
386} // namespace esbmct
Definition bigint.hh:58
int compare(llong_t) const
Definition bigint.cpp:709
Base class for all expressions.
Definition irep2.h:725
esbmct::function_ref< void(const expr2tc &)> const_op_delegate
Definition irep2.h:741
esbmct::function_ref< void(expr2tc &)> op_delegate
Definition irep2.h:742
Definition fixedbv.h:38
Definition ieee_float.h:75
ieee_float_spect spec
Definition ieee_float.h:89
BigInt pack() const
Definition ieee_float.cpp:367
Definition irep_idt.h:12
Base class for all types.
Definition irep2.h:554
esbmct::function_ref< void(type2tc &)> subtype_delegate
Definition irep2.h:586
esbmct::function_ref< void(const type2tc &)> const_subtype_delegate
Definition irep2.h:585
#define T
Definition exp2f.c:24
std::list< member_entryt > list_of_memberst
Definition irep2.h:459
irep_container< type2t > type2tc
Definition irep2.h:430
std::pair< std::string, std::string > member_entryt
Definition irep2.h:458
irep_container< expr2t > expr2tc
Definition irep2.h:431
bool do_get_sub_expr(const T &, size_t, size_t &, const expr2tc *&)
Definition irep2_dispatch.h:112
bool do_get_sub_expr< expr2tc >(const expr2tc &item, size_t idx, size_t &it, const expr2tc *&ptr)
Definition irep2_utils.cpp:332
void call_expr_delegate(T &, U &)
Definition irep2_dispatch.h:147
size_t do_count_sub_exprs(T &)
Definition irep2_dispatch.h:132
bool do_type_cmp(const T &side1, const T &side2)
Definition irep2_dispatch.h:57
void call_type_delegate(T &, U &)
Definition irep2_dispatch.h:173
void call_type_delegate< type2tc, type2t::subtype_delegate >(type2tc &ref, type2t::subtype_delegate &f)
Definition irep2_utils.cpp:425
void do_type2string(const T &thething, unsigned int idx, std::string(&names)[esbmct::num_type_fields], list_of_memberst &vec, unsigned int indent)
Definition irep2_dispatch.h:101
size_t do_count_sub_exprs< const expr2tc >(const expr2tc &)
Definition irep2_utils.cpp:370
void call_type_delegate< const type2tc, type2t::const_subtype_delegate >(const type2tc &ref, type2t::const_subtype_delegate &f)
Definition irep2_utils.cpp:417
void call_expr_delegate< expr2tc, expr2t::op_delegate >(expr2tc &ref, expr2t::op_delegate &f)
Definition irep2_utils.cpp:391
std::string type_to_string(const bool &thebool, int)
Definition irep2_utils.cpp:456
void call_expr_delegate< const expr2tc, expr2t::const_op_delegate >(const expr2tc &ref, expr2t::const_op_delegate &f)
Definition irep2_utils.cpp:383
int do_type_lt(const T &side1, const T &side2)
Definition irep2_dispatch.h:64
printf_kindt
Which member of the printf family a code_printf2t represents.
Definition irep2_expr.h:98
constant_string_kindt
Definition irep2_expr.h:27
symbol_renaming_level
Symex renaming level for symbol2t.
Definition irep2_expr.h:54
sideeffect_allockind
Enumeration identifying each particular kind of side effect.
Definition irep2_expr.h:73
pointer_ref_kindt
How the source spelled a pointer.
Definition irep2_type.h:556
Containers and field-walking infrastructure for irep2 nodes.
Definition esbmc_internal_cpp.h:3
constexpr bool assert_kind_invariants()
Definition irep2.h:1134
void generic_foreach_operand_impl_const(const K &a, expr2t::const_op_delegate &f)
Definition irep2_dispatch.h:302
int generic_lt_type(const K &a, const type2t &o)
Definition irep2_dispatch.h:343
void generic_foreach_operand_impl(K &a, expr2t::op_delegate &f)
Definition irep2_dispatch.h:314
bool generic_cmp(const K &a, const expr2t &o)
Definition irep2_dispatch.h:215
list_of_memberst generic_tostring_type(const K &a, unsigned int indent)
Definition irep2_dispatch.h:356
void generic_foreach_subtype(K &a, type2t::subtype_delegate &f)
Definition irep2_dispatch.h:380
bool generic_cmp_type(const K &a, const type2t &o)
Definition irep2_dispatch.h:329
size_t generic_get_num_sub_exprs(const K &a)
Definition irep2_dispatch.h:289
list_of_memberst generic_tostring(const K &a, unsigned int indent)
Definition irep2_dispatch.h:250
void generic_foreach_subtype_const(const K &a, type2t::const_subtype_delegate &f)
Definition irep2_dispatch.h:371
int generic_lt(const K &a, const expr2t &o)
Definition irep2_dispatch.h:231
const expr2tc * generic_get_sub_expr(const K &a, size_t idx)
Definition irep2_dispatch.h:273
const unsigned int num_type_fields
Maximum number of fields to support in expr2t subclasses.
Definition irep2.h:998