11// Author: Diffblue Ltd.
22
33#include < util/arith_tools.h>
4+ #include < util/bitvector_expr.h>
45#include < util/bitvector_types.h>
56#include < util/c_types.h>
7+ #include < util/config.h>
68#include < util/expr_initializer.h>
79#include < util/namespace.h>
810#include < util/std_code.h>
911#include < util/symbol_table.h>
1012
13+ #include < testing-utils/invariant.h>
1114#include < testing-utils/use_catch.h>
1215
16+ #include < iomanip>
17+ #include < sstream>
18+
1319// / Helper struct to hold useful test components.
1420struct expr_initializer_test_environmentt
1521{
@@ -19,6 +25,10 @@ struct expr_initializer_test_environmentt
1925
2026 static expr_initializer_test_environmentt make ()
2127 {
28+ // These config lines are necessary before construction because char size
29+ // depend on the global configuration.
30+ config.ansi_c .mode = configt::ansi_ct::flavourt::GCC;
31+ config.ansi_c .set_arch_spec_x86_64 ();
2232 return {};
2333 }
2434
@@ -68,24 +78,217 @@ create_tag_populate_env(const typet &type, symbol_tablet &symbol_table)
6878 UNREACHABLE;
6979}
7080
71- TEST_CASE (" nondet_initializer boolean" , " [core][util][expr_initializer]" )
81+ exprt replicate_expression (
82+ const exprt &expr,
83+ const typet &output_type,
84+ std::size_t times)
85+ {
86+ if (times == 1 )
87+ {
88+ return expr;
89+ }
90+ exprt::operandst operands;
91+ operands.push_back (expr);
92+ for (std::size_t i = 1 ; i < times; ++i)
93+ {
94+ operands.push_back (
95+ shl_exprt{expr, from_integer (config.ansi_c .char_width * i, size_type ())});
96+ }
97+ return multi_ary_exprt{ID_bitor, operands, output_type};
98+ }
99+
100+ TEST_CASE (
101+ " duplicate_per_byte precondition works" ,
102+ " [core][util][duplicate_per_byte]" )
103+ {
104+ auto test = expr_initializer_test_environmentt::make ();
105+ typet input_type = signedbv_typet{8 };
106+
107+ SECTION (" duplicate_per_byte fails when init type is not a bitvector" )
108+ {
109+ const array_typet array_type{
110+ bool_typet{}, from_integer (3 , signedbv_typet{8 })};
111+
112+ const cbmc_invariants_should_throwt invariants_throw;
113+
114+ REQUIRE_THROWS_MATCHES (
115+ duplicate_per_byte (array_of_exprt{true_exprt{}, array_type}, input_type),
116+ invariant_failedt,
117+ invariant_failure_containing (
118+ " Condition: (init_type_as_bitvector && "
119+ " init_type_as_bitvector->get_width() <= config.ansi_c.char_width) || "
120+ " init_byte_expr.type().id() == ID_bool" ));
121+ }
122+
123+ SECTION (
124+ " duplicate_per_byte fails when init type is a bitvector larger than "
125+ " char_width bits" )
126+ {
127+ const cbmc_invariants_should_throwt invariants_throw;
128+
129+ REQUIRE_THROWS_MATCHES (
130+ duplicate_per_byte (from_integer (0 , unsignedbv_typet{10 }), input_type),
131+ invariant_failedt,
132+ invariant_failure_containing (
133+ " init_type_as_bitvector->get_width() <= config.ansi_c.char_width" ));
134+ }
135+ }
136+
137+ std::string to_hex (unsigned int value)
138+ {
139+ std::stringstream ss;
140+ ss << " 0x" << std::hex << value;
141+ return ss.str ();
142+ }
143+
144+ TEST_CASE (
145+ " duplicate_per_byte on unsigned_bv with constant" ,
146+ " [core][util][duplicate_per_byte]" )
147+ {
148+ auto test = expr_initializer_test_environmentt::make ();
149+ // elements are init_expr_value, init_expr_size, output_expected_value, output_size
150+ using rowt = std::tuple<std::size_t , unsigned int , std::size_t , unsigned int >;
151+ unsigned int init_expr_value, output_expected_value;
152+ std::size_t output_size, init_expr_size;
153+ std::tie (
154+ init_expr_value, init_expr_size, output_expected_value, output_size) =
155+ GENERATE (
156+ rowt{0xFF , 8 , 0xFF , 8 }, // same-type constant
157+ rowt{0x2 , 2 , 0x02 , 8 }, // smaller-type constant gets promoted
158+ rowt{0x11 , 5 , 0x11 , 5 }, // same-type constant
159+ rowt{0x21 , 8 , 0x01 , 5 }, // bigger-type constant gets truncated
160+ rowt{0x2 , 3 , 0x02 , 5 }, // smaller-type constant gets promoted
161+ rowt{0xAB , 8 , 0xABAB , 16 }, // smaller-type constant gets replicated
162+ rowt{0xAB , 8 , 0xBABAB , 20 } // smaller-type constant gets replicated
163+ );
164+ SECTION (
165+ " Testing with output size " + std::to_string (output_size) + " init value " +
166+ to_hex (init_expr_value) + " of size " + std::to_string (init_expr_size))
167+ {
168+ typet output_type = unsignedbv_typet{output_size};
169+ const auto result = duplicate_per_byte (
170+ from_integer (init_expr_value, unsignedbv_typet{init_expr_size}),
171+ output_type);
172+ const auto expected =
173+ from_integer (output_expected_value, unsignedbv_typet{output_size});
174+ REQUIRE (result == expected);
175+
176+ // Check that signed-bv values are replicated including the sign bit.
177+ const auto result_with_signed_init_type = duplicate_per_byte (
178+ from_integer (init_expr_value, signedbv_typet{init_expr_size}),
179+ output_type);
180+ REQUIRE (result_with_signed_init_type == result);
181+ }
182+ }
183+
184+ TEST_CASE (
185+ " duplicate_per_byte on unsigned_bv with non-constant expr" ,
186+ " [core][util][duplicate_per_byte]" )
187+ {
188+ auto test = expr_initializer_test_environmentt::make ();
189+ // elements are init_expr_size, output_size, replication_count
190+ using rowt = std::tuple<std::size_t , std::size_t , std::size_t >;
191+ std::size_t init_expr_size, output_size, replication_count;
192+ std::tie (init_expr_size, output_size, replication_count) = GENERATE (
193+ rowt{8 , 8 , 1 }, // same-type expr no-cast
194+ rowt{2 , 2 , 1 }, // same-type expr no-cast
195+ rowt{3 , 8 , 1 }, // smaller-type gets promoted
196+ rowt{8 , 2 , 1 }, // bigger type gets truncated
197+ rowt{8 , 16 , 2 }, // replicated twice
198+ rowt{8 , 20 , 3 }); // replicated three times and truncated
199+ SECTION (
200+ " Testing with output size " + std::to_string (output_size) + " init size " +
201+ std::to_string (init_expr_size))
202+ {
203+ typet output_type = signedbv_typet{output_size};
204+
205+ const auto init_expr = plus_exprt{
206+ from_integer (1 , unsignedbv_typet{init_expr_size}),
207+ from_integer (2 , unsignedbv_typet{init_expr_size})};
208+ const auto result = duplicate_per_byte (init_expr, output_type);
209+
210+ const auto casted_init_expr =
211+ typecast_exprt::conditional_cast (init_expr, output_type);
212+ const auto expected =
213+ replicate_expression (casted_init_expr, output_type, replication_count);
214+
215+ REQUIRE (result == expected);
216+ }
217+ }
218+
219+ TEST_CASE (" expr_initializer boolean" , " [core][util][expr_initializer]" )
72220{
73221 auto test = expr_initializer_test_environmentt::make ();
74222 typet input = bool_typet{};
75- const auto result = nondet_initializer (input, test.loc , test.ns );
76- REQUIRE (result.has_value ());
77- const auto expected = side_effect_expr_nondett{bool_typet{}, test.loc };
78- REQUIRE (result.value () == expected);
223+ SECTION (" nondet_initializer" )
224+ {
225+ const auto result = nondet_initializer (input, test.loc , test.ns );
226+ REQUIRE (result.has_value ());
227+ const auto expected = side_effect_expr_nondett{bool_typet{}, test.loc };
228+ REQUIRE (result.value () == expected);
229+ }
230+ SECTION (" zero_initializer" )
231+ {
232+ const auto result = zero_initializer (input, test.loc , test.ns );
233+ REQUIRE (result.has_value ());
234+ const auto expected = from_integer (0 , bool_typet ());
235+ ;
236+ REQUIRE (result.value () == expected);
237+ }
238+ SECTION (" expr_initializer with same-type constant" )
239+ {
240+ const auto result =
241+ expr_initializer (input, test.loc , test.ns , true_exprt{});
242+ REQUIRE (result.has_value ());
243+ const auto expected = true_exprt{};
244+ REQUIRE (result.value () == expected);
245+ }
246+ SECTION (" expr_initializer with other-type constant" )
247+ {
248+ const auto result = expr_initializer (
249+ input, test.loc , test.ns , from_integer (1 , signedbv_typet{8 }));
250+ REQUIRE (result.has_value ());
251+ const auto expected =
252+ typecast_exprt{from_integer (1 , signedbv_typet{8 }), bool_typet{}};
253+ REQUIRE (result.value () == expected);
254+ }
255+ SECTION (" expr_initializer with non-constant expr" )
256+ {
257+ const auto result = expr_initializer (
258+ input, test.loc , test.ns , or_exprt{true_exprt (), true_exprt{}});
259+ REQUIRE (result.has_value ());
260+ const auto expected = or_exprt{true_exprt{}, true_exprt{}};
261+ REQUIRE (result.value () == expected);
262+ }
79263}
80264
81- TEST_CASE (" nondet_initializer signed_bv" , " [core][util][expr_initializer]" )
265+ TEST_CASE (
266+ " nondet_initializer 8-bit signed_bv" ,
267+ " [core][util][expr_initializer]" )
82268{
83269 auto test = expr_initializer_test_environmentt::make ();
84- typet input = signedbv_typet{8 };
85- const auto result = nondet_initializer (input, test.loc , test.ns );
86- REQUIRE (result.has_value ());
87- const auto expected = side_effect_expr_nondett{signedbv_typet{8 }, test.loc };
88- REQUIRE (result.value () == expected);
270+ const std::size_t input_type_size = 8 ;
271+ typet input_type = signedbv_typet{input_type_size};
272+ SECTION (" nondet_initializer" )
273+ {
274+ const auto result = nondet_initializer (input_type, test.loc , test.ns );
275+ REQUIRE (result.has_value ());
276+ const auto expected =
277+ side_effect_expr_nondett{signedbv_typet{input_type_size}, test.loc };
278+ REQUIRE (result.value () == expected);
279+ }
280+ SECTION (" zero_initializer" )
281+ {
282+ const auto result = zero_initializer (input_type, test.loc , test.ns );
283+ REQUIRE (result.has_value ());
284+ const auto expected = from_integer (0 , signedbv_typet{input_type_size});
285+ REQUIRE (result.value () == expected);
286+ }
287+ SECTION (" expr_initializer calls duplicate_per_byte" )
288+ {
289+ // TODO: duplicate_per_byte is tested separately. Here we should check that
290+ // expr_initializer calls duplicate_per_byte.
291+ }
89292}
90293
91294TEST_CASE (" nondet_initializer c_enum" , " [core][util][expr_initializer]" )
0 commit comments