Skip to content
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

Implement header union type and header union type isValid built-in method #96

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

tagolog
Copy link
Collaborator

@tagolog tagolog commented Mar 5, 2025

Signed-off-by: Vladimir Shiryaev w@tagolog.com

…thod.

Signed-off-by: Vladimir Shiryaev <w@tagolog.com>
!p4hir.header_union<"name", field1: HeaderType1, field2: HeaderType2>
}];

// We skip default builders entirely to consistently add validity bit field on fly
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need this? One can construct union from headers only that already contain validity bits.

@@ -264,6 +300,12 @@ HeaderType HeaderType::get(mlir::MLIRContext *context, llvm::StringRef name,
return Base::get(context, name, realFields);
}

HeaderUnionType HeaderUnionType::get(mlir::MLIRContext *context, llvm::StringRef name,
llvm::ArrayRef<FieldInfo> fields) {
llvm::SmallVector<FieldInfo, 4> realFields(fields);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks strange. Why copy fields?


action header_union_isValid_test() {
U u;
if (u.isValid())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You also need tests for # literal as well as setValid / setInvalid, etc. calls

// CHECK: %[[VAL_4:.*]] = p4hir.read %[[VAL_3]] : <!validity_bit>
// CHECK: %[[VAL_5:.*]] = p4hir.const #[[$ATTR_2]]
// CHECK: %[[VAL_6:.*]] = p4hir.cmp(eq, %[[VAL_4]], %[[VAL_5]]) : !validity_bit, !p4hir.bool
// CHECK: %[[VAL_7:.*]] = p4hir.ternary(%[[VAL_1]], true {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generated code looks a bit weird, as we're evaluating all nested isValid's even if we already deduced that the the result is true. I think we'd need to shortcut and emit something like this:
(H.h1.isValid() ? true : (H.h2.isValid() ? true : (H.h3.isValid() ? : ...))). So, it will be a sequence of nested ternary operators where you're yielding true in true region and recurse in false region.

@@ -329,6 +330,10 @@ class P4HIRConverter : public P4::Inspector, public P4::ResolutionContext {
// Should be resolved eslewhere
return false;
}
bool preorder(const P4::IR::InvalidHeaderUnion *hu) override {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need test for this (# literal).

@@ -1276,7 +1360,13 @@ void P4HIRConverter::postorder(const P4::IR::Member *m) {
// TODO: Likely we can do similar things for the majority of struct-like
// types
auto parentType = getOrCreateType(m->expr);
if (mlir::isa<P4HIR::StructType, P4HIR::HeaderType>(parentType)) {
if (mlir::isa<P4HIR::StructType, P4HIR::HeaderUnionType>(parentType)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why duplicate the code? Just add another case to isa

@@ -1139,21 +1224,20 @@ bool P4HIRConverter::preorder(const P4::IR::MethodCallExpression *mce) {
// TODO: Are there cases when we do not have l-value here?
auto ref = resolveReference(bCall->appliedTo);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ref is unused?


mlir::Value P4HIRConverter::emitHeaderUnionBuiltInMethod(
const P4::IR::Type_HeaderUnion *p4cHeaderUnionType, const P4::BuiltInMethod *builtInMethod,
mlir::OpBuilder &builder, mlir::Location loc) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to pass builder here (and above).


for (auto huField : huFields) {
auto headerRef = builder.create<P4HIR::StructExtractRefOp>(loc, headerUnion, huField.name);
auto validityBitRef = builder.create<P4HIR::StructExtractRefOp>(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you can refactor the code a bit, so you could reuse some pieces of emitHeaderBuiltInMethod?

E.g.:

  • Instead of passing builtInMethod, pass only method name
  • Instead of emitting a reference to a header (via resolveReference), inside do it outside, and pass the mlir::Value as argument.

This way you'd essentially need to call such refactored emitHeaderBuiltInMethod with headerRef argument and then combine the resulting values properly.

auto validityBit = builder.create<P4HIR::ReadOp>(loc, validityBitRef);
auto isHeaderValid = builder.create<P4HIR::CmpOp>(loc, P4HIR::CmpOpKind::Eq, validityBit,
getValidHeaderConstant(loc));
auto ternaryOpResult = builder.create<P4HIR::TernaryOp>(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above about expected code sequence.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants