65 std::map<const IR::IDeclaration *, SymbolicValue *> map;
68 for (
auto v : map) result->map.emplace(v.first, v.second->clone());
74 if (filter(v.first, v.second)) result->map.emplace(v.first, v.second);
84 return ::P4::get(map, left);
87 void dbprint(std::ostream &out)
const {
90 if (!first) out << std::endl;
91 out << f.first <<
"=>" << f.second;
97 BUG_CHECK(map.size() == other->map.size(),
"Merging incompatible maps?");
99 auto v = other->get(d.first);
101 change = change || d.second->merge(v);
105 bool equals(
const ValueMap *other)
const {
106 BUG_CHECK(map.size() == other->map.size(),
"Incompatible maps compared");
108 auto ov = other->get(v.first);
110 if (!v.second->equals(ov))
return false;
121 bool evaluatingLeftValue =
false;
123 std::map<const IR::Expression *, SymbolicValue *> value;
126 LOG2(
"Symbolic evaluation of " << expression <<
" is " << v);
127 value.emplace(expression, v);
131 void postorder(
const IR::Constant *expression)
override;
132 void postorder(
const IR::BoolLiteral *expression)
override;
133 void postorder(
const IR::StringLiteral *expression)
override;
134 void postorder(
const IR::Operation_Ternary *expression)
override;
135 void postorder(
const IR::Operation_Binary *expression)
override;
136 void postorder(
const IR::Operation_Relation *expression)
override;
137 void postorder(
const IR::Operation_Unary *expression)
override;
138 void postorder(
const IR::PathExpression *expression)
override;
139 void postorder(
const IR::Member *expression)
override;
140 bool preorder(
const IR::ArrayIndex *expression)
override;
141 void postorder(
const IR::ArrayIndex *expression)
override;
142 void postorder(
const IR::ListExpression *expression)
override;
143 void postorder(
const IR::StructExpression *expression)
override;
144 void postorder(
const IR::MethodCallExpression *expression)
override;
145 void checkResult(
const IR::Expression *expression,
const IR::Expression *result);
146 void setNonConstant(
const IR::Expression *expression);
150 : refMap(refMap), typeMap(typeMap), valueMap(valueMap) {
153 CHECK_NULL(valueMap);
159 SymbolicValue *evaluate(
const IR::Expression *expression,
bool leftValue);
162 auto r = ::P4::get(value, expression);
163 BUG_CHECK(r !=
nullptr,
"no evaluation for %1%", expression);
189class SymbolicException :
public SymbolicError {
191 const P4::StandardExceptions exc;
192 SymbolicException(
const IR::Node *errorPosition, P4::StandardExceptions exc)
193 : SymbolicError(errorPosition), exc(exc) {}
194 SymbolicValue *clone()
const override {
return new SymbolicException(errorPosition, exc); }
195 void dbprint(std::ostream &out)
const override { out <<
"Exception: " << exc; }
196 cstring message()
const override {
197 std::stringstream str;
203 DECLARE_TYPEINFO(SymbolicException, SymbolicError);
206class SymbolicStaticError :
public SymbolicError {
208 const std::string msg;
209 SymbolicStaticError(
const IR::Node *errorPosition, std::string_view message)
210 : SymbolicError(errorPosition), msg(message) {}
211 SymbolicValue *clone()
const override {
return new SymbolicStaticError(errorPosition, msg); }
212 void dbprint(std::ostream &out)
const override { out <<
"Error: " << msg; }
213 cstring message()
const override {
return msg; }
216 DECLARE_TYPEINFO(SymbolicStaticError, SymbolicError);
219class ScalarValue :
public SymbolicValue {
221 enum class ValueState {
228 ScalarValue(ScalarValue::ValueState state,
const IR::Type *type)
229 : SymbolicValue(type), state(state) {}
233 bool isUninitialized()
const {
return state == ValueState::Uninitialized; }
234 bool isUnknown()
const {
return state == ValueState::NotConstant; }
235 bool isKnown()
const {
return state == ValueState::Constant; }
236 bool isScalar()
const override {
return true; }
237 void dbprint(std::ostream &out)
const override {
238 if (isUninitialized())
239 out <<
"uninitialized";
240 else if (isUnknown())
243 static ValueState init(
bool uninit) {
244 return uninit ? ValueState::Uninitialized : ValueState::NotConstant;
246 void setAllUnknown()
override { state = ScalarValue::ValueState::NotConstant; }
247 ValueState mergeState(ValueState other)
const {
248 if (state == ValueState::Uninitialized && other == ValueState::Uninitialized)
249 return ValueState::Uninitialized;
250 if (state == ValueState::Constant && other == ValueState::Constant)
252 return ValueState::Constant;
253 return ValueState::NotConstant;
255 bool hasUninitializedParts()
const override {
return state == ValueState::Uninitialized; }
257 DECLARE_TYPEINFO(ScalarValue, SymbolicValue);
281class SymbolicBool final :
public ScalarValue {
284 explicit SymbolicBool(ScalarValue::ValueState state)
285 : ScalarValue(state, IR::Type_Boolean::get()), value(
false) {}
287 : ScalarValue(ScalarValue::ValueState::Uninitialized, IR::Type_Boolean::get()),
289 explicit SymbolicBool(
const IR::BoolLiteral *constant)
290 : ScalarValue(ScalarValue::ValueState::Constant, IR::Type_Boolean::get()),
291 value(constant->value) {}
292 SymbolicBool(
const SymbolicBool &other) =
default;
293 explicit SymbolicBool(
bool value)
294 : ScalarValue(ScalarValue::ValueState::Constant, IR::Type_Boolean::get()), value(value) {}
295 void dbprint(std::ostream &out)
const override {
296 ScalarValue::dbprint(out);
297 if (!isKnown())
return;
298 out << (value ?
"true" :
"false");
301 auto result =
new SymbolicBool();
302 result->state = state;
303 result->value = value;
310 DECLARE_TYPEINFO(SymbolicBool, ScalarValue);
313class SymbolicInteger final :
public ScalarValue {
315 const IR::Constant *constant;
316 explicit SymbolicInteger(
const IR::Type_Bits *type)
317 : ScalarValue(ScalarValue::ValueState::Uninitialized, type), constant(
nullptr) {}
318 SymbolicInteger(ScalarValue::ValueState state,
const IR::Type_Bits *type)
319 : ScalarValue(state, type), constant(
nullptr) {}
320 explicit SymbolicInteger(
const IR::Constant *constant)
321 : ScalarValue(ScalarValue::ValueState::Constant, constant->type), constant(constant) {}
322 SymbolicInteger(
const SymbolicInteger &other) =
default;
323 void dbprint(std::ostream &out)
const override {
324 ScalarValue::dbprint(out);
325 if (isKnown()) out << constant->value;
328 auto result =
new SymbolicInteger(type->to<IR::Type_Bits>());
329 result->state = state;
330 result->constant = constant;
337 DECLARE_TYPEINFO(SymbolicInteger, ScalarValue);
340class SymbolicString final :
public ScalarValue {
342 const IR::StringLiteral *string;
343 explicit SymbolicString(
const IR::Type_String *type)
344 : ScalarValue(ScalarValue::ValueState::Uninitialized, type), string(
nullptr) {}
345 SymbolicString(ScalarValue::ValueState state,
const IR::Type_String *type)
346 : ScalarValue(state, type), string(
nullptr) {}
347 explicit SymbolicString(
const IR::StringLiteral *
string)
348 : ScalarValue(ScalarValue::ValueState::Constant, string->type), string(
string) {}
349 SymbolicString(
const SymbolicString &other) =
default;
350 void dbprint(std::ostream &out)
const override {
351 ScalarValue::dbprint(out);
352 if (isKnown()) out <<
string->value;
355 auto result =
new SymbolicString(type->to<IR::Type_String>());
356 result->state = state;
357 result->string = string;
364 DECLARE_TYPEINFO(SymbolicString, ScalarValue);
367class SymbolicVarbit final :
public ScalarValue {
369 explicit SymbolicVarbit(
const IR::Type_Varbits *type)
370 : ScalarValue(ScalarValue::ValueState::Uninitialized, type) {}
371 SymbolicVarbit(ScalarValue::ValueState state,
const IR::Type_Varbits *type)
372 : ScalarValue(state, type) {}
373 SymbolicVarbit(
const SymbolicVarbit &other) =
default;
374 void dbprint(std::ostream &out)
const override { ScalarValue::dbprint(out); }
376 return new SymbolicVarbit(state, type->to<IR::Type_Varbits>());
382 DECLARE_TYPEINFO(SymbolicVarbit, ScalarValue);
386class SymbolicEnum final :
public ScalarValue {
390 explicit SymbolicEnum(
const IR::Type *type)
391 : ScalarValue(ScalarValue::ValueState::Uninitialized, type) {}
392 SymbolicEnum(ScalarValue::ValueState state,
const IR::Type *type,
const IR::ID value)
393 : ScalarValue(state, type), value(value) {}
394 SymbolicEnum(
const IR::Type *type,
const IR::ID value)
395 : ScalarValue(ScalarValue::ValueState::Constant, type), value(value) {}
396 SymbolicEnum(
const SymbolicEnum &other) =
default;
397 void dbprint(std::ostream &out)
const override {
398 ScalarValue::dbprint(out);
399 if (isKnown()) out << value;
401 SymbolicValue *clone()
const override {
return new SymbolicEnum(state, type, value); }
406 DECLARE_TYPEINFO(SymbolicEnum, ScalarValue);
409class SymbolicStruct :
public SymbolicValue {
411 explicit SymbolicStruct(
const IR::Type_StructLike *type) : SymbolicValue(type) {
414 std::map<cstring, SymbolicValue *> fieldValue;
415 SymbolicStruct(
const IR::Type_StructLike *type,
bool uninitialized,
418 auto r = ::P4::get(fieldValue, field);
422 void set(
cstring field, SymbolicValue *value) {
424 fieldValue[field] = value;
426 void dbprint(std::ostream &out)
const override;
427 bool isScalar()
const override {
return false; }
428 SymbolicValue *clone()
const override;
429 void setAllUnknown()
override;
430 void assign(
const SymbolicValue *other)
override;
431 bool merge(
const SymbolicValue *other)
override;
432 bool equals(
const SymbolicValue *other)
const override;
433 bool hasUninitializedParts()
const override;
435 DECLARE_TYPEINFO(SymbolicStruct, SymbolicValue);
473class SymbolicArray final :
public SymbolicValue {
474 std::vector<SymbolicValue *> values;
475 friend class AnyElement;
476 explicit SymbolicArray(
const IR::Type_Array *type)
477 : SymbolicValue(type),
478 size(type->getSize()),
479 elemType(type->elementType->to<IR::Type_Header>()) {}
483 const IR::Type_Header *elemType;
484 SymbolicArray(
const IR::Type_Array *stack,
bool uninitialized,
486 SymbolicValue *get(
const IR::Node *node,
size_t index)
const {
487 if (index >= values.size())
489 return values.at(index);
491 void shift(
int amount);
494 values[index] = value;
496 void dbprint(std::ostream &out)
const override;
497 SymbolicValue *clone()
const override;
498 SymbolicValue *next(
const IR::Node *node);
499 SymbolicValue *last(
const IR::Node *node);
500 SymbolicValue *lastIndex(
const IR::Node *node);
501 bool isScalar()
const override {
return false; }
502 void setAllUnknown()
override;
503 void assign(
const SymbolicValue *other)
override;
504 bool merge(
const SymbolicValue *other)
override;
505 bool equals(
const SymbolicValue *other)
const override;
506 bool hasUninitializedParts()
const override;
508 DECLARE_TYPEINFO(SymbolicArray, SymbolicValue);
512class AnyElement final :
public SymbolicHeader {
516 explicit AnyElement(
SymbolicArray *parent) : SymbolicHeader(parent->elemType), parent(parent) {
520 auto result =
new AnyElement(parent);
523 void setAllUnknown()
override { parent->setAllUnknown(); }
524 void assign(
const SymbolicValue *)
override { parent->setAllUnknown(); }
525 void dbprint(std::ostream &out)
const override { out <<
"Any element of " << parent; }
526 void setValid(
bool)
override { parent->setAllUnknown(); }
530 bool hasUninitializedParts()
const override { BUG(
"Should not be called"); }
532 DECLARE_TYPEINFO(AnyElement, SymbolicHeader);
535class SymbolicTuple final :
public SymbolicValue {
536 std::vector<SymbolicValue *> values;
539 explicit SymbolicTuple(
const IR::Type_Tuple *type) : SymbolicValue(type) {}
540 SymbolicTuple(
const IR::Type_Tuple *type,
bool uninitialized,
542 SymbolicValue *get(
size_t index)
const {
return values.at(index); }
543 void dbprint(std::ostream &out)
const override {
545 for (
auto f : values) {
546 if (!first) out <<
", ";
551 SymbolicValue *clone()
const override;
552 bool isScalar()
const override {
return false; }
553 void setAllUnknown()
override;
554 void assign(
const SymbolicValue *)
override { BUG(
"%1%: tuples are read-only",
this); }
555 void add(SymbolicValue *value) { values.push_back(value); }
556 bool merge(
const SymbolicValue *other)
override;
557 bool equals(
const SymbolicValue *other)
const override;
558 bool hasUninitializedParts()
const override;
560 DECLARE_TYPEINFO(SymbolicTuple, SymbolicValue);
564class SymbolicExtern :
public SymbolicValue {
566 explicit SymbolicExtern(
const IR::Type_Extern *type) : SymbolicValue(type) { CHECK_NULL(type); }
567 void dbprint(std::ostream &out)
const override { out <<
"instance of " << type; }
568 SymbolicValue *clone()
const override {
569 return new SymbolicExtern(type->to<IR::Type_Extern>());
571 bool isScalar()
const override {
return false; }
572 void setAllUnknown()
override { BUG(
"%1%: extern is read-only",
this); }
573 void assign(
const SymbolicValue *)
override { BUG(
"%1%: extern is read-only",
this); }
574 bool merge(
const SymbolicValue *)
override {
return false; }
575 bool equals(
const SymbolicValue *other)
const override;
576 bool hasUninitializedParts()
const override {
return false; }
578 DECLARE_TYPEINFO(SymbolicExtern, SymbolicValue);
582class SymbolicPacketIn final :
public SymbolicExtern {
587 unsigned minimumStreamOffset;
593 explicit SymbolicPacketIn(
const IR::Type_Extern *type)
594 : SymbolicExtern(type), minimumStreamOffset(0), conservative(
false) {}
595 void dbprint(std::ostream &out)
const override {
596 out <<
"packet_in; offset =" << minimumStreamOffset
597 << (conservative ?
" (conservative)" :
"");
600 auto result =
new SymbolicPacketIn(type->to<IR::Type_Extern>());
601 result->minimumStreamOffset = minimumStreamOffset;
602 result->conservative = conservative;
605 void setConservative() { conservative =
true; }
606 bool isConservative()
const {
return conservative; }
607 void advance(
unsigned width) { minimumStreamOffset += width; }
611 DECLARE_TYPEINFO(SymbolicPacketIn, SymbolicExtern);
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:13