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 CHECK_NULL(constant);
324 SymbolicInteger(
const SymbolicInteger &other) =
default;
325 void dbprint(std::ostream &out)
const override {
326 ScalarValue::dbprint(out);
327 if (isKnown()) out << constant->value;
330 auto result =
new SymbolicInteger(type->to<IR::Type_Bits>());
331 result->state = state;
332 result->constant = constant;
339 DECLARE_TYPEINFO(SymbolicInteger, ScalarValue);
342class SymbolicString final :
public ScalarValue {
344 const IR::StringLiteral *string;
345 explicit SymbolicString(
const IR::Type_String *type)
346 : ScalarValue(ScalarValue::ValueState::Uninitialized, type), string(
nullptr) {}
347 SymbolicString(ScalarValue::ValueState state,
const IR::Type_String *type)
348 : ScalarValue(state, type), string(
nullptr) {}
349 explicit SymbolicString(
const IR::StringLiteral *
string)
350 : ScalarValue(ScalarValue::ValueState::Constant, string->type), string(
string) {
353 SymbolicString(
const SymbolicString &other) =
default;
354 void dbprint(std::ostream &out)
const override {
355 ScalarValue::dbprint(out);
356 if (isKnown()) out <<
string->value;
359 auto result =
new SymbolicString(type->to<IR::Type_String>());
360 result->state = state;
361 result->string = string;
368 DECLARE_TYPEINFO(SymbolicString, ScalarValue);
371class SymbolicVarbit final :
public ScalarValue {
373 explicit SymbolicVarbit(
const IR::Type_Varbits *type)
374 : ScalarValue(ScalarValue::ValueState::Uninitialized, type) {}
375 SymbolicVarbit(ScalarValue::ValueState state,
const IR::Type_Varbits *type)
376 : ScalarValue(state, type) {}
377 SymbolicVarbit(
const SymbolicVarbit &other) =
default;
378 void dbprint(std::ostream &out)
const override { ScalarValue::dbprint(out); }
380 return new SymbolicVarbit(state, type->to<IR::Type_Varbits>());
386 DECLARE_TYPEINFO(SymbolicVarbit, ScalarValue);
390class SymbolicEnum final :
public ScalarValue {
394 explicit SymbolicEnum(
const IR::Type *type)
395 : ScalarValue(ScalarValue::ValueState::Uninitialized, type) {}
396 SymbolicEnum(ScalarValue::ValueState state,
const IR::Type *type,
const IR::ID value)
397 : ScalarValue(state, type), value(value) {}
398 SymbolicEnum(
const IR::Type *type,
const IR::ID value)
399 : ScalarValue(ScalarValue::ValueState::Constant, type), value(value) {}
400 SymbolicEnum(
const SymbolicEnum &other) =
default;
401 void dbprint(std::ostream &out)
const override {
402 ScalarValue::dbprint(out);
403 if (isKnown()) out << value;
405 SymbolicValue *clone()
const override {
return new SymbolicEnum(state, type, value); }
410 DECLARE_TYPEINFO(SymbolicEnum, ScalarValue);
413class SymbolicStruct :
public SymbolicValue {
415 explicit SymbolicStruct(
const IR::Type_StructLike *type) : SymbolicValue(type) {
418 std::map<cstring, SymbolicValue *> fieldValue;
419 SymbolicStruct(
const IR::Type_StructLike *type,
bool uninitialized,
422 auto r = ::P4::get(fieldValue, field);
426 void set(
cstring field, SymbolicValue *value) {
428 fieldValue[field] = value;
430 void dbprint(std::ostream &out)
const override;
431 bool isScalar()
const override {
return false; }
432 SymbolicValue *clone()
const override;
433 void setAllUnknown()
override;
434 void assign(
const SymbolicValue *other)
override;
435 bool merge(
const SymbolicValue *other)
override;
436 bool equals(
const SymbolicValue *other)
const override;
437 bool hasUninitializedParts()
const override;
439 DECLARE_TYPEINFO(SymbolicStruct, SymbolicValue);
477class SymbolicArray final :
public SymbolicValue {
478 std::vector<SymbolicValue *> values;
479 friend class AnyElement;
480 explicit SymbolicArray(
const IR::Type_Array *type)
481 : SymbolicValue(type),
482 size(type->getSize()),
483 elemType(type->elementType->to<IR::Type_Header>()) {}
487 const IR::Type_Header *elemType;
488 SymbolicArray(
const IR::Type_Array *stack,
bool uninitialized,
490 SymbolicValue *get(
const IR::Node *node,
size_t index)
const {
491 if (index >= values.size())
493 return values.at(index);
495 void shift(
int amount);
498 values[index] = value;
500 void dbprint(std::ostream &out)
const override;
501 SymbolicValue *clone()
const override;
502 SymbolicValue *next(
const IR::Node *node);
503 SymbolicValue *last(
const IR::Node *node);
504 SymbolicValue *lastIndex(
const IR::Node *node);
505 bool isScalar()
const override {
return false; }
506 void setAllUnknown()
override;
507 void assign(
const SymbolicValue *other)
override;
508 bool merge(
const SymbolicValue *other)
override;
509 bool equals(
const SymbolicValue *other)
const override;
510 bool hasUninitializedParts()
const override;
512 DECLARE_TYPEINFO(SymbolicArray, SymbolicValue);
516class AnyElement final :
public SymbolicHeader {
520 explicit AnyElement(
SymbolicArray *parent) : SymbolicHeader(parent->elemType), parent(parent) {
525 auto result =
new AnyElement(parent);
528 void setAllUnknown()
override { parent->setAllUnknown(); }
529 void assign(
const SymbolicValue *)
override { parent->setAllUnknown(); }
530 void dbprint(std::ostream &out)
const override { out <<
"Any element of " << parent; }
531 void setValid(
bool)
override { parent->setAllUnknown(); }
535 bool hasUninitializedParts()
const override { BUG(
"Should not be called"); }
537 DECLARE_TYPEINFO(AnyElement, SymbolicHeader);
540class SymbolicTuple final :
public SymbolicValue {
541 std::vector<SymbolicValue *> values;
544 explicit SymbolicTuple(
const IR::Type_Tuple *type) : SymbolicValue(type) {}
545 SymbolicTuple(
const IR::Type_Tuple *type,
bool uninitialized,
547 SymbolicValue *get(
size_t index)
const {
return values.at(index); }
548 void dbprint(std::ostream &out)
const override {
550 for (
auto f : values) {
551 if (!first) out <<
", ";
556 SymbolicValue *clone()
const override;
557 bool isScalar()
const override {
return false; }
558 void setAllUnknown()
override;
559 void assign(
const SymbolicValue *)
override { BUG(
"%1%: tuples are read-only",
this); }
560 void add(SymbolicValue *value) { values.push_back(value); }
561 bool merge(
const SymbolicValue *other)
override;
562 bool equals(
const SymbolicValue *other)
const override;
563 bool hasUninitializedParts()
const override;
565 DECLARE_TYPEINFO(SymbolicTuple, SymbolicValue);
569class SymbolicExtern :
public SymbolicValue {
571 explicit SymbolicExtern(
const IR::Type_Extern *type) : SymbolicValue(type) { CHECK_NULL(type); }
572 void dbprint(std::ostream &out)
const override { out <<
"instance of " << type; }
573 SymbolicValue *clone()
const override {
574 return new SymbolicExtern(type->to<IR::Type_Extern>());
576 bool isScalar()
const override {
return false; }
577 void setAllUnknown()
override { BUG(
"%1%: extern is read-only",
this); }
578 void assign(
const SymbolicValue *)
override { BUG(
"%1%: extern is read-only",
this); }
579 bool merge(
const SymbolicValue *)
override {
return false; }
580 bool equals(
const SymbolicValue *other)
const override;
581 bool hasUninitializedParts()
const override {
return false; }
583 DECLARE_TYPEINFO(SymbolicExtern, SymbolicValue);
587class SymbolicPacketIn final :
public SymbolicExtern {
592 unsigned minimumStreamOffset;
598 explicit SymbolicPacketIn(
const IR::Type_Extern *type)
599 : SymbolicExtern(type), minimumStreamOffset(0), conservative(
false) {}
600 void dbprint(std::ostream &out)
const override {
601 out <<
"packet_in; offset =" << minimumStreamOffset
602 << (conservative ?
" (conservative)" :
"");
605 auto result =
new SymbolicPacketIn(type->to<IR::Type_Extern>());
606 result->minimumStreamOffset = minimumStreamOffset;
607 result->conservative = conservative;
610 void setConservative() { conservative =
true; }
611 bool isConservative()
const {
return conservative; }
612 void advance(
unsigned width) { minimumStreamOffset += width; }
616 DECLARE_TYPEINFO(SymbolicPacketIn, SymbolicExtern);
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:13