14
14
15
15
#include " p4_symbolic/z3_util.h"
16
16
17
+ #include < cstddef>
18
+ #include < cstdint>
19
+ #include < string>
20
+
21
+ #include " absl/numeric/int128.h"
22
+ #include " absl/status/status.h"
17
23
#include " absl/status/statusor.h"
24
+ #include " absl/strings/match.h"
25
+ #include " absl/strings/numbers.h"
26
+ #include " absl/strings/str_cat.h"
27
+ #include " absl/strings/string_view.h"
18
28
#include " absl/strings/strip.h"
29
+ #include " absl/types/optional.h"
19
30
#include " gmpxx.h"
20
31
#include " gutil/status.h"
32
+ #include " p4_pdpi/string_encodings/bit_string.h"
21
33
#include " p4_pdpi/string_encodings/hex_string.h"
22
34
#include " z3++.h"
35
+ #include " z3_api.h"
23
36
24
37
namespace p4_symbolic {
25
38
@@ -113,25 +126,32 @@ absl::Status AppendHexCharStringToPDPIBitString(
113
126
114
127
absl::StatusOr<bool > EvalZ3Bool (const z3::expr& bool_expr,
115
128
const z3::model& model) {
116
- // TODO: Ensure this doesn't crash by checking sort first.
117
- auto value = model.eval (bool_expr, true ).bool_value ();
129
+ if (!bool_expr.is_bool ()) {
130
+ return gutil::InvalidArgumentErrorBuilder ()
131
+ << " Expected a boolean expression, found '" << bool_expr << " '" ;
132
+ }
133
+
134
+ auto value = model.eval (bool_expr, /* model_completion=*/ true ).bool_value ();
118
135
switch (value) {
119
136
case Z3_L_FALSE:
120
137
return false ;
121
138
case Z3_L_TRUE:
122
139
return true ;
123
140
default :
124
- break ;
141
+ return gutil::InternalErrorBuilder ()
142
+ << " boolean expression '" << bool_expr
143
+ << " ' evaluated to unexpected Boolean value " << value;
125
144
}
126
- return gutil::InternalErrorBuilder ()
127
- << " boolean expression '" << bool_expr
128
- << " ' evaluated to unexpected Boolean value " << value;
129
145
}
130
146
131
147
absl::StatusOr<int > EvalZ3Int (const z3::expr& int_expr,
132
148
const z3::model& model) {
133
- // TODO: Ensure this doesn't crash by checking sort first.
134
- return model.eval (int_expr, true ).get_numeral_int ();
149
+ if (!int_expr.is_int ()) {
150
+ return gutil::InvalidArgumentErrorBuilder ()
151
+ << " Expected an integer expression, found '" << int_expr << " '" ;
152
+ }
153
+
154
+ return model.eval (int_expr, /* model_completion=*/ true ).get_numeral_int ();
135
155
}
136
156
137
157
absl::Status EvalAndAppendZ3BitvectorToBitString (pdpi::BitString& output,
@@ -142,22 +162,73 @@ absl::Status EvalAndAppendZ3BitvectorToBitString(pdpi::BitString& output,
142
162
<< " Expected a bitvector, found '" << bv_expr << " '" ;
143
163
}
144
164
145
- const std::string field_value =
165
+ const std::string value =
166
+ model.eval (bv_expr, /* model_completion=*/ true ).to_string ();
167
+ return AppendZ3ValueStringToBitString (output, value,
168
+ bv_expr.get_sort ().bv_size ());
169
+ }
170
+
171
+ absl::StatusOr<uint64_t > EvalZ3BitvectorToUInt64 (const z3::expr& bv_expr,
172
+ const z3::model& model) {
173
+ if (!bv_expr.is_bv ()) {
174
+ return gutil::InvalidArgumentErrorBuilder ()
175
+ << " Expected a bitvector, found '" << bv_expr << " '" ;
176
+ }
177
+
178
+ if (bv_expr.get_sort ().bv_size () > 64 ) {
179
+ return gutil::InvalidArgumentErrorBuilder ()
180
+ << " Expected a bitvector within 64 bits, found "
181
+ << bv_expr.get_sort ().bv_size () << " bits" ;
182
+ }
183
+
184
+ const std::string value =
146
185
model.eval (bv_expr, /* model_completion=*/ true ).to_string ();
147
- absl::string_view field_value_view = field_value;
148
-
149
- if (absl::ConsumePrefix (&field_value_view, " #x" )) {
150
- RETURN_IF_ERROR (AppendHexCharStringToPDPIBitString (
151
- output, field_value_view, bv_expr.get_sort ().bv_size ()));
152
- } else if (absl::ConsumePrefix (&field_value_view, " #b" )) {
153
- RETURN_IF_ERROR (AppendBitCharStringToPDPIBitString (
154
- output, field_value_view, bv_expr.get_sort ().bv_size ()));
186
+ return Z3ValueStringToInt (value);
187
+ }
188
+
189
+ absl::StatusOr<absl::uint128> EvalZ3BitvectorToUInt128 (const z3::expr& bv_expr,
190
+ const z3::model& model) {
191
+ if (!bv_expr.is_bv ()) {
192
+ return gutil::InvalidArgumentErrorBuilder ()
193
+ << " Expected a bitvector, found '" << bv_expr << " '" ;
194
+ }
195
+
196
+ if (bv_expr.get_sort ().bv_size () > 128 ) {
197
+ return gutil::InvalidArgumentErrorBuilder ()
198
+ << " Expected a bitvector within 128 bits, found "
199
+ << bv_expr.get_sort ().bv_size () << " bits" ;
200
+ }
201
+
202
+ const std::string value_string =
203
+ model.eval (bv_expr, /* model_completion=*/ true ).to_string ();
204
+ absl::string_view value = value_string;
205
+ absl::uint128 result;
206
+
207
+ if (absl::ConsumePrefix (&value, " #x" )) {
208
+ if (!absl::SimpleHexAtoi (value, &result)) {
209
+ return gutil::InvalidArgumentErrorBuilder ()
210
+ << " Unable to convert hex string '" << value << " ' to uint128" ;
211
+ }
212
+ } else if (absl::ConsumePrefix (&value, " #b" )) {
213
+ uint64_t hi = 0 ;
214
+ uint64_t lo = 0 ;
215
+
216
+ if (value.size () > 64 ) {
217
+ hi = std::stoull (std::string (value.substr (0 , value.size () - 64 )),
218
+ /* idx=*/ nullptr , /* base=*/ 2 );
219
+ lo = std::stoull (std::string (value.substr (value.size () - 64 )),
220
+ /* idx=*/ nullptr , /* base=*/ 2 );
221
+ } else {
222
+ lo = std::stoull (std::string (value), /* idx=*/ nullptr , /* base=*/ 2 );
223
+ }
224
+
225
+ result = absl::MakeUint128 (hi, lo);
155
226
} else {
156
227
return gutil::InvalidArgumentErrorBuilder ()
157
- << " Invalid Z3 bitvector value '" << field_value << " '" ;
228
+ << " Invalid Z3 bitvector value '" << value << " '" ;
158
229
}
159
230
160
- return absl::OkStatus () ;
231
+ return result ;
161
232
}
162
233
163
234
absl::StatusOr<z3::expr> HexStringToZ3Bitvector (z3::context& context,
@@ -191,4 +262,21 @@ uint64_t Z3ValueStringToInt(const std::string& value) {
191
262
}
192
263
}
193
264
265
+ absl::Status AppendZ3ValueStringToBitString (pdpi::BitString& result,
266
+ absl::string_view value,
267
+ size_t num_bits) {
268
+ if (absl::ConsumePrefix (&value, " #x" )) {
269
+ RETURN_IF_ERROR (
270
+ AppendHexCharStringToPDPIBitString (result, value, num_bits));
271
+ } else if (absl::ConsumePrefix (&value, " #b" )) {
272
+ RETURN_IF_ERROR (
273
+ AppendBitCharStringToPDPIBitString (result, value, num_bits));
274
+ } else {
275
+ return gutil::InvalidArgumentErrorBuilder ()
276
+ << " Invalid Z3 bitvector value '" << value << " '" ;
277
+ }
278
+
279
+ return absl::OkStatus ();
280
+ }
281
+
194
282
} // namespace p4_symbolic
0 commit comments