-
Notifications
You must be signed in to change notification settings - Fork 444
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[P4Testgen] Flatten the genEq function and support struct expressions. #4225
Conversation
8d96a28
to
6bef935
Compare
6bef935
to
d71aebe
Compare
d71aebe
to
a921d91
Compare
a921d91
to
d3de6af
Compare
@vlstill This PR is in preparation for full struct expression support in P4Testgen. Ultimately, this will allow us to pass struct expressions to functions, which will resolve the problem that we can not have both the reference and the value in extern calls. I have a series of PRs that will implement this. |
backends/p4tools/common/lib/gen_eq.h
Outdated
/// Important, this equation assumes that struct expressions have been ordered. | ||
/// This calculation does not match the names of the struct expressions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should there be some check that the order matches? This seems to me like a possible source of very hard to find bugs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a little difficult to implement because it might need a lot of special casing. Let me think about something sensible. In general, the assumption is that the front-end has taking care of ordering.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, the right way to do this is to simply check the type of the underlying struct expression and match it up with the components
. Unfortunately, that type is often a Type_Name
, very inconvenient...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, the right way to do this is to simply check the type of the underlying struct expression and match it up with the
components
. Unfortunately, that type is often aType_Name
, very inconvenient...
Is it not possible to resolve the Type_Name
using P4::TypeMap
at this point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have implemented this and it seems to pass all tests for now.
Is it not possible to resolve the Type_Name using P4::TypeMap at this point?
We do not have access to the TypeMap at this point, P4Testgen does its own type resolution because passes can break type-checking. Usually, any Type_Name is resolved before. The problem is Type_Names in nested struct expressions. We do not have to deal with this right now because we resolve most nesting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that #4215 is merged, which resolves Type_Name, this is a much safer assumption and will hold.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. Do you plan to add an additional check, or is this kept as a precondition only? I think this is actually complicated by the eager resolving of singletons which means the types don't need to match exactly. Therefore it is probably OK to just leave the "compatibility" of types as a precondition.
const IR::Expression *GenEq::checkSingleton(const IR::Expression *expr) { | ||
if (const auto *listExpr = expr->to<IR::BaseListExpression>()) { | ||
if (listExpr->size() == 1) { | ||
expr = checkSingleton(listExpr->components.at(0)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not return directly?
} else if (auto structExpr = left->to<IR::StructExpression>()) { | ||
leftElems = IR::flattenStructExpression(structExpr); | ||
} else { | ||
BUG("Unsupported list expression %1% of type %2%.", left, left->node_type_name()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BUG("Unsupported list expression %1% of type %2%.", left, left->node_type_name()); | |
BUG("Unsupported list/struct expression %1% of type %2%.", left, left->node_type_name()); |
or something like that
std::vector<const IR::Expression *> rightElems; | ||
if (auto listExpr = right->to<IR::BaseListExpression>()) { | ||
rightElems = IR::flattenListExpression(listExpr); | ||
} else if (auto structExpr = right->to<IR::StructExpression>()) { | ||
rightElems = IR::flattenStructExpression(structExpr); | ||
} else { | ||
BUG("Unsupported right list expression %1% of type %2%.", right, right->node_type_name()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please extract this piece of code to a function, it is there twice.
|
||
if (const auto *listKey = keyset->to<IR::ListExpression>()) { | ||
return equate(target, listKey); | ||
const IR::Expression *GenEq::checkSingleton(const IR::Expression *expr) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use different name, check*
suggests this will return bool
, but it returns an expression.
// If we still have lists after unrolling, compare them. | ||
if (left->is<IR::BaseListExpression>() || left->is<IR::StructExpression>()) { | ||
BUG_CHECK(right->is<IR::BaseListExpression>() || right->is<IR::StructExpression>(), | ||
"Right expression must be a list expression. Is %1% of type %2%.", right, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Right expression must be a list expression. Is %1% of type %2%.", right, | |
"Right expression must be a list or struct expression. Is %1% of type %2%.", right, |
be29f5a
to
3ffd79a
Compare
ir/irutils.cpp
Outdated
@@ -176,7 +175,10 @@ const IR::Expression *getDefaultValue(const IR::Type *type, const Util::SourceIn | |||
|
|||
std::vector<const Expression *> flattenStructExpression(const StructExpression *structExpr) { | |||
std::vector<const Expression *> exprList; | |||
for (const auto *listElem : structExpr->components) { | |||
const auto *structType = structExpr->type->checkedTo<IR::Type_StructLike>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a little problematic because the structType can be Type_Name
. I am not sure about a better way to handle this, however. At least we throw a bug in this case, which is easy to debug.
For P4Testgen, this is easy to fix once #4215 is approved and merged. We can just add a pass that converts every Type_Name
of a struct expression into a Type_Structlike
. We should do this anyway.
3ffd79a
to
69e2e2e
Compare
69e2e2e
to
2cfdf4b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can almost approve this now.
backends/p4tools/common/lib/gen_eq.h
Outdated
/// Generates an equality on a target expression and a keyset expression, recursing into lists. | ||
/// Generates an semantic equality on two input expressions, recursing into lists and structs. | ||
/// This supports fuzzy matching on singleton lists: singleton lists are considered the same as | ||
/// their singleton elements. This is implemented by eagerly recursing into singleton lists before | ||
/// attempting to generate the equality. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please mention a precondition that the types need to be compatible.
Also, I suggest you move the documentation to the function and better yet that you make equate
into a freestanding function and remove the class altogether (moving the helpers into .cpp).
backends/p4tools/common/lib/gen_eq.h
Outdated
/// Important, this equation assumes that struct expressions have been ordered. | ||
/// This calculation does not match the names of the struct expressions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. Do you plan to add an additional check, or is this kept as a precondition only? I think this is actually complicated by the eager resolving of singletons which means the types don't need to match exactly. Therefore it is probably OK to just leave the "compatibility" of types as a precondition.
ir/irutils.cpp
Outdated
// Ensure that the underlying type is a Type_StructLike. | ||
// TODO: How do fail gracefully if we get a Type_Name? | ||
const auto *structType = structExpr->type->to<IR::Type_StructLike>(); | ||
BUG_CHECK(structType != nullptr, "%1%: expected a struct type, received %2%", structExpr->type, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... struct like?
2cfdf4b
to
cf7f0f4
Compare
cf7f0f4
to
a73efad
Compare
Simplify
genEq
by performing all checks within a single function and resolving nested expressions recursively. Also ensure support of struct expressions. Note that this assumes that the elements within the struct expression are already ordered, i.e, they are enumerated the same way the underlying type is. The struct expression comparison is also on the basis of the contained expressions. We do not check whether the names are the same.