73 std::map<const IR::IDeclaration *, SymbolicValue *> map;
76 for (
auto v : map) result->map.emplace(v.first, v.second->clone());
82 if (filter(v.first, v.second)) result->map.emplace(v.first, v.second);
92 return ::P4::get(map, left);
95 void dbprint(std::ostream &out)
const {
98 if (!first) out << std::endl;
99 out << f.first <<
"=>" << f.second;
105 BUG_CHECK(map.size() == other->map.size(),
"Merging incompatible maps?");
107 auto v = other->get(d.first);
109 change = change || d.second->merge(v);
113 bool equals(
const ValueMap *other)
const {
114 BUG_CHECK(map.size() == other->map.size(),
"Incompatible maps compared");
116 auto ov = other->get(v.first);
118 if (!v.second->equals(ov))
return false;
129 bool evaluatingLeftValue =
false;
131 std::map<const IR::Expression *, SymbolicValue *> value;
134 LOG2(
"Symbolic evaluation of " << expression <<
" is " << v);
135 value.emplace(expression, v);
139 void postorder(
const IR::Constant *expression)
override;
140 void postorder(
const IR::BoolLiteral *expression)
override;
141 void postorder(
const IR::Operation_Ternary *expression)
override;
142 void postorder(
const IR::Operation_Binary *expression)
override;
143 void postorder(
const IR::Operation_Relation *expression)
override;
144 void postorder(
const IR::Operation_Unary *expression)
override;
145 void postorder(
const IR::PathExpression *expression)
override;
146 void postorder(
const IR::Member *expression)
override;
147 bool preorder(
const IR::ArrayIndex *expression)
override;
148 void postorder(
const IR::ArrayIndex *expression)
override;
149 void postorder(
const IR::ListExpression *expression)
override;
150 void postorder(
const IR::StructExpression *expression)
override;
151 void postorder(
const IR::MethodCallExpression *expression)
override;
152 void checkResult(
const IR::Expression *expression,
const IR::Expression *result);
153 void setNonConstant(
const IR::Expression *expression);
157 : refMap(refMap), typeMap(typeMap), valueMap(valueMap) {
160 CHECK_NULL(valueMap);
166 SymbolicValue *evaluate(
const IR::Expression *expression,
bool leftValue);
169 auto r = ::P4::get(value, expression);
170 BUG_CHECK(r !=
nullptr,
"no evaluation for %1%", expression);
196class SymbolicException :
public SymbolicError {
198 const P4::StandardExceptions exc;
199 SymbolicException(
const IR::Node *errorPosition, P4::StandardExceptions exc)
200 : SymbolicError(errorPosition), exc(exc) {}
201 SymbolicValue *clone()
const override {
return new SymbolicException(errorPosition, exc); }
202 void dbprint(std::ostream &out)
const override { out <<
"Exception: " << exc; }
203 cstring message()
const override {
204 std::stringstream str;
210 DECLARE_TYPEINFO(SymbolicException, SymbolicError);
213class SymbolicStaticError :
public SymbolicError {
215 const std::string msg;
216 SymbolicStaticError(
const IR::Node *errorPosition, std::string_view message)
217 : SymbolicError(errorPosition), msg(message) {}
218 SymbolicValue *clone()
const override {
return new SymbolicStaticError(errorPosition, msg); }
219 void dbprint(std::ostream &out)
const override { out <<
"Error: " << msg; }
220 cstring message()
const override {
return msg; }
223 DECLARE_TYPEINFO(SymbolicStaticError, SymbolicError);
226class ScalarValue :
public SymbolicValue {
228 enum class ValueState {
235 ScalarValue(ScalarValue::ValueState state,
const IR::Type *type)
236 : SymbolicValue(type), state(state) {}
240 bool isUninitialized()
const {
return state == ValueState::Uninitialized; }
241 bool isUnknown()
const {
return state == ValueState::NotConstant; }
242 bool isKnown()
const {
return state == ValueState::Constant; }
243 bool isScalar()
const override {
return true; }
244 void dbprint(std::ostream &out)
const override {
245 if (isUninitialized())
246 out <<
"uninitialized";
247 else if (isUnknown())
250 static ValueState init(
bool uninit) {
251 return uninit ? ValueState::Uninitialized : ValueState::NotConstant;
253 void setAllUnknown()
override { state = ScalarValue::ValueState::NotConstant; }
254 ValueState mergeState(ValueState other)
const {
255 if (state == ValueState::Uninitialized && other == ValueState::Uninitialized)
256 return ValueState::Uninitialized;
257 if (state == ValueState::Constant && other == ValueState::Constant)
259 return ValueState::Constant;
260 return ValueState::NotConstant;
262 bool hasUninitializedParts()
const override {
return state == ValueState::Uninitialized; }
264 DECLARE_TYPEINFO(ScalarValue, SymbolicValue);
288class SymbolicBool final :
public ScalarValue {
291 explicit SymbolicBool(ScalarValue::ValueState state)
292 : ScalarValue(state, IR::Type_Boolean::get()), value(
false) {}
294 : ScalarValue(ScalarValue::ValueState::Uninitialized, IR::Type_Boolean::get()),
296 explicit SymbolicBool(
const IR::BoolLiteral *constant)
297 : ScalarValue(ScalarValue::ValueState::Constant, IR::Type_Boolean::get()),
298 value(constant->value) {}
299 SymbolicBool(
const SymbolicBool &other) =
default;
300 explicit SymbolicBool(
bool value)
301 : ScalarValue(ScalarValue::ValueState::Constant, IR::Type_Boolean::get()), value(value) {}
302 void dbprint(std::ostream &out)
const override {
303 ScalarValue::dbprint(out);
304 if (!isKnown())
return;
305 out << (value ?
"true" :
"false");
308 auto result =
new SymbolicBool();
309 result->state = state;
310 result->value = value;
317 DECLARE_TYPEINFO(SymbolicBool, ScalarValue);
320class SymbolicInteger final :
public ScalarValue {
322 const IR::Constant *constant;
323 explicit SymbolicInteger(
const IR::Type_Bits *type)
324 : ScalarValue(ScalarValue::ValueState::Uninitialized, type), constant(
nullptr) {}
325 SymbolicInteger(ScalarValue::ValueState state,
const IR::Type_Bits *type)
326 : ScalarValue(state, type), constant(
nullptr) {}
327 explicit SymbolicInteger(
const IR::Constant *constant)
328 : ScalarValue(ScalarValue::ValueState::Constant, constant->type), constant(constant) {
329 CHECK_NULL(constant);
331 SymbolicInteger(
const SymbolicInteger &other) =
default;
332 void dbprint(std::ostream &out)
const override {
333 ScalarValue::dbprint(out);
334 if (isKnown()) out << constant->value;
337 auto result =
new SymbolicInteger(type->to<IR::Type_Bits>());
338 result->state = state;
339 result->constant = constant;
346 DECLARE_TYPEINFO(SymbolicInteger, ScalarValue);
349class SymbolicVarbit final :
public ScalarValue {
351 explicit SymbolicVarbit(
const IR::Type_Varbits *type)
352 : ScalarValue(ScalarValue::ValueState::Uninitialized, type) {}
353 SymbolicVarbit(ScalarValue::ValueState state,
const IR::Type_Varbits *type)
354 : ScalarValue(state, type) {}
355 SymbolicVarbit(
const SymbolicVarbit &other) =
default;
356 void dbprint(std::ostream &out)
const override { ScalarValue::dbprint(out); }
358 return new SymbolicVarbit(state, type->to<IR::Type_Varbits>());
364 DECLARE_TYPEINFO(SymbolicVarbit, ScalarValue);
368class SymbolicEnum final :
public ScalarValue {
372 explicit SymbolicEnum(
const IR::Type *type)
373 : ScalarValue(ScalarValue::ValueState::Uninitialized, type) {}
374 SymbolicEnum(ScalarValue::ValueState state,
const IR::Type *type,
const IR::ID value)
375 : ScalarValue(state, type), value(value) {}
376 SymbolicEnum(
const IR::Type *type,
const IR::ID value)
377 : ScalarValue(ScalarValue::ValueState::Constant, type), value(value) {}
378 SymbolicEnum(
const SymbolicEnum &other) =
default;
379 void dbprint(std::ostream &out)
const override {
380 ScalarValue::dbprint(out);
381 if (isKnown()) out << value;
383 SymbolicValue *clone()
const override {
return new SymbolicEnum(state, type, value); }
388 DECLARE_TYPEINFO(SymbolicEnum, ScalarValue);
391class SymbolicStruct :
public SymbolicValue {
393 explicit SymbolicStruct(
const IR::Type_StructLike *type) : SymbolicValue(type) {
396 std::map<cstring, SymbolicValue *> fieldValue;
397 SymbolicStruct(
const IR::Type_StructLike *type,
bool uninitialized,
400 auto r = ::P4::get(fieldValue, field);
404 void set(
cstring field, SymbolicValue *value) {
406 fieldValue[field] = value;
408 void dbprint(std::ostream &out)
const override;
409 bool isScalar()
const override {
return false; }
410 SymbolicValue *clone()
const override;
411 void setAllUnknown()
override;
412 void assign(
const SymbolicValue *other)
override;
413 bool merge(
const SymbolicValue *other)
override;
414 bool equals(
const SymbolicValue *other)
const override;
415 bool hasUninitializedParts()
const override;
417 DECLARE_TYPEINFO(SymbolicStruct, SymbolicValue);
455class SymbolicArray final :
public SymbolicValue {
456 std::vector<SymbolicStruct *> values;
457 friend class AnyElement;
458 explicit SymbolicArray(
const IR::Type_Stack *type)
459 : SymbolicValue(type),
460 size(type->getSize()),
461 elemType(type->elementType->to<IR::Type_Header>()) {}
465 const IR::Type_Header *elemType;
466 SymbolicArray(
const IR::Type_Stack *stack,
bool uninitialized,
468 SymbolicValue *get(
const IR::Node *node,
size_t index)
const {
469 if (index >= values.size())
471 return values.at(index);
473 void shift(
int amount);
476 values[index] = value;
478 void dbprint(std::ostream &out)
const override;
479 SymbolicValue *clone()
const override;
480 SymbolicValue *next(
const IR::Node *node);
481 SymbolicValue *last(
const IR::Node *node);
482 SymbolicValue *lastIndex(
const IR::Node *node);
483 bool isScalar()
const override {
return false; }
484 void setAllUnknown()
override;
485 void assign(
const SymbolicValue *other)
override;
486 bool merge(
const SymbolicValue *other)
override;
487 bool equals(
const SymbolicValue *other)
const override;
488 bool hasUninitializedParts()
const override;
490 DECLARE_TYPEINFO(SymbolicArray, SymbolicValue);
494class AnyElement final :
public SymbolicHeader {
498 explicit AnyElement(
SymbolicArray *parent) : SymbolicHeader(parent->elemType), parent(parent) {
503 auto result =
new AnyElement(parent);
506 void setAllUnknown()
override { parent->setAllUnknown(); }
507 void assign(
const SymbolicValue *)
override { parent->setAllUnknown(); }
508 void dbprint(std::ostream &out)
const override { out <<
"Any element of " << parent; }
509 void setValid(
bool)
override { parent->setAllUnknown(); }
513 bool hasUninitializedParts()
const override { BUG(
"Should not be called"); }
515 DECLARE_TYPEINFO(AnyElement, SymbolicHeader);
518class SymbolicTuple final :
public SymbolicValue {
519 std::vector<SymbolicValue *> values;
522 explicit SymbolicTuple(
const IR::Type_Tuple *type) : SymbolicValue(type) {}
523 SymbolicTuple(
const IR::Type_Tuple *type,
bool uninitialized,
525 SymbolicValue *get(
size_t index)
const {
return values.at(index); }
526 void dbprint(std::ostream &out)
const override {
528 for (
auto f : values) {
529 if (!first) out <<
", ";
534 SymbolicValue *clone()
const override;
535 bool isScalar()
const override {
return false; }
536 void setAllUnknown()
override;
537 void assign(
const SymbolicValue *)
override { BUG(
"%1%: tuples are read-only",
this); }
538 void add(SymbolicValue *value) { values.push_back(value); }
539 bool merge(
const SymbolicValue *other)
override;
540 bool equals(
const SymbolicValue *other)
const override;
541 bool hasUninitializedParts()
const override;
543 DECLARE_TYPEINFO(SymbolicTuple, SymbolicValue);
547class SymbolicExtern :
public SymbolicValue {
549 explicit SymbolicExtern(
const IR::Type_Extern *type) : SymbolicValue(type) { CHECK_NULL(type); }
550 void dbprint(std::ostream &out)
const override { out <<
"instance of " << type; }
551 SymbolicValue *clone()
const override {
552 return new SymbolicExtern(type->to<IR::Type_Extern>());
554 bool isScalar()
const override {
return false; }
555 void setAllUnknown()
override { BUG(
"%1%: extern is read-only",
this); }
556 void assign(
const SymbolicValue *)
override { BUG(
"%1%: extern is read-only",
this); }
557 bool merge(
const SymbolicValue *)
override {
return false; }
558 bool equals(
const SymbolicValue *other)
const override;
559 bool hasUninitializedParts()
const override {
return false; }
561 DECLARE_TYPEINFO(SymbolicExtern, SymbolicValue);
565class SymbolicPacketIn final :
public SymbolicExtern {
570 unsigned minimumStreamOffset;
576 explicit SymbolicPacketIn(
const IR::Type_Extern *type)
577 : SymbolicExtern(type), minimumStreamOffset(0), conservative(
false) {}
578 void dbprint(std::ostream &out)
const override {
579 out <<
"packet_in; offset =" << minimumStreamOffset
580 << (conservative ?
" (conservative)" :
"");
583 auto result =
new SymbolicPacketIn(type->to<IR::Type_Extern>());
584 result->minimumStreamOffset = minimumStreamOffset;
585 result->conservative = conservative;
588 void setConservative() { conservative =
true; }
589 bool isConservative()
const {
return conservative; }
590 void advance(
unsigned width) { minimumStreamOffset += width; }
594 DECLARE_TYPEINFO(SymbolicPacketIn, SymbolicExtern);
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24